We currently are able to take payments and authenticate users, but we are lacking an email layer to tie it all together.
Nodemailer
For my project, I used nodemailer to send emails. The great thing about nodemailer is that it is A. easy to test and B. makes it easy to setup email providers. I used Fastmail as my email provider, which nodemailer provides a simple config option for. After you've installed the package, sending an email in nodemailer
is as easy as:
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass, // generated ethereal password
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred Foo 👻" <foo@example.com>', // sender address
to: "bar@example.com, baz@example.com", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // html body
});
Our purposes won't be much more complicated than this. We'll just be sending two kinds of emails - one for login, and one for signup.
Signup Email
Do you remember back in the billing tutorial when we created our checkout route? Once a user is created, and their API key initialized, we will want to send them a welcome email. For FavoritesAPI, this is as simple as an email saying "Welcome - here are our docs" and a link. Can't get much simpler than that.
static async sendSignupEmail(email) {
// TODO: add in your own email info
const msg = {
to: email,
from: 'support@myapi.com',
subject: 'Welcome to MyAPI!',
html: `check out our documentation <a href="${config.get('BASE_URL')}/documentation">here</a>`,
};
try {
console.info(`Sending signup email to ${email}`);
await this.transport.sendMail(msg);
} catch(err) {
console.info(`Signup email error ${err.message}`);
throw err;
}
}
Login Email
The login email is a bit more complicated, because it will need to contain the login token that we created earlier. So you'll want to create a new login token using your LoginToken
model, and then pass the string token
into an email. The email itself would just need to link to your login route at https://mysite.com/login?token=MY_TOKEN
. Once they go there, a cookie is set that keeps them logged in.
static async sendLoginEmail(email, loginToken) {
const loginLink = `${config.get('BASE_URL')}/login?token=${loginToken}`;
// TODO: add in your own email info
const msg = {
to: email,
from: 'support@myapi.com',
subject: 'Login Request',
html: `Log in by clicking the following <a href="${loginLink}">link</a>`,
};
try {
console.info(`Sending login email to ${email}`);
await this.transport.sendMail(msg);
} catch(err) {
console.info(`Login email error ${err.message}`);
throw err;
}
}
Email Provider Setup
There are a bunch of different email providers you can opt for, but I usually go with Fastmail for their privacy-focus and ease of setup. To use an email service like them, you'll need to verify your domain by adding an MX record to your DNS config. Once that's done, you'll also need to configure a sending identity (for instance, support@favoritesapi.com). FastMail also makes it easy to create an app password, which you can safely use with nodemailer
in place of the testAccount
credentials.
Marketing
Which marketing service to use is a bit of an open question, since you now have all of your user's emails stored nicely in the users
table. Mailchimp and Sendgrid are two common options, and allow you to track conversion rate and other nice features. If you are fine with a cheap/less data-intensive approach, you could even opt to create one-off email jobs using nodemailer
. This is not an area I have much experience in, so I'll opt to stay quiet on this one.
Thanks for reading! Next time, I'll be giving a quick rundown of how I deploy FavoritesAPI.