My Road to Docker: Sorting Out SMTP

This post is part of a series on this project. Here is the series so far:

Having said in my last ‘Road to Docker’ post that I didn’t have any current plans for another post, something came up which warrants a write up here. I managed to solve the problem in question in a Dockerised fashion and I’m quite pleased with the solution. Let’s get into it….

The Backstory

After converting my web stack over to Docker recently, I had installed the WP Mail SMTP plugin in WordPress to handle mail from the site. This was required since WordPress could no longer send via a local mail setup. I configured the plugin to send via my existing mail server. This worked well for a while – then I encountered a speed bump on my road to Docker!

For some reason (I think due to an update of the WordPress container), I just stopped receiving email from the site. Upon investigation it seemed that the TLS connection was unable to be started correctly. I got the following debug log when testing mail via WordPress:

SMTP Debug:

2019-07-30 08:38:11	Connection: opening to, timeout=300, options=array (
2019-07-30 08:38:11	Connection: opened
2019-07-30 08:38:11	SERVER -> CLIENT: 220 ESMTP Postfix
2019-07-30 08:38:11	CLIENT -> SERVER: EHLO
2019-07-30 08:38:11	SERVER -> CLIENT:
                   	                  250-SIZE 30720000
                   	                  250 DSN
2019-07-30 08:38:11	CLIENT -> SERVER: STARTTLS
2019-07-30 08:38:11	SERVER -> CLIENT: 220 2.0.0 Ready to start TLS
2019-07-30 08:38:12	SMTP Error: Could not connect to SMTP host.
2019-07-30 08:38:12	CLIENT -> SERVER: QUIT
2019-07-30 08:38:12	SERVER -> CLIENT: 
2019-07-30 08:38:12	SMTP ERROR: QUIT command failed: 
2019-07-30 08:38:12	Connection: closed
2019-07-30 08:38:12	SMTP Error: Could not connect to SMTP host.

Looking into the logs on the mail server, I found the following corresponding error:

warning: TLS library problem: 27261:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1275:SSL alert number 40:

I tried googling the error, but after trying a few of the suggested fixes, I gave up and decided to solve the problem a different way.

Fixing it, Take 1

My first attempt involved installing Postfix on the host in a smarthost configuration to my main server. This is the same setup as I use on most of my servers for system mail from cron, etc (via a custom Ansible role).

After getting the mail system running and able to send mail from the host, I tried to configure it in WordPress. However, I was unable to connect to the host machine from the container on the Docker host IP address. I investigated this and found that because I was using a private network the IP address was different than the standard Docker interface address.

Trying this address didn’t work either. Perhaps this is a security feature in Docker, or perhaps I was doing it wrong. Either way it pushed me on to a better solution.

Fixing it, Take 2

My next plan involved putting Postfix into a container. This would be put on the same private network as the WordPress container to allow access. I needed to keep the smarthost configuration to talk to the main mailserver. A quick search turned up a suitable image in the form of boky/postfix. This image is intended exactly for this purpose and I was able to set it up without too much trouble.

To spin this up I added the following to my previous docker-compose.yml file:

    image: boky/postfix
      - ""
      RELAYHOST_TLS_LEVEL: "verify"
      - /home/rob/docker-data/postfix/spool:/var/spool/postfix
      - internal
    restart: always

Pretty simple! As per the previous post I put all the secrets into an file to keep them separate from the stack.

The mail forwarder is available both on the internal Docker network and on the host system to replace the native mail forwarding setup. Setting this up with WordPress ended up being trivial (see screenshot below). However, I required some further configuration to make the mail on the host system work.

my road to docker smtp
We just use the container name as the hostname and 587 as the port! Authentication and SMTP aren’t required for the local connection.


In order to redirect the system mail from the host via the Dockerised mail forwarder, I had to set up MSMTP. This is pretty effectively documented elsewhere, so I won’t go into details. The only differences in this setup are that we don’t require authentication or TLS to the mail forwarder because it’s only available locally. The mail forwarder itself is already handling authentication and TLS to the main mail server.

For reference, here is the msmtprc file I ended up with:

# Set default values for all following accounts.
auth           off
tls            off
logfile        /var/log/msmtp/msmtp.log

# Local mailserver
account        local
host           localhost
port           587

# Set a default account
account default : local

aliases         /etc/aliases


Here we’ve seen how to quickly deploy a mail forwarding server for your Dockerised applications. We’ve also configured our host system to also use it, so we don’t need to run two forwarders.

I feel that this is the best solution to this problem (although I still don’t quite know what the original problem was!). It feels like a nicer solution than my original solution of running the mail forwarder locally. It has also resulted in one more Dockerised application!

I’m intending to convert my other Docker servers over to this approach in the near future. For the system mail part, I still need to create an Ansible role to push out the MSMTP configuration. Actually, the whole question of Ansible/host configuration and how it fits with Dockerised services is still something I need to work out. If anyone has any ideas feel free to share in the comments.

As I said in the last post, I don’t have any more ‘Road to Docker’ posts planned in the immediate future. However, the migration is ongoing so there will be more at some point!

One response to “My Road to Docker: Sorting Out SMTP”

  1. Quick Project: Splitting Docker Compose Projects – Blogging to Nowhere

    […] basic approach here is to move my two common containers (my Traefik container and SMTP forwarder) into their own project. This project will create a couple of networks for interfacing to the […]

Leave a Reply

Your email address will not be published. Required fields are marked *

Bad Behavior has blocked 371 access attempts in the last 7 days.