How do I template SendGrid's content with Nodejs?
I am trying to send emails from contact form in an application using SendGrid. I have a Google Cloud Function that I am calling via an HTTP post. I am able to pass in the form data as a JSON object to my Google Cloud Function, and display a raw JSON object in my email content, but when I try to template my SendGrid content, the JSON object's properties keep coming back as undefined. How do I display my different formData properties within my SendGrid email content?
Here is the code:
const functions = require('firebase-functions');
const sg = require('sendgrid')(
process.env.SENDGRID_API_KEY || '<my-api-key-placed-here>'
);
exports.contactMail = functions.https.onRequest((req, res) => {
contactMail(req.body);
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.send("Mail Successfully Sent!");
})
function contactMail(formData) {
const mailRequest = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: {
personalizations: [{
to: [{ email: 'my.email#gmail.com' }],
subject: 'Contact Us Form Submitted'
}],
from: { email: 'noreply#email-app.firebaseapp.com' },
content: [{
type: 'text/plain',
value: `
You have received a contact us form submission. Here is the data:
Name: ${formData.userFirstName} ${formData.userLastName}
Email: ${formData.userEmail}
Subject: ${formData.formSubject}
Message: ${formData.formMessage}
`
}]
}
});
sg.API(mailRequest, function (error, response) {
if (error) {
console.log('Mail not sent; see error message below.');
} else {
console.log('Mail sent successfully!');
}
console.log(response);
});
}
This displays undefined for each template expression.
However if my content section is set to this:
content: [{
type: 'text/plain',
value: formData
}]
Then the email content is displayed as a raw JSON object.
How do I clean up my SendGrid email content and display my JSON data in a formatted, cleaner way?
The problem was my req.body was a text string, not a JSON object.
Using const formData = JSON.parse(req.body); and then passing this variable to contactMail will properly display the JSON object's properties in an ES6 template literal.
Related
I hope you all have a great day. I am coding my own personal website and I have a section called to contact me. The problem I have with this section is that I am trying to send my client email to my email and when I am trying to send their message to my server through Graphql I get this error
[
{
"message": "Syntax Error: Unterminated string.",
"locations": [
{
"line": 3,
"column": 123
}
]
}
]
the request I sent to my server is
'\n mutation{\n sendEmail(EmailInput: {name: "Test name", email: "Test#email.com",
subject: "this is test subject", message: "\n
this is the first line \nthis is the second line\nwhen I have multiple lines I have these problem\n
"}) {\n success\n message\n }\n }\n '
I don't know how to fix it I don't know why I get this error.
I used fetch to send my code backend :
const emailMutationQuery = `
mutation{
sendEmail(EmailInput: {name: "${senderName.value}", email: "${senderEmail.value}", subject: "${senderSubject.value}", message: "
${senderMessage.value}
"}) {
success
message
}
}
`;
const result = await fetch("http://localhost:2882/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: emailMutationQuery,
}),
});
const convertedResult = await result.json();
GraphQL supports variables, which can be used to supply input data separately from the query. The variables are just a separate JSON-encoded object. This avoids syntactic difficulties (and potential security risks!) from trying to embed the inputs directly in the query.
For this you'd write a fixed query, that declares and uses the variable, but doesn't depend on the per-request inputs
const emailMutationQuery = `
mutation SendEmail($emailInput: SendEmailInput!) {
sendEmail(EmailInput: $emailInput) {
success
message
}
}
`;
You'd then create a second object containing the variable(s). The top-level keys match what you declare in the GraphQL operation line, and their content matches the corresponding GraphQL input types.
const variables = {
emailInput: {
name: senderName.value,
email: senderEmail.value,
subject: senderSubject.value,
message: senderMessage.value
}
};
Note that this is an ordinary Javascript object, and we haven't quoted or escaped anything here.
Now when we make the request, we send the query and variables together
const result = await fetch("http://localhost:2882/graphql", {
...,
body: JSON.stringify({
query: emailMutationQuery,
variables: variables
})
});
Things like newlines in the message content will be escaped in the variables block, and get passed through correctly to the underlying GraphQL engine.
I actually find a solution for it but feel free to share your answers here. The solution I found for this problem was that you have to use JSON.stringify() for the textarea. you have to pass your textarea value to this function and js will take care of the rest. my code now looks like this
const emailMutationQuery = `
mutation{
sendEmail(EmailInput: {name: "${senderName.value}", email: "${senderEmail.value}", subject: "${senderSubject.value}",
message:${JSON.stringify(senderMessage.value)}}) {
success
message
}
}
`;
I hope this help you guys.
I've been playing around with this for a while, and I have to say I'm rather stumped.
I have a table called "physical_sites", and created the column "history" as a "json" type in this table.
My API request function is as follows:
const response = await fetch(BASE_URL + "physical_sites", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ data: jobSite }),
});
With my incoming data as:
{
"physical_site_name": "Here",
"physical_site_loc": "test",
"created_by": "ME",
"status": "Active",
"history": [{
"action_date": "2022-07-21T01:22:44.056Z",
"action_taken": "Create Job Site",
"action_by": "me",
"action_by_id": 24,
"action_comment": "Initial Upload",
"action_key": "1jt9JPRLy7RHJUwmz3kqoy98u"
}]
}
I will continually be adding items to the 'array' in history, so there will be multiple objects here. I checked this in an online JSON validator, and it seems correct.
Lastly, my "create" function in the controller is as follows:
async function create(req, res) {
const result = req.body.data;
console.log(result);
const data = await knex("physical_sites")
.insert(result)
.returning("*")
.then((results) => results[0]); //insert body data into assets
res.status(201).json({ data });
}
Fairly simple.
However, I keep getting this error:
message: 'insert into "physical_sites" ("created_by", "history", "physical_site_loc", "physical_site_name", "status") values ($1, $2, $3, $4, $5) returning
* - invalid input syntax for type json'
Not exactly sure what is going on, can someone help me understand what I'm missing?
Thanks.
Most likely one of you column for this table has a JSON type. I believe that it is the history column.
You could parse the history property to String before sending the request.
// ...
body: JSON.stringify({
data: {
...jobSite,
history: JSON.parse(jobSite.history)
}
}),
// ...
I wrote a code and i got the data in a json format. Now i want it to convert that data into a discord embed so that when i enter a command . EX:- .data the json data to be sent from the URL.
Here is the input
request({
url: "https://data.vatsim.net/v3/vatsim-data.json",
json: true
}, (err, response, body) => {
console.log(body)
})
The json data looks like this :
{
cid: 1435807,
name: ' ',
callsign: 'ZAP85LJ',
flight_plan: [Object],
last_updated: '2021-10-24T10:45:52.516736Z'
},
{
cid: 1439854,
name: ' ',
callsign: 'DLH1ML',
flight_plan: [Object],
last_updated: '2021-10-24T10:46:13.4226778Z'
}
You can use EmbedFields, you can use up to 25 fields on an embed. On this example I used .forEach so that for each element on the array I can create a field with its value:
request({
url: "https://data.vatsim.net/v3/vatsim-data.json",
json: true
}, (err, response, body) => {
const embed = new Discord.MessageEmbed()
const pilots = body.pilots.slice(0, 15)
body.pilots.forEach(pilot => {
embed.addField(p.name,
`CID : ${p.cid}
Server : ${p.server}
etc...`)
})
message.channel.send(embed)
}
If you really want to show every single one of your elements on the array you can use discord-buttons to make the embed edit its message and change pages but for now this is the simplest and easiest solution for you.
Axios sends an array of strings instead of an array of objects. I have an array of objects that contains data about the event. I'm trying to send a request to the server via axios, but I get a array of strings insteenter image description heread of objects at the output
let data = {
title: 'Game',
subject: 'Some subject',
date: ['01/01/2021','01/01/2021'],
years: ['1970', '1970'],
address: 'None',
ages: [
{
title: 'Men',
weights: [{page: 0, title: '60'}]
}
]
};
api.Create({
params: data
}).then(function (response) {
console.log(response.data);
})
.catch(function (err) {
console.log(err);
});
api response
try to:
console.log(JSON.parse(response.data))
What you get back from the server is string. you need to parse it.
When you send data to and from a server, it is sent as a 'serialized' string, usually JSON format
That's how server responses work
It turned out to be an incorrect request. I used GET to pass the object, instead of POST, so it converts it to a string. I want to notice that there is an evil community on this site.
I'm trying to send emails through the Mandrill API with Mailchimp templates. I am doing this in the cloud code with Parse.com, see here https://www.parse.com/docs/cloud_modules_guide#mandrill. The emails are sent just fine, however, the mc:edit fields are never updated. This is the only content in the template now:
<span mc:edit="ship_id">ship_id</span>
This is what my call in Javascript looks like, hope somebody sees my mistake. I'm running this in Parse.com cloud code if that makes any difference. Thanks a lot!
var Mandrill = require('mandrill');
Mandrill.initialize('api-key');
Mandrill.sendTemplate({
template_name: "Drip campaign",
template_content: [{
name: "ship_id",
content:"Test Test"
}],
message: {
text: "Hi",
subject: "You have new mail",
from_email: "info#example.com",
from_name: "Thomas",
to: [
{
email: "answer#example.com",
name: "Fred"
}
],
"headers": {
"Reply-To": "answer#example.com"
},
"important": false,
"track_opens": true,
"track_clicks": true,
},
async: true
},{
success: function(httpResponse) {
response.success("Email sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
}
Ok, so there is nothing wrong with my code, but it seems like the templates are not sent properly from Mailchimp to Mandrill as adding fields such as |NAME| for merge tages or mc:edit="name" just were not populated. At least the code of the Mailchimp template is pretty weird and very nested.
For that reason, I would recommend using your own HTML here, where you enter the merge tages or mc:edits https://mandrillapp.com/templates/.
As far as I understand from your question that you want to send e-mail at the same time you want to dynamically edit the mail content. As you have already used, you can do it via the Mandrill API. I suggest you to use the js files which are downloadable in the link;
https://github.com/jlainog/parse-mandrill-sendTemplate
From the js file in the github account, you can dynamically edit the mail content(must be in your template) via using the tag mc:edit.
For my case working copy of code is below;
Parse.Cloud.define("sendMail", function(request, response) {
var Mandrill = require('cloud/mandrillSend.js');
var sentTo = //Mail address to sent
var subject = //Mail Subject
var fromEmail = //From email
var fromName = //From Name
var sentToName = //Parameters from request
var fullName = //Full Name
Mandrill.initialize('YOUR MANDRILL API KEY');
Mandrill.sendTemplate({
template_name: "MANDRIL TEMPLATE",
template_content: [
{
name: "nameHeader",
content: sentToName,
},
{
name: "mail",
content: sentTo,
},
],
"key": "YOUR MANDRILL API KEY",
message: {
subject: subject,
from_email: fromEmail,
from_name: fromName,
to: [{
email: sentTo,
name: fullName
}],
important: true
},
async: false
}, {
success: function (httpResponse) {
console.log(httpResponse);
response.success("Email sent!");
},
error: function (httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
});
For example, in Mandrdil Template there is a span with the id;
<span mc:edit="mail"> test#gmail.com</span>
Hope this helps.
Regards.