DEV Community

Cover image for Create Beautiful Transactional Emails with the Feathers-Mailer Module
Rachel
Rachel

Posted on

Create Beautiful Transactional Emails with the Feathers-Mailer Module

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'),
        },
      })
    )
  );
};
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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);
      }
    },
  };
};
Enter fullscreen mode Exit fullscreen mode

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}.
Enter fullscreen mode Exit fullscreen mode

When the template is compiled, you'll get something like this:

<p>Welcome Sarah! You're now registered for Fullstack Javascript.</p>
Enter fullscreen mode Exit fullscreen mode

You can also use code blocks to generate HTML tags.

-
  var list = ["Apples", "Bananas", "Oranges",
          "Kiwis", "Jackfruit", "Kumquats"]
each item in list
  li= item
Enter fullscreen mode Exit fullscreen mode

Which results in:

<li>Apples</li>
<li>Bananas</li>
<li>Oranges</li>
<li>Kiwis</li>
<li>Jack</li>
<li>Kumquats</li>
Enter fullscreen mode Exit fullscreen mode

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.

Screenshot of Really Good Emails

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:

Image of HTML to Pug

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  ...)
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

Now, when I send a request for a password reset, I receive the following email:

Screenshot of Customized Password Reset 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.

Top comments (0)