Skip to content

Instantly share code, notes, and snippets.

@tvlooy
Last active October 13, 2022 15:47
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tvlooy/b053370535be665ede108a3cb86c1603 to your computer and use it in GitHub Desktop.
Save tvlooy/b053370535be665ede108a3cb86c1603 to your computer and use it in GitHub Desktop.
Dealing with email on a testing server

Dealing with email on a testing server

There are lots of setups with programs that can collect email in testing environments. Some of them require you to install perl, nodejs, ruby, ... or require you do do a sophisticated setup with your mailserver.

But there is a little program called mailhog that is just a standalone statically linked binary that has no dependencies.

That makes it very easy to use.

Mailhog

Just download the latest release and put it into your /usr/local/bin:

wget -O /usr/local/bin/mailhog https://github.com/mailhog/MailHog/releases/download/v1.0.0/MailHog_linux_amd64
chmod +x /usr/local/bin/mailhog

You can just start the program by running /usr/local/bin/mailhog.

The SMTP will be available on port 1025 and the web UI on port 8025.

Systemd

We want mailhog to start with system boot and restart when it would crash. You can do that sort of stuff with systemd. Create a file named /lib/systemd/system/mailhog.service with this in it:

[Unit]
Description=Mailhog SMTP

[Service]
User=mailhog
Group=mailhog
WorkingDirectory=/home/mailhog
Restart=always
ExecStart=/usr/local/bin/mailhog -api-bind-addr 127.0.0.1:8025 -ui-bind-addr 127.0.0.1:8025 -smtp-bind-addr 127.0.0.1:1025

[Install]
WantedBy=multi-user.target

Create the user mailhog with group mailhog and home directory /home/mailhog first, or leave it out and mailhog will run as root. Running stuff as root is a bad idea, especially if it is something that listens on the network.

It's also not a good idea to make mailhog accessible on your public IP. It does that by default so that's why you would add -api-bind-addr 127.0.0.1:8025 -ui-bind-addr 127.0.0.1:8025 -smtp-bind-addr 127.0.0.1:1025 to make it only listen on localhost.

Now enable the mailhog service to start it at boot time and then start it manually:

systemctl enable mailhog
systemctl start mailhog

Postfix

We hook it up to postfix and make it so that if you mail to an email address ending in .external, it will be relayed to a real server. And, if doesn't we relay it to mailhog.

Eg: mail to tom@somedomain.tdl will go to mailhog and tom@somedomain.tdl.external will be delivered to tom@somedomain.tdl.

Postfix configuration /etc/postfix/main.cf:

myhostname = myserver.mydomain.tld
relayhost = real-smtp-relay.mydomain.tld
smtp_generic_maps = pcre:/etc/postfix/smtp_generic_maps.pcre
transport_maps = hash:/etc/postfix/transport

The smtp maps make sure that the .external part is stripped off.

/(.*)\.external$/ $1

The transport maps decide that .external addresses will be relayed to the real SMTP server and the rest will be relayed to mailhog.

.external :
*           smtp:127.0.0.1:1025

Because the transport maps are hashed you need to run postmap /etc/postfix/transport.

Apache

I do want to make mailhog available on my public IP on /mailhog/. But I want to do it with an Apache proxy that requires basic HTTP authentication.

Create the file /etc/apache2/conf-available/mailhog.conf with this in it:

RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /mailhog/(.*) ws://0.0.0.0:8025/$1 [P,L]

ProxyPreserveHost Off
ProxyRequests Off
<Proxy *>
    AuthType Basic
    AuthName "Authentication required"
    AuthUserFile "/etc/apache2/mailhog.password"
    Require user mailhog

    Order deny,allow
    Allow from all
</Proxy>
ProxyPass /mailhog/  http://0.0.0.0:8025/
ProxyPassReverse /mailhog/ http://0.0.0.0:8025/

Generate the password file:

htpasswd -c /etc/apache2/mailhog.password mailhog

Enable the necessary Apache modules, and enable the config:

a2enmod proxy proxy_http rewrite
a2enconf mailhog

systemctl reload apache2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment