Docker, PHP and E-Mail: getting things to work
Integrating Mailhog and SSMTP in your development environment
It’s a common need for software nowadays to send notifications through e-mail: registration confirmations, password recovery requests, event notifications and so on. As my colleagues develop software, they often encounter problems while dealing with such e-mail exchange in their local (Docker) environment.
The problem
Let’s say you are also developing a PHP application and you want to use docker in your development machine. You will notice that – if you use the official PHP images from the docker hub – sending e-mail out of the box simply won’t work. Lets’ see what I mean in practice, considering this simple index.php file, sending out an e-mail:
1 2 3 4 5 6 7 |
$result = mail("info@example.com", "Subject", "The very important email body"); if ($result) { echo "Email sent correctly"; } else { echo "Error sending the email"; } |
Please note: using the mail command to send an email is the simplest way, but there are many more powerful libraries out there that could make things easier. We have chosen to use the mail command just to keep the example as simple as possible.
If we run it using docker with the following command:
1 |
docker run -p "80:80" -v `pwd`:/var/www/html --rm php:7-apache |
and visit http://localhost with our browser, we’ll see that the mail command will fail, and we’ll get an “Error sending the email” message.
The reason why this happens is that the “mail” command relies on the “sendmail” system command inside the container, which is missing from the official PHP docker image.
While you could simply create a new image extending the original one and adding the sendmail command, I suggest using a different strategy.
Here at MV Labs we do use a tool called Mailhog (https://github.com/mailhog/MailHog) which acts as an SMTP server listening on port 1025 but instead of sending real emails to your recipients, it simply displays them in a handy web interface (which is listening, by default, on port 8025). This way you avoid the risk of sending your testing e-mails to the customer (it happened at least once to everybody) and you don’t have to deal with spam filters or other annoyances in the e-mail chain.
So, how can we achieve this? To make things easier, we can take advantage of docker-compose. Let’s start by adding the mailhog container to our services:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
version: '2' services: php: image: php:7-apache volumes: - .:/var/www/html/ ports: - 80:80 networks: - base mailhog: image: mailhog/mailhog ports: - 8025:8025 networks: - base networks: base: |
Now, if we run docker-compose up
and head our browsers to http://localhost:8025 we should see the mailhog simple but powerful web interface.
We’re not done yet, though, as we still need to tell the mail command to send emails through our new mailhog smtp server. Unluckily this requires the building of a custom docker image, since PHP doesn’t allow using the native mail command to connect to a SMTP server. For this reason, we need a tool called ssmtp (https://linux.die.net/man/8/ssmtp) which is basically a configurable sendmail command replacement, and which forwards the message to a SMTP server configured in its config file. We’ll need the following Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 |
FROM php:7-apache # install ssmtp RUN apt-get update; apt-get install ssmtp -y # tell php to use ssmtp's sendmail for email sending RUN echo "sendmail_path=/usr/sbin/sendmail -t -i" >/usr/local/etc/php/conf.d/sendmail.ini # tell ssmtp to use mailhog as the mail transport RUN echo "Mailhub=mailhog:1025" > /etc/ssmtp/ssmtp.conf RUN echo "FromLineOverride=Yes" >> /etc/ssmtp/ssmtp.conf |
Then we’ll need to tell docker-compose.yml to build the image from the Dockerfile for our PHP container:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
version: '2' services: php: build: . volumes: - .:/var/www/html/ ports: - 80:80 networks: - base mailhog: image: mailhog/mailhog ports: - 8025:8025 networks: - base networks: base: |
and build our containers again with:
1 |
docker-compose up -d --build |
Now we’re ready to send our first “virtual” email. Just head your browser to http://localhost and you’ll get the message “Email sent correctly”. If you check your mailhog at http://localhost:8025 you’ll see your email!
Summary
Using a simple example, we have demonstrated one possible solution for sending test e-mails out of our web applications under development in a secure and handy way, by using some nice open source tools such as SSmtp and Mailhog inside a docker dev environment.
Let us know what you think in the comments area below and happy developing!