So You Wanna Build a (Test) Mail Server

I’ve recently been working on an app which processes data in an email box. Old school!

What’s the best way to test that? We could mock out the mail service and do occasional smoke tests against the real mail server. That approach is fine, but leaves the mail server integration code untested for most builds.

Another approach is to black box test with a real mail server. For this you would need:

  • A test mail server setup that runs cleanly in docker
  • An easy way to send a message to that server

On top of that you could also add any mail clients in your programming language of choice to send or receive messages.

Here’s a setup I’ve been using.

Send Mail from the Command Line

Let’s assume our mail server is called mailserver (which will be true in a bit) and let’s look at the s-nail command:

echo "My Message Body" | s-nail -s "This is the subject" \
  -a /path/to/attachment \
  -S v15-compat -S smtp-auth=none -S mta=smtp://mailserver:25 \
  user@codingcraftsman.wordpress.com

The above command sends a mail with a subject, body and attachment to a mail server called mailserver. Let’s unpack some of the highlights:

  • The body is echoed and piped to the command
  • The subject is the `-s` parameter
  • An attachment can be provided with the `-a` parameter
  • The `-S` parameters are settings for `s-nail`, in this case setting which version of the settings to use, the fact that our smtp server has no auth, and the mta, which is the address and port of the mailserver called `mailserver`
  • The last parameter is the target email address

To get s-nail you can create a docker container, mounting any volumes containing attachments. The docker container with the mail client can share a network with the mail server, so it can reach it.

Here’s a dockerfile I found on the net to provide s-nail on an ubuntu base:

FROM ubuntu:latest
ENV DEBIAN_FRONTEND="noninteractive"
RUN apt-get update
RUN apt-get install -y s-nail

A Standalone Test Mail Server

There is a handy specialization of the more complex docker mail server project that works well for testing.

Here’s my docker-compose.yml setup for this:

  mailserver:
    container_name: mailserver
    image: antespi/docker-imap-devel:latest
    volumes:
      - ./10-auth.conf:/etc/dovecot/conf.d/10-auth.conf
      - ./10-ssl.conf:/etc/dovecot/conf.d/10-ssl.conf
    # expose the SMTP and IMAP ports
    ports:
      - 25:25
      - 143:143
    environment:
      MAILNAME: codingcraftsman.wordpress.com
      MAIL_PASS: password
      MAIL_ADDRESS: user@codingcraftsman.wordpress.com

You’ll note there are two volume mounts of files. These are overrides of the built in configuration files and are used to turn off SSL authorization. You may not need to override them. If you do, then the settings to change in clones of the files:

  • `10-ssl.conf` -> `ssl=no`
  • `10-auth.conf` -> `disable_plaintext_auth=no`

Putting it Together

These two services can then be put in the same dockerfile, and so reside on the same network. The docker compose for the mail client:

  mailclient:
    build:
      context: .
      dockerfile: MailUtilsDockerfile
    volumes:
      - ./test-data:/opt/test-data

We can use docker-compose up mailserver to bring the mail server up, and use docker-compose run mailclient to execute s-nail commands on the mail client. In the above docker compose file, I’ve mapped a test-data folder into the container.

In practice, I put my long send mail command into a shell script, which I added to the container’s definition in its docker file, so I could have easier commands.

Does it Work?

Actually, yes. The containers start up quickly enough, even on Windows! The simplicity of this environment once you get it set up, is better than fears over a simulated mock mail server, or the inconvenience of hitting a real-world mailbox that changes over time and needs its real life credentials protecting.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s