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
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 \ firstname.lastname@example.org
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
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
FROM ubuntu:latest ENV DEBIAN_FRONTEND="noninteractive" RUN apt-get update RUN apt-get install -y s-nail
A Standalone Test Mail Server
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: email@example.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.