How to send emails in Javascript (3 ways with Node examples)
Tags: javascript, node, testing, api
Published: 2020-04-14 12:53:28

# How to send emails in Javascript (3 ways to send and test emails with NodeJS)

### 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](https://www.sendgrid.com), [MailJet](https://www.mailjet.com), [MailGun](https://mailgun.com). 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.

```javascript
// 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](https://aws.amazon.com/ses/) 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.

```hcl
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.

```javascript
// 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](https://github.com/tomav/docker-mailserver/wiki/Using-in-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.

```javascript
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](https://www.mailslurp.com) automatically as part of an end-to-end or smoke test.

With [MailSlurp](https://www.mailslurp.com) 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](https://www.mailslurp.com) - 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:

```javascript
// 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](https://www.mailslurp.com)!