Mail-Server with Cow Power
My mail server have seen better days and it’s time to think about a new stack.
A modern mail server should cover:
- Anti-Spam tools with auto-learning
- SSL Encryption
- DKIM mail signing
- Sender policy framework (SPF)
- Webmail UI
- Filter-rules for ie vacation auto-reply
- Docker containers
The most difficult part is the anti-spam implementation. Its a narrow burr between spam and ham. A good spam filter should block most real spam but has to be permissive enough to accept your friends mails.
I’ve used Postfix as SMTP and Dovecot for IMAP along with SpamAssassin and Postgrey for anti-spam and greylisting. I achieved good results using this stack.
Greylisting is a technique to block mails from unknown servers in a way that the sending SMTP thinks the target is not reachable. Ordinary mail servers would retry the delivery for some time but spammers (mostly) give up on the first fail. The drawback is a delay of about 15 minutes for mails from unknown servers and this can be really annoying.
Some researches brought me to rspamd. This nice anti-spam tool scans the incoming mails and uses greylisting only if the spam rating exceeds a given threshold. It looks like a better replacement for SpamAssassin and Postgrey.
Mailcow
A friend who has written some german posts about his mail setup recommended mailcow. I took a deeper look at the dockerized version of mailcow which differs from the standard setup but includes all the things from my must-have feature list and has a nice WebUI.
So I tried mailcow. The setup was pretty easy, a little bash script generates
a config for you and docker-compose up
does the rest. Mailserver up and
running in one minute. Nice!
SOGo Groupware
Mailcow bundles the SOGo Groupware solution but it’s nothing I need. To get
rid of it remove the sogo-mailcow
definition from the docker-compose.yml
file. But from now, dovecot won’t start anymore. The entrypoint script needs the
sogo volume mounts. A look at the docker-entrypoint.sh
shows that it
populates only some sieve credentials to one file. I opened a
pull request
to make this optional and rebuilt the image myself.
docker-compose.yml adjustments
Mailcow’s compose file looks pretty good but it uses volume containers what
I dislike. I prefer volume mounts to specify the path on the host system.
Because I’ve an global reverse proxy I also kicked the nginx container. The
last adjustment affects the service names. I.e. the mailcow-postfix
service
obtain mailcow_mailcow-postfix
as container name because docker-compose adds
the project name prefix.
Rainloop Webmail
I choose Rainloop as webmail client cause it looks simple and integrates a sive filter management. The setup is pretty straight forward but some points must be considered:
- Every Domain must be set up in the admin tool
- Use SSL for IMAP and SMTP
- Use STARTTLS for Sieve
Send mails from the docker host system
Usually the host-system has its own postfix installation configured as mail
relay but the port 25 is occupied by mailcow. Just comment the line starting
with smtp inet ...
in /etc/postfix/master.conf
. After an restart postfix
does not bind the port anymore but sendmail can still deliver mails.
DNS, DKIM, SPF
A proper DKIM and SPF setup needs correct DNS records.
Mailcow lets you generate DKIM Keys and uses dkim
als selector.
The DNS records could look like:
@ IN TXT "v=spf1 a mx -all"
_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:you@example.com"
dkim._domainkey IN TXT "v=DKIM1;k=rsa;t=s;s=email;p=MIGfMA0...DAQAB"
This defines that the SPF validation should accept if the sender IP
matches the A
or MX
record and reject all others.
There are some tools you can use to check your setup like MX Toolbox
That’s it basically, if you didn’t it already, checkout Mailcow