Sending emails with Node.js

On January 10, 2024
9min read
Diana Lepilkina Content Specialist @Mailtrap

Sending emails using Node.js is easy. We have gone over it in our previous blog post on sending emails with Nodemailer. Last time we reviewed Nodemailer’s capabilities we focused on sending HTML emails via Simple Mail Transfer Protocol. 

In this post, we will examine how to send emails with your Node.js backend using a popular email service like Gmail. Also, we will have a look at other transport options and packages to build and send emails from Node.js.

What options are available for sending emails in Node.js?

Being a server-side tool, Node.js allows sending emails in a few ways, the most common two are using SMTP and an API. Let’s have a quick look at the two, and how they work and differ from each other.  

Option 1: Send emails using Node.js and SMTP

One of the most common methods of sending emails is via an SMTP server. Essentially the process looks like this: 

  1. Using an email client (Gmail, AOL, Outlook, etc.) you send a text file (email) by uploading it to your outgoing SMTP server. 
  1. After a  series of authentication stages, the text file gets picked up by the receiving SMPT server and is placed in the recipient’s inbox. 

Since this is one of the most widespread methods of sending and receiving emails, setting up and integrating it into your web app is relatively easy. 

But being the most commonly used has its disadvantages. The primary one is that SMTPs are highly vulnerable to a variety of cyber threats from data breaches to DDoS attacks. 

So for anyone using this method, server maintenance, particularly its security, is a top priority.

Option 2: Send emails in Node.js and email API

The second option of sending emails doesn’t require you to handle any servers. Instead, a simple hosted API from a third-party service is used to manage all of the email transactions.

Most transactional email APIs on the market have quick app integration and high-volume email sending capabilities among many other functions.  

Most email API services provide insights and have various analytical reports that can help improve your email deliverability.

However, unlike the SMPT, the API method minimizes your control over email infrastructure and is handled by a third-party service. 

How to send emails in Node.js with Nodemailer?

The only thing required to start using Nodemailer module is having Node.js version 6.0 or above. After that comes the Nodemailer installation with the npm  or Yarn package manager.

Here is a basic outline of the actions required to start sending emails with the zero dependency Node.js module Nodemailer:

  1. Install Nodemailer via the following command:

    npm install nodemailer --save or  yarn add nodemailer
  2. Once completed, include it into your web application
  3. Create Nodemailer transporter 
  4. Set Nodemailer message options
  5. Deliver a message with sendMail()

For detailed instructions with code refer to this guide. Additionally, Nodemailer’s package.json file, other main .js files, folders, and code can be found on their Github page.

How to send emails in Node.js with Mailtrap Email Sending?

Before we dive into reviewing the rest of the Node.js email packages, it’s worth mentioning a new package that was just released – Mailtrap’s very own sending package.

Mailtrap Email Sending is a powerful solution for integrating email functionality into your application. By utilizing our API and SMTP services, you can easily connect your app to our robust email infrastructure, which is designed to provide fast and reliable service. Using Email Sending, developers gain full control over their delivery and infrastructure of their emails.

The actionable analytics and deliverability alerts allow users to keep an eye on the performance of their emails and quickly identify any unexpected issues that may arise. The analytics dashboard offers a bird’s eye view of the metrics, including detailed reports and 60-day email logs giving developers the ability to track their emails’ journey.

Here is how you can quckly add email sending functionality to your Node.js application with Mailtrap:

yarn:

yarn add mailtrap

npm:

npm install mailtrap

To further proceed with adding sending functionality to your Node.js application refer here for the source code. 

If you want to find any issues that can lead to bugs or other inconsistencies use yarn lint with ESLint.

Can you send emails with Node.js only using Nodemailer?

In some guides and tutorials, you might find a note that there are a variety of Node.js email packages and there are. But in reality, Nodemailer is the most robust out there and you can barely find a decent alternative.

On Github, you can find several packages for Node.js related to emails but they won’t offer you a wide functionality.

With Nodemailer, you can create both plain-text and HTML emails with attachments and send them via SMTP, SES (wrapper for sending emails via AWS SES), or sendmail.

  1. The most similar package is Emaijs. Its features include:
  • Sending emails via SMTP servers (SSL and TLS) with authentication
  • HTML support and MIME attachments. Those that can also be added as:
    • Strings
    • Streams
    • File paths
  • Asynchronous sending of queued emails 
  • UTF-8 encoding in headers and body.

So, the main difference is that in Emailjs you will use MIME type to work with attachments, while in Nodemailer you use strings.

  1. Another quite popular package is email-templates. As you can see from the name, this package is designed for creating various custom templates for Node.js. It features support for:
  • Automatic inline CSS 
  • Stylesheets
  • Embedded images
  • Fonts

Also, it has a preview option where you can check how the receiver will see the email. The email templates package was made by the creator of the Lad framework. So it’s recommended to use it with Lad.

  1. One more package worth mentioning here is Mailgen. It is aimed at creating HTML templates for transactional emails. There is a note on Github, that with Mailgen you can “Programmatically create beautiful emails using plain old JavaScript.” The package includes:
  • several open-source themes 
  • custom elements (tables, action buttons, etc.)

It is your choice how to send an email created with Mailgen, but they recommend checking out Nodemailer for this purpose. 

FeatureNodemailerEmailjsEmail templatesMailgen
Building HTML emailsyesYes +MIMEYes + CSS and customization+templatesyes+CSS+themes
Email sendingSMTP, SES, sendmailSMTPLadno
Github rating (starts) (as on Aug 10, 2022)14.9k2k3.4k2.5k
Last commit (as on Aug 10, 2022)Aug 1, 2022Apr 29, 2022Jul 23, 2022Jul 6, 2022

Nodemailer is the most popular package, which offers functionality for both email creation and email sending, period. It’s not limited to one sending method.

But it won’t be easy to create a special email template. With no real alternative that surpasses Nodemailer in functionality,  the optimal route is using it in combination with another package.

To find all related packages and plugins, search for nodemailer in npm.

Sending HTML emails with dynamic content

In our previous blog post, we reviewed several examples of sending HTML emails with Nodemailer, embedding images, and attaching files. 

In most cases, for transactional emails like registration confirmation, resetting passwords, and other notifications, you need to use dynamic content. It will be easier and more efficient to do it with one of the template modules.

Let’s experiment with the email-templates package. It has several interesting features:

  • Support for different template engines (Pug is a default one)
  • Email preview (by default) in the development environment
  • Direct email sending. So, you don’t need extra packages like Nodemailer for email sending. 

First of all, let’s create our templates, for a frequently occurring scenario: new user registration. In this example, we are working with the default option (for more details and samples of using Pug, refer to Github where the rest of the following code can be found.) 

Install the template engine:

npm:

npm install email-templates pug

yarn:

yarn add email-templates pug

We should create two files: subject and HTML body.

subject.pug:
= `Hi ${firstName} ${lastName}, happy to see you at My App!`
html.pug:
   h1 Hello #{firstName} #{lastName}
    p.
Welcome to My App! Now your test emails will be safe. We just need to make sure your account is real. 
Please, click the button below and start using your account. 
a(href='https://example.com/confirmation') Confirm!


Now make sure that your directory has all the .pug and .js files in the following structure:

├── app.js
├── emails
│   └── welcome (the template name)
│       ├── html.pug
│       ├── subject.pug
│       └── text.pug

Pay attention to the text part of your message: if you don’t include it, it will be generated automatically. But if you add it, it will be rendered automatically. This means that the content of the text and HTML parts may differ.

Now we can write some code to gather all the elements together and add transport. As usual, we will use Mailtrap Email Testing, to be able to test, send, control, and check everything from top to bottom.

const Email = require('email-templates');
const email = new Email({
 message: {
   from: 'hi@example.com'
 },
 send: true,
 transport: {
   host: 'smtp.mailtrap.io',
   port: 2525,
   ssl: false,
   tls: true,
   auth: {
     user: '1a2b3c4d5e6f7g', // your Mailtrap username
     pass: '1a2b3c4d5e6f7g' //your Mailtrap password
   }
 }
});

const people = [
 {firstName: 'Diana', lastName: 'One'},
 {firstName: 'Alex', lastName: 'Another'}
];

people.forEach((person) => {
 email
   .send({
     template: 'welcome',
     message: {
       to: 'test@example.com'
     },
     locals: person
   })
   .then(console.log)
   .catch(console.error);
}).

By default, the preview of your email will be opened in your browser. It might be helpful if you are working on your template and don’t need to actually send the message.

If you need to test how the variables work, and you compose a message that has dozens or even hundreds of sender addresses, be careful with this option.

To switch it off, specify options.open as false.

This is why we use Email Testing: we will see how the message looks for each recipient, explore both HTML and text versions, and will be able to perform additional checks.

With Pug and email-templates, you can build a complex template using CSS, inlined images, tables, etc. 

Here is an example of how it should look in the Mailtrap virtual inbox:

HTML:

Text:

Sending emails with attachments

You can add different types of data to your message in Nodemailer using the following main properties:

  • filename: the name of the attached file. Here you can use Unicode as well.
  • content:  the body of your attachment. It can be a string, a buffer, or a stream.  
  • path: path to the file, to stream it instead of including it in the message. It is a good option for big attachments.
  • href: attachment URL. Data URIs are also supported.
    list: {
            // List-Help: <mailto:admin@example.com?subject=help>
            help: 'admin@example.com?subject=help',

            // List-Unsubscribe: <http://example.com> (Comment)
            unsubscribe: [
                {
                    url: 'http://example.com/unsubscribe',
                    comment: 'A short note about this url'
                },
                'unsubscribe@example.com'
            ],

            // List-ID: "comment" <example.com>
            id: {
                url: 'mylist.example.com',
                comment: 'my new list'
            }
        }
    };

Optional properties let you add specific content types or inline images.

  • contentType: if you don’t set it, it will be inferred from the filename property
        // An array of attachments
        attachments: [
            // String attachment
            {
                filename: 'notes.txt',
                content: 'new important notes',
                contentType: 'text/plain' // optional, would be detected from the filename
            },
  • CID: inline images in the HTML message. For more details on attaching images to HTML emails, read this post. Note that the CID value should be unique.
    cid: 'note@example.com' // should be as unique as possible
            },

            // File Stream attachment
            {
                filename: 'matrix neo.gif',
                path: __dirname + '/assets/neo.gif',
                cid: 'neo@example.com' // should be as unique as possible
            }
        ],
  • Encoding: can be added to the string type of content. It will encode the content to a buffer type according to the encoding value you set (base64, binary, etc.)           
           // Binary Buffer attachment
            {
                filename: 'image.png',
                content: Buffer.from(
                    'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/' +
                        '//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U' +
                        'g9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC',
                    'base64'
                )

Sending emails with Gmail 

To be able to use Gmail to send messages via your app, you should start with several account configurations.

If you use a plain password, then you should allow access to a “less secure web application”.

  1. Go to the Less secure app access section of your Google Account.
  2. Turn Allow less secure apps on.
  3. Additionally, you should enable Display Unlock Captcha.

If you are using 2-Step Verification, you should sign in with App Passwords. To create your password:

  1. Go to the Security section of your Gmail account 
  2. Choose App Passwords in the Signing into Google block
  3. Select the app and device from the list and press Generate.

Please note that you can use it for your personal account only. It’s not available for accounts that are a part of an organization. 

What else you should remember when setting the Gmail SMTP:

  1. Gmail will automatically set the authenticated username as the From email address. To change it, you should “Add another address you own”. You will find it in your Gmail account -> Settings-> Accounts.

For more details, refer to this Google Help Center article

  1. Gmail has its own email limits. For free (trial) accounts, it’s only 500 emails per day. If you reach the limit, your account might be suspended.

Now, when you made all necessary configurations, let’s set up the Gmail’s SMTP as a transport in the Node.js app.

Gmail SMTP hostname is smtp.gmail.com, port should be 465 for SSL connection or 587 for TLS.

var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 465,
    secure: true, // use SSL
    auth: {
        user: 'yourusername@gmail.com',
        pass: 'yourpassword'
    }
});

To avoid authentication issues, it is recommended to use oAuth2. Nodemailer requires an Access Token to perform authentication. Read the instructions on the Nodemailer documentation to proceed with this method.

Once you have retrieved the client ID and client Secret, refresh the token and enable Gmail API at the API console. It is recommended to use bunyan logger:

const bunyan = require('bunyan');
const nodemailer = require('../lib/nodemailer');
let logger = bunyan.createLogger({
    name: 'nodemailer'
});
logger.level('trace');
// Create a SMTP transporter object
let transporter = nodemailer.createTransport(
    {
        service: 'Gmail',
        auth: {
            type: 'OAuth2',
            user: 'mail',
            clientId: 'clientid',
            clientSecret: 'clientsecret',
            refreshToken: 'refreshtoken',
            accessToken: 'accesstoken',
            expires: 12345
        },

Otherwise, to get an access token, you can use xoauth2 package.  
For more detailed instructions on using Gmail, refer to our Nodemailer Gmail Tutorial

Sending emails without SMTP 

If you stick to one of the popular email sending providers like Sendgrid, Mandrill, Mailgun, or Postmark, you can integrate your Node.js app with their API directly.

For AWS SES, there is a wrapper around Nodemailer, node-ses. You can use aws-sdk directly, but node-ses provides a simpler way to send complex emails templates with images and attachments. 

Bottom line

If you are adding email sending functionality to your Node.js app, most likely you will use Nodemailer. It is the simplest and most popular sending option compatible with other packages.

Whatever route you decide to go, always choose the option which best suits your current environment and needs. Just don’t forget to inspect and debug your test emails before delivering them to your customers.

Check out some of our other posts from the “How to send emails with different frameworks and technologies” series.

Article by Diana Lepilkina Content Specialist @Mailtrap