Sending emails in Javascript (3 ways to send and test emails with Node).

Sending emails in NodeJS with Sengrid, SES, or custom SMTP servers.

About

Sending emails is a core requirement of many modern businesses. Whether it’s invoice receipts, password resets, or support messages many applications send emails programmatically in response to different events. Sending emails these days is easy and doesn’t require knowledge of SMTP, POP3, or IMAP! Here are three ways to send email in NodeJS and how to test them.

Transactional mail services

There are many email-as-a-service APIs. Some of the most popular names include SendGrid, MailJet, MailGun. They each offer different features and pricing models but they all send emails on demand via API request.

Usually setup is required with the service to enable sending from a custom domain. Once this is done emails are typically sent with an SDK and REST API request. For this example we’ll demonstrate sending emails with the SendGrid SDK and Node.

Installing SendGrid SDK

You can get the official SendGrid Javascript library from NPM.

npm install -s @sendgrid/mail

Sending an eail with SendGrid

Sending an email is easy. Just provide your API key and then describe the message you wish to send. Lastly call send and let SendGrid handle the rest.

// get a instance of sendgrid and set the API key
const sendgrid = require('@sendgrid/mail');
sendgrid.setApiKey(SENDGRID_API_KEY);

// construct an email
const email = {
  to: 'test@mailslurp.com',
  from: 'test@mailslurp.com',
  subject: 'My first email',
  text: 'Hello world',
};

// send the email via sendgrid
sendgrid.send(email)

SendGrid also supports an html property for sending HTML formatted emails. It also has a feature-rich templating system with a browser based UI designer. Pricing is reasonable but for more control try the next option: AWS SES.

Email as infrastructure

If you run your application on cloud infrastructure chances are your cloud provider will have an email sending service. Amazon AWS has a Simple Email Service called SES. It’s a great option for those who want a bit more control. You can define email domains and routing rules with Terraform so that email becomes a managed part of your infrastructure.

Setup AWS SES with Terraform

SES requires a bit of setup but once enabled can be easily used with NodeJS. All AWS infrastructure can be enable by hand in the console but a better way to manage cloud resources is with Terraform.

Here is how to set up an SES domain with Terraform. This will allow us to send emails from a specific address.

resource "aws_ses_domain_identity" "example" {
  domain = "yourdomain.com"
}

resource "aws_route53_record" "example_amazonses_verification_record" {
  zone_id = "your_zone_id"
  name    = "_amazonses.yourdomain.com"
  type    = "TXT"
  ttl     = "600"
  records = ["${aws_ses_domain_identity.example.verification_token}"]
}
Sending email with AWS SES and Node

So, now that SES is set up we can call it from Node. First we need the AWS SDK.

npm install -s aws-sdk

Now let’s create a script to send the email.

// configure the AWS sdk
const AWS = require('aws-sdk');
AWS.config.update({region: 'us-west-2'});

// Create email params
const params = {
  Destination: { 
    ToAddresses: [
      'my-test-email@gmail.com'
    ]
  },
  Message: { 
    Body: { 
      Text: {
       Charset: "UTF-8",
       Data: "Hello world!"
      }
     },
     Subject: {
      Charset: 'UTF-8',
      Data: 'My email subject'
     }
    },
  Source: 'no-reply@yourdomain.com', 
};

// Create the promise and SES service object
const sendPromise = new AWS
  .SES({apiVersion: '2010-12-01'})
  .sendEmail(params)
  .promise();

// Handle promise's fulfilled/rejected states
sendPromise.then(data => {
    console.log(data.MessageId);
  }).catch(err => {
    console.error(err, err.stack);
  });

Custom SMTP server

While transactional mail services and SES are pretty straight forward if you need ultimate control deploying your own SMTP server is the way to go.

You can deploy an SMTP server on Kubernetes with a bit of setup and configuring. I won’t go into that here as it is a rather big job. Note SMTP solutions are only suggested if you have some unusual email sending requirements.

Sending email via SMTP in Node

Once that’s done you can easily interact with your SMTP server using the NPM package nodemailer.

npm install -s nodemailer

And here’s an example of sending an email with nodemailer.

const nodemailer = require("nodemailer");

const transporter = nodemailer.createTransport({
  host: "smtp.yourdomain.email",
  port: 587,
  secure: false,
  auth: {
    user: SMTP_USER
    pass: SMTP_PASSWORD
  }
});

// send mail with defined transport object
transporter.sendMail({
  from: '"YourCompany" <no-reply@yourdomain.com>', 
  to: "customer@example.com", 
  subject: "Test email", 
  text: "Hello world"
});

Testing email sending

So we’ve just seen three different ways to send emails with Node. But how do we test it? We could test our scripts manually and use our own email addresses as te recipient but this process is slow and unreliable. Ideally we want to test email sending automatically as part of an end-to-end or smoke test.

With MailSlurp you can create new email inboxes on the fly, send emails to them using your service, and then verify the results - all from within a test suite.

Install MailSlurp SDK

First you want to sign up for MailSlurp - it’s free to start. Then let’s install the MailSlurp SDK and the Jest test framework (you can use any framework you like).

npm install -s jest mailslurp-client

Testing emails with Jest

Let’s write a simple test that:

  • creates a new email address with MailSlurp
  • invokes our service’s email sending function
  • sends an email to our MailSlurp address
  • calls MailSlurp to get this email
  • verifies the results

Using the SendGrid example as a base our test might look something like this:

// can your app handle inbound emails
import { MailSlurp } from "mailslurp-client"
const api = new MailSlurp({ apiKey: "test" })

test('my app can send emails', async () => {
    // create a new email address for this test
    const inbox = await api.createInbox()

    // trigger an app action that sends an email
    await signUpForMyApp(inbox.emailAddress)

    // fetch sent email from the inbox
    // include a retryTimeout and minCount so that
    // MailSlurp waits for an email
    const emails = await api.getEmails(inbox.id, { minCount: 1, retryTimeout: 60000 })

    // assert that the correct email was sent
    expect(emails[0].length).toBe(1)
    expect(emails[0].content).toBe("Hello world")
})

That’s it! Now you can test your email sending functions with real email addresses so you know for sure that your emails are working.

Summary

Sending emails is easy these days. There are tons of services available each with different features, pricing and control. For a quickstart try SendGrid, MailJet or MailGun. For more control try Amazon SES. For even further control try running an SMTP server and use Nodemailer.

With every emailing solution it’s important to test that messages are really sent and received. Many email providers apply spam filters so the only way to know for sure that your emails are working is with an end-to-end test using real addresses. Luckily, MailSlurp has you covered. Check it out!