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:
1 2 3 4 | 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:
1 2 3 4 | 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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | 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:
1 2 3 4 5 6 | 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.
Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: So You Wanna Build a (Test) Mail Server Opinions expressed by Java Code Geeks contributors are their own. |