Reputation:
I'm building a command line app that will query a DynamoDB table, collect email addresses for each item on the table that has not already had an email sent to it, map over that array of items to create a customized message object for each one, pass that array into SendGrid's sgMail.send()
method to send an email for each message inside, and then create a Communication object for each one on a second DynamoDB table. I followed the steps outlined in option three of this Twilio blog, and the code is working.
However, this method does not seem to allow error handling on a message by message basis when you pass in an array to .send()
. Right now I first run sgMail.send(messages)
in a try/catch block, and then create all of my Communication objects separately for each item only if the .send()
call is completely successful. I'd prefer to be able to create an individual Communication object each time an email is successfully sent, rather than hoping that the try/catch block hits no errors and then wholesale creating the Communication objects after the fact.
My first thought was to iterate through the array returned from the DynamoDB query, and for each one first send an email, then once successful, create a Communication object. That method didn't work (the Communication was being created but the email was never sent, even though I was using await
on all async calls). Once that didn't work, I found the blog linked above and used that method.
My worry is that if a random batch of the messages in the array fails and triggers the exception, but another chunk of emails was successfully sent before the error was caught, then I'll have a portion of emails sent out without corresponding Communication objects for them since the creation of those objects happens entirely independently from the email being sent.
I've combed through SendGrid's documentation as well as numerous Google searches, but haven't been able to find a helpful answer. Here's the current working code:
// First wait to send emails
console.log("Sending emails...")
try {
const messages = items.map((item) => {
return {
to: item.details.email,
from: SendGrid domain here,
subject: Email subject here,
html: Email content here
})
// Send email to each address passed in.
await sgMail.send(messages).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
} catch (error) {
throw error
}
// Then create communications
console.log("Creating communication objects...")
try {
for (let i = 0; i < items.length; i++) {
const params = {
TableName: process.env.COMMUNICATION_TABLE,
Item: {
communication_id: uuidv1(),
item_id: items[i].item_id,
date: new Date().toLocaleDateString()
}
};
try {
await docClient.put(params).promise();
} catch (error) {
throw error
}
}
} catch (error) {
throw error
}
// On success
console.log("Process complete!")
Upvotes: 0
Views: 916
Reputation: 73027
Twilio SendGrid developer evangelist here.
When you send an array of mail objects to sgMail.send
, the @sendgrid/mail
package actually loops through the array and makes an API call for each message. You are right though, that one may fail to send and you will be left in the state where some emails have sent and others failed or were cancelled.
So, you can loop through the array yourself and handle the successes/failures yourself too.
Try something like this:
console.log("Sending emails...");
items.forEach(async (item) => {
const mail = {
to: item.details.email,
from: "SendGrid domain here",
subject: "Email subject here",
html: "Email content here",
};
try {
await sgMail.send(mail);
console.log(`Sent mail for ${item.item_id} successfully, now saving Communication object`);
const params = {
TableName: process.env.COMMUNICATION_TABLE,
Item: {
communication_id: uuidv1(),
item_id: item.item_id,
date: new Date().toLocaleDateString(),
},
};
try {
await docClient.put(params).promise();
console.log(`Communications object saved successfully for ${item.item_id}.`);
} catch (error) {
console.log(
"There was a problem saving the Communications object: ",
error
);
}
} catch (error) {
console.error("Email could not be sent: ", error);
}
});
// On success
console.log("Process complete!");
Upvotes: 1