Create Beautiful Transactional Emails with the Feathers-Mailer Module
Rachel
Posted on October 28, 2020
FeathersJS is a robust web application framework for real-time applications and REST APIs. It's great for serving as a Minimum Viable Product (MVP) backend and scales when you are ready to move beyond MVP stage and grow your customer base.
Feathers provides a command-line tool to quickly scaffold a project and a handful of generators to build out services to meet your project needs.
One of the first features I developed with Feathers is transactional emails.
This article covers creating beautiful templated emails - even if you don't have design skills. By leveraging a combination of several tools, it's quite easy to develop professional emails for your platform.
The codebase for this tutorial will be building off a previous post I wrote - Intro: Fullstack JS User Roles & Management. At the end of this series, the email functionality already exists as part of account management and registration, but the emails are boring text emails like Click link here.
In this article, I'll use a combination of the following to transform the text emails into beautiful branded emails:
The Template
Beginning with the User Roles & Management Repo, I created a new repo using it as the template. You're welcome to follow along if you'd like by creating a copy of the above repo. The final repo is located here.
This repo already includes functionality for user login, password reset, and account registration, all of which send out an email when the action is triggered. I won't go into too much detail in this article, but if you'd like to learn more, read my previous article that covers it in greater detail.
Project Features
This project leverages feathers-authentication-management to provide account management functionality. An email service is also created to send out emails.
Email Service
The email service is quite simple. I set it up following the instructions found in the docs.
feathers generate service
with the name 'email'.
This scaffolds out a service named email. I then defined the mailer configuration in the service file.
module.exports = function (app) {
// Initialize our service with any options it requires
app.use(
'/email',
Mailer(
smtpTransport({
host: app.get('smtp_host'),
secure: true,
auth: {
user: app.get('smtp_user'),
pass: app.get('smtp_pw'),
},
})
)
);
};
The app.get('variable')
function pulls the value from a configuration file. Details about this can be found in the FeathersJS configuration docs.
The email service uses the feathers-mailer module, which is a wrapper for the nodemailer library so it supports the same transport options. For this project, I used the AWS SES transport, but you can also configure your service with different supported transport options or SMTP options.
To configure for AWS, the following configuration keys will be needed from your AWS account:
{
"smtp_user": "aws_smtp_user",
"smtp_pw": "aws_smtp_pw",
"smtp_host": "aws_smtp_host"
}
You can add these to the ${env}.json
configuration file or default.json
configuration file.
Sending Emails
Feathers-authentication-management allows you to define which emails are sent based on the action requested. There's a total of 6 actions: resendVerifySignup, verifySignup, sendResetPwd, resetPwd, passwordChange, and identityChange.
These are all defined in the notifier function, which is passed to the authManagement service. Here's an excerpt of the notifier function for the Send Password Reset action:
module.exports = function (app) {
// generates the token link
function getLink(type, hash) {
const url = app.get('client_url') + '/' + type + '?token=' + hash;
return url;
}
// sends the email using an email service
function sendEmail(email) {
return app
.service('email')
.create(email)
.then(function (result) {
console.log('Sent email', result);
})
.catch((err) => {
console.log('Error sending email', err);
});
}
const FROM_EMAIL = app.get('from_email');
return {
notifier: function (type, user) {
let tokenLink;
let email;
switch (type) {
// user clicks link from email to verify their email
case 'sendResetPwd':
tokenLink = getLink('reset-password', user.resetToken);
email = {
from: FROM_EMAIL,
to: user.email,
subject: 'Reset Password',
html: `<html><b>Reset Password</b>: ${tokenLink}</html>`,
};
return sendEmail(email);
}
},
};
};
The notifier function is where we'll want to send the branded emails we'll soon be creating.
Transforming Emails
Up to this point, the code simply sends a simple HTML string with some content. We want it to do more. We want it to send a beautiful HTML email that is personalized for the user. To generate this HTML, we'll use a templating language so we can insert variables and allow customization on a per user basis.
I used Pug, but you're welcome to use a different templating language if you prefer. The template will compile to HTML, which you can then send as the email where we currently provide a text HTML string.
Within the server directory, install Pug:
npm i pug --save
Pug is a bit more concise than HTML, eliminating the need for code blocks. It relies on declaring the element type before providing the content.
Take a look:
p Welcome #{name}! You're now registered for #{event}.
When the template is compiled, you'll get something like this:
<p>Welcome Sarah! You're now registered for Fullstack Javascript.</p>
You can also use code blocks to generate HTML tags.
-
var list = ["Apples", "Bananas", "Oranges",
"Kiwis", "Jackfruit", "Kumquats"]
each item in list
li= item
Which results in:
<li>Apples</li>
<li>Bananas</li>
<li>Oranges</li>
<li>Kiwis</li>
<li>Jack</li>
<li>Kumquats</li>
Take a look at the docs to see it's full features.
Email Templates
While not required, I used email templates found on Really Good Emails to reduce the design time. I can easily tweak a design I like and match the colors/brands I want to use. They sort email templates into categories so you can easily search emails matching a template you want to use, from giveaways to account setup.
Once you find an email you like, you can also modify it live on their site before exporting to use elsewhere.
For this project, I'll use a simple Password Reset Template.
HTML to Pug
Once I'm done creating a template according to my brand, I can use another tool to compile the HTML to Pug, called HTML-to-Pug. Copy/paste HTML on one side, get Pug outputted on the other side. Quick and easy! It's not perfect, but it does most of the heavy lifting for generating the Pug code needed:
I save the Pug code into a new template file directly nested under the auth-management folder. You'll find the pug code under /server/src/services/auth-management/templates/password-reset.pug
.
Now I can add some customization once I have the Pug template code.
For this project, I'm keeping it simple. I want to change the headline to include the user's name, and I'll add in the reset link. So if I reset my own account password, I'll see Reset your password Rachel
.
I updated the pug template to include the firstname variable and the url link for the button:
Reset your password #{firstname}
...
...
a.Button-primary(href=url ...)
The variables are then provided to the HTML compile function, so the new notifier code looks like this:
case 'sendResetPwd': {
tokenLink = getLink('reset-password', user.resetToken);
// create the function to compile the pug template to HTML
const pwReset = pug.compileFile(
path.join(__dirname, 'templates', 'password-reset.pug')
);
email = {
from: FROM_EMAIL,
to: user.email,
subject: 'Reset Password',
// use the function and add in the variables required by the template. This will output customized HTML.
html: pwReset({
firstname: user.firstname,
url: tokenLink
}),
};
return sendEmail(email);
}
Now, when I send a request for a password reset, I receive the following email:
I can then repeat this process for other transactional emails, or even create an automated email campaign.
Now it's your turn. What will you create?
Resource List
Did I Miss Something?
Leave a comment and let me know how this works for you. If something isn't clear, ask.
Posted on October 28, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.