Run your own mail server with Postfix and Dovecot

Ansible role with commentary for setting up your own mail server with Postfix and Dovecot.

This could be considered a part two of Mail relay, MX backup and spam filtering with Postfix. Many postfix configurations are identical between these setups.

Why

Anyone can set up there own mail server and start exchanging e-mail with every other Internet user in the world. This is quite amazing I think.

So many things on the Internet today is controlled by a handful of tech giants. E-mail is something you can and should control yourself. It’s a bit complex to setup but done right it’s stable and low maintenance.

I have run my own mail servers for well over a decade. The setup I describe below has with minor changes been running in production since 2013. I recently upgraded them to Debian 9 Stretch and in early 2016 I started using Letsencrypt certs.

I host domains for my company and my family so mail between us are reasonably secure since all traffic uses TLS. E-mail is not a secure way to communicate but with your own server your mail is at least not used to target you for ads and what not.

To get started

Don’t be a cargo cult sysadmin, read the documentation.

Ansible mailserver role

Complete configurations can be found in my mailserver role at frjo/ansible-roles on Github. This is what I use to set up my own servers.

The common role that set up a firewall and other essentials on all my servers, the letsencrypt role for free certs and the dbserver role are also on GitHub. At the moment you will need to setup a web server with PHP support yourself, or take a look at Running Drupal on Debian 9 with Apache 2.4, HTTP/2, event MPM and PHP-FPM (via socks and proxy).

What you will get

  • Mail server with (almost) only standard Debian 9 packages so easy to keep updated via apt.
  • Virtual domains, mailboxes and aliases stored in MariaDB (MySQL but better).
  • Postfix for SMTP with opportunistic TLS, SPF and Postscreen configured.
  • Dovecot for IMAP/POP with required TLS.
  • PostfixAdmin - web based administration interface for Postfix mail servers. (the only non Debian package)
  • Spam filtering with DNSBL Spamhaus ZEN and BarracudaCentral.
  • Support for address extensions, user+whatever@example.com addresses.
  • Striping of outgoing mail headers that reveal unneeded information like users IP address, mail client etc.

What you will not get

  • Webmail, see no use for that now that most people have a smartphone with a e-mail client built in.
  • Bayesian filtering or other text filtering systems. I believe this belongs on the client side.
  • DKIM/DMARK, I find them cumbersome and of no benefit.

DNS - get this right and good things will follow

Make sure the servers IP address is not blacklisted. It need to be a static address in good standing or your mail will get marked as junk.

The DNS record should look something like this. Please do not forget to set a valid PTF (pointer) record. In best case it should be the reverse of the A record but in must exist and be a valid address for the server.

mail.example.com.	3600	IN	A	123.4.5.6
6.5.4.123.in-addr.arpa.	3600	IN	PTR	mail.example.com.

With the MX record you tell all other mail servers what server handle the mail for your domain.

example.com.		3600	IN	MX	10 mail.example.com.

If you set up some mail relay servers as I have done your MX record might look like this.

example.com.		3600	IN	MX	10 mx1.example.com.
example.com.		3600	IN	MX	20 mx2.example.com.

The SPF record tells other mail servers what servers are allowed to send mail for your domain.

The following is what I often use. It says that servers with a A or MX record for the domain is valid but none other. If you are using other external services to send e.g. news letters you need to add them as well.

example.com.		3600	IN	TXT	"v=spf1 mx a -all"

If you run your web server on a separate host and have the MX records pointed at mail relays you can explicitly add the mail servers A record like this.

example.com.		3600	IN	TXT	"v=spf1 a a:mail.example.com mx -all"

If you like some of my customers use Mailgun (or other services) to send out mail remember to add them to your SPF record. For Mailgun it looks like this.

example.com.		3600	IN	TXT	"v=spf1 a mx include:mailgun.org -all"

Dovecot

Postfix handles the sending and receiving of mail. Dovecot is what users, or rather their mail client of choice, connect to when they want to read the mail.

Dovecot is the most standard compliant IMAP server and it just works. I used Courier for the first few years but never looked back after switching to Dovecot.

It supports the IDLE command so mail will arrive almost instantaneously on desktop mail clients that support it. Push support for iOS would be really nice to have and it’s possible to get working but it’s not straight forward.

Dovecot configuration consist mostly of making it talk with Postfix and MariaDB for user authentication. Postfix will handle all authentication via Dovecot.

Postfix

A lot of the Postfix configuration is identical to the Mail Relay setup, see article link above. What follows is an quick overview of some Postfix configurations specific for the mail server.

The Ansible role will set up all this but it’s good to understand what it does and why.

Let Postfix in chroot jail access MariaDB sock

On Debian Postfix is by default set up to run in a chroot environment. This provides a significant barrier against intrusion. It also creates a stumbling block since it stops Postfix from accessing files outside the chroot jail.

By mounting /var/run/mysqld in /var/spool/postfix/var/run/mysqld we allow the postfix processes to access the MariaDB sock and all is well.

Authenticate via Dovecot

This will make Postfix authenticate users via Dovecot. Users mail clients will connect directly to Postfix for sending mail and we need them to authenticate.

# SASL settings
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_authenticated_header = yes

Virtual domains, mailboxes and aliases stored in MariaDB

This makes it possible to host multiple domains on one single mail server. Postfix will look up mailboxes and aliases in the database and deliver valid mail to dovecot or send onward if an alias point to an external address.

All local mail will be stored in the /var/spool/vmail directory belonging to the vmail user.

virtual_minimum_uid = 5000
virtual_gid_maps = static:5000
virtual_uid_maps = static:5000
virtual_mailbox_base = /var/spool/vmail
virtual_alias_domains =
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
default_destination_concurrency_limit = 5
relay_destination_concurrency_limit = 1

Administer with PostfixAdmin

PostfixAdmin is a web interface written in PHP. It’s simple but works well for administering mailboxes and aliases for multiple domains.

The playbook is not using the latest version since I had trouble getting that to work. Since the older version works without issues I have not put a lot of time investigating the problem.

To be on the safe side I put it behind an Apache basic auth protection.

Removing headers on outgoing mail for security reasons

With smtp_header_checks you can manipulate the headers of mail sent out from the server by users. I use it to remove some headers for security reasons.

I remove X-Originating-IP, information about the mail client and the received header. This way the e-mail will appear to originate from the mail server itself and not reveal unnecessary information about the sending device/user.

# /etc/postfix/smtp_header_checks
#
# /^HEADER:.*content_to_act_on/ ACTION [MESSAGE]

/^Received:/                 IGNORE
/^User-Agent:/               IGNORE
/^X-Mailer:/                 IGNORE
/^X-Originating-IP:/         IGNORE

Further reading

Ars Technica has a four part article series “Taking e-mail back” that has a lot of good information.

Other good articles.