In this article you will learn how to use Nodemailer to send your AWS SES emails.
I recommend this approach because the Nodemailer API
- gives you a platform-agnostic interface to build on top of, reducing vendor lock-in
- is less verbose than the AWS SDK API
- supports more advanced features such as attachments, out of the box
Compare this AWS SDK snippet:
import AWS from "aws-sdk";
async function sendSignInLink({
to,
signInLink,
expiresInDays,
}: {
to: string;
signInLink: string;
expiresInDays: number;
}) {
const params = {
Source: `Authentication <noreply@example.com>`,
Destination: {
ToAddresses: [to],
},
Message: {
Subject: {
Charset: "UTF-8",
Data: "Your Sign-In Link",
},
Body: {
Text: {
Charset: "UTF-8",
Data: `Hi there,
This is your sign-in link: ${signInLink}
This link will expire in ${expiresInDays} days.
For security reasons, you shouldn't reply to this email.`,
},
},
},
};
await new AWS.SES().sendEmail(params).promise();
}
With its Nodemailer equivalent:
import AWS from "aws-sdk";
import nodemailer from "nodemailer";
async function sendSignInLink({
to,
signInLink,
expiresInDays,
}: {
to: string;
signInLink: string;
expiresInDays: number;
}) {
const mailer = nodemailer.createTransport({
SES: new AWS.SES(),
});
await mailer.sendMail({
from: `Authentication <noreply@example.com>`,
to: to,
subject: "Your Sign-In Link",
text: `Hi there,
This is your sign-in link: ${signInLink}
This link will expire in ${expiresInDays} days.
For security reasons, you shouldn't reply to this email.`,
});
}
Installation
npm install aws-sdk nodemailer
If you're using TypeScript:
npm install --save-dev @types/nodemailer
At some point you may need to specify your AWS Region:
AWS.config.update({ region: process.env.AWS_REGION_ID });
Creating the Nodemailer instance
const mailer = nodemailer.createTransport({
SES: new AWS.SES(),
});
Attachments example
This is one of the main reasons I like using Nodemailer, it provides a clean facade for trickier use cases such as attachments.
const args = {
// ...
};
const mailer = nodemailer.createTransport({
SES: new AWS.SES(),
});
await mailer.sendMail({
from: `${args.fromName} <${args.fromEmail}>`,
to: args.toEmail,
cc: args.ccEmails,
subject: args.subject,
text: args.text,
html: `<div>${args.text}</div>`,
attachments: [
{
filename: args.fileName,
content: fs.createReadStream(args.filePath),
},
],
});
Switching transport based on environment
let mailer;
if (process.env.NODE_ENV === "production") {
mailer = nodemailer.createTransport({
SES: new AWS.SES(),
});
} else {
mailer = nodemailer.createTransport({
port: 1025,
});
}