Test Your Email Flow with Mailhog, a Fake SMTP Server
Tags: webdev, docker, testing, tutorial
Published: 2020-06-18 21:02:57

---
title: Test Your Email Flow with Mailhog, a Fake SMTP Server
published: true
description: Learn how to set up Mailhog with Docker so you can test your email flow for free 
tags: WebDevelopment, Docker, Testing, Tutorial
cover_image: https://res.cloudinary.com/dmq9pzw0o/image/upload/v1592513724/test-your-email-flow-with-mailhog-a-fake-smtp-server/Group_1_omihri.png
canonical_url: https://jfelix.info/blog/test-your-email-flow-with-mailhog-a-fake-smtp-server
---

_Don't want to code along? Here is the [GitHub repository](https://github.com/Jfelix61/mailhog-docker-express-example) for what we are building on this post!_

Most apps sooner or later will have to deal with sending emails to the user, that being after registration or a specific event. After sending the email, a developer most likely would want to test how the user would receive it or if there is a link, how it reacts within the app. Using a real SMTP server for this can be tricky and could end up spamming a user with emails without needing to. That is why a fake SMTP server can be useful as it can allow you to send emails to a safe box that will trap all these emails and can be fetched if you need to use them to test your flow or content. There are many SaaS (Software as a Service) that can set up this server for you, however, they can be costly and limiting. That is why in this post, I'll be teaching you how to use [Mailhog](https://github.com/mailhog/MailHog) with Docker to create a fake email server and be able to fetch emails so you can use it on your tests.   

## Creating an Express Server

In this tutorial, I'll use an [Express](https://github.com/expressjs/express) server with [Nodemailer](https://github.com/nodemailer/nodemailer) since it is my main toolset. Regardless, this method will work for any stack that can use SMTP as a client. First, start a node environment by running: 

```bash
npm init -y
```

Then, install the required dependencies: 

```bash
npm install --save express nodemailer
```

Next, create a `server.js` which will start our server: 

```jsx
const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => res.send("Hello World!"));

app.listen(port, () =>
  console.log(`Example app listening at http://localhost:${port}`)
);
```

Add a start script in `package.json` to start our server:

```jsx
{ 
  "scripts": {
    "start": "node server.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  }, 
}
```

Finally, start the server with:

```jsx
npm run start
```

![Running server on server port 3000](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1592513879/test-your-email-flow-with-mailhog-a-fake-smtp-server/Untitled_tryhhj.png)

## Setting up docker

Setting Mailhog is as easy as using your OS install command. However, if you are sharing your repository with other developers it would be nice to use Docker so that it can work as expected in other machines or CI (Continous Integration). Also, the developer is able to clean the history as needed by just removing the container.

If you don't have docker installed please refer to their [site](https://www.docker.com/) and follow their instruction on how to install for you OS. 

> Note: If you are using Linux, please install Docker Compose on their [docs page](https://docs.docker.com/compose/install/)

Once you have installed docker create a `Dockerfile`. This will fetch a Node.js image and start our server.

```docker
FROM node:10

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

CMD [ "node", "server.js" ]
```

Also, create a `.dockerignore:`

```docker
node_modules
npm-debug.log
```

Create a `docker-compose.yaml` which will start up our just created Dockerfile and also Mailhog. 

```docker
version: '2.4'

services:
  node:
    build:
      context: .
      dockerfile: Dockerfile 
    ports:
      - '3000:3000'     

  mailhog:
    image: mailhog/mailhog:latest
    restart: always
    ports:
      - 1025:1025
      - 8025:8025
```

Finally, run:

```docker
docker-compose up --build
```

And you will see that our images will be built and our servers will start automatically! 

![Mailhog and server initialized with Docker](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1592513912/test-your-email-flow-with-mailhog-a-fake-smtp-server/Untitled_1_kxbn52.png)

## Receiving Emails

To receive emails we just have to send them as we would for a normal SMTP. Go to `server.js` and add the following : 

```jsx
const express = require("express");
const nodemailer = require("nodemailer");
const app = express();
const port = 3000;

const transporter = nodemailer.createTransport({
  host: "mailhog",
  port: 1025
});

app.get("/send_email/:email", (req, res) => {
  const { email } = req.params;

  const messageStatus = transporter.sendMail({
    from: "My Company <company@companydomain.org>",
    to: email,
    subject: "Hi Mailhog!",
    text: "This is the email content",
  });

  if (!messageStatus) res.json("Error sending message!").status(500);

  res.json("Sent!").status(200);
});

// ...
```

Here we create a Nodemailer transport with Mailhog's default credentials. Also, a GET route that receives an `email` parameter to where we want to 'send' it. Now if you head in your browser and type [`http://localhost:3000/send_email/test@test.com`](http://localhost:3000/send_email/test@test.com) you will see a 'sent!' JSON response. If you head towards Mailhog's dashboard on `[localhost:8025](http://localhost:8025)`, the email we just sent will be visible and you can open it to see any details such as headers, and text content. 

![Mailhog dashboard](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1592513938/test-your-email-flow-with-mailhog-a-fake-smtp-server/Untitled_2_z0rjdw.png)

## Query Mailhog

Querying Mailhog is as easy as doing it for a REST server. To find all the possible routes to query,  you can find their [Swagger](https://swagger.io/) JSON and YAML [on their GitHub](https://github.com/mailhog/MailHog/tree/master/docs/APIv2). To get all the emails from a specific email we use the following GET route `http://localhost:8025/api/v2/search`. Since we sent a message to `test@test.com` our query will be `http://localhost:8025/api/v2/search?kind=to&query=test@test.com`. If you paste this in your browser you'll see the email we just sent! 

![Queried email JSON](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1592513954/test-your-email-flow-with-mailhog-a-fake-smtp-server/Untitled_3_ydvvut.png)

Awesome! Now you can use this information for testing using Cypress or Jest. 

## Conclusion

Testing email flows is very important to guarantee a stellar experience for users, especially since these flows can sometimes be fundamental for general functionality like a sign-up confirmation. Using our real STMP server can result in sending a user an email by mistake. Also, by setting a fake SMTP using a SaaS provider like Mailtrap can be expensive. Instead, we can use Mailhog and Docker to create this server quickly that allows us to query for sent emails so we can use them in our tests without dealing with quota or price plans. 

For more up-to-date web development content, follow me on [Twitter](https://twitter.com/Jose_R_Felix), and [Dev.to](https://dev.to/jfelx)! Thanks for reading! 😎

---

Did you know I have a newsletter? 📬

If you want to get notified when I publish new blog posts and receive an **awesome weekly resource** to stay ahead in web development, head over to [https://jfelix.info/newsletter](https://jfelix.info/newsletter).