A basic postfix/dovecot mail server set-up

published: 2022-01-03
title: A basic postfix/dovecot mail server set-up
tags: miscellaneous

previous [‘What it means being human (to me)’] next [‘Remove DRM from ebooks’] parent directory [‘Blog’]

Out of curiousity I wanted to set up my own mail server, to learn what magic happens between one mail client and the other. I could have run a fully configured suite in a container, like mailcow, but I found it more interesting to start more low-level to figure out what I need and don’t need. So I chose the postfix and dovecot solution.

For the major part of the configuration I followed this tutorial.

What are postfix and dovecot?

postfix is a popular mail transfer agent (MTA) (or just mailserver). So it transfers email - receiving and forwarding them via SMTP. To deliver an email, it takes a mail delivery agent (MDA), while the email client in mailserver lingo appears to be a mail user agent (MUA). I didn’t know any of this, so I had a hard time following some of the available documentation.

dovecot is an IMAP and POP3 server; in this set-up it is the MDA that receives the mails from postfix and provides the interface to my email clients to actually receive the mails.

My set-up

In contrast to e.g. Exim, postfix is a suite of binaries that each do their one thing. The actual SMTP server is smtpd. The way which binaries are used is specified in the /etc/postfix/master.cf, while the main configuration and variables definition takes place in etc/postfix/main.cf.

Basic settings

To send my mail I configure postfix’ smptd as

# /etc/postfix/master.cf

smtp       inet n       -       n       -       -       smtpd
submission inet n       -       n       -       -       smtpd

First I configure my domains:

# /etc/postfix/main.cf

mail_owner = postfix
myhostname = mail.schubisu.de  # this is the mailserver
mydomain = schubisu.de         # this is the main domain
myorigin = $mydomain           # this is what I want others to see as origin
inet_interfaces = all
inet_protocols = all
mydestination = localhost      # mails are not forwarded to another server, localhost is the final destination

Virtual transport

There are numerous ways to set up a mailserver, depending on the use case. In my case, postfix is supposed to forward email that I write on my client to the recipient - or to the next server in that provider’s chain to process my email. For received email, it should be the final destination; the mail should be processed by dovecot to deliver it to me or other valid users of my server.

So when receiving an email, postfix will try to figure out which user is the recipient. Often single users can have multiple email addresses, so postfix needs a file to map email addresses to users. Secondly, users could be local users with a system account, or they can be virtual users. My server will be used by me and my family, but I don’t want to have a system account for each of them, so I go with virtual users and a virtual user map, or virtual alias map.

Here’s an excerpt of my virtual user table:

# /etc/postfix/virtual

robin@schubisu.de robin@schubisu.de
robin@mail.schubisu.de robin@schubisu.de
...

This maps multiple email addresses to one virtual user robin@schubisu.de. For postfix to be able to use this table, it needs to be converted with postmap /etc/postfix/virtual resulting in a binary virtual.db file.

I still want a single system user take care of the virtual users, so I add a new system user vmail with uid=5000 and gid=5000 and tell postfix to let this user handle the virtuals:

# /etc/postfix/main.cf

# the user that handles the virtual users
virtual_minimum_uid = 5000
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = hash:/etc/postfix/virtual

I’ll have to do the same thing with the destination of my email. I want it to be stored on the server in a Maildir format, but that will be handled by dovecot later. So I map my virtual users to their Maildir locations in /etc/postfix/vmailbox:

# /etc/postfix/vmailbox

robin@schubisu.de  schubisu.de/robin

And another postmap command to convert this file to binary.

In my configuration file I add

# /etc/postfix/main.cf

# the destination where mail will be stored on the server
virtual_mailbox_domains = schubisu.de mail.schubisu.de
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox

I found that information in the [postfix documentation][virtual-alias] for virtual transport. After we have specified all this, dovecot should take over to deliver the mails, so we add

# /etc/postfix/main.cf

dovecot_destination_recipient_limit = 1
virtual_transport = dovecot

and in /etc/postfix/master.cf

# /etc/postfix/master.cf

dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/dovecot-lda -f ${sender} -d ${recipient}

The pipe command is another command from the postfix toolbox; here we specify the dovecot section that was set for virtual transport. We let the local delivery agent dovecot-lda handle the mail from here on. I took this snippet from their documentation.

Transport encryption

# /etc/postfix/main.cf

smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = /var/run/dovecot/auth-client
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_received_header = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.schubisu.de/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.schubisu.de/privkey.pem
smtpd_sasl_local_domain = $mydomain
smtpd_tls_loglevel = 1
smtp_tls_security_level = may
smtp_tls_loglevel = 1

Dovecot settings

Mailserver reputation

# /etc/postfix/main.cf

smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Fighting spam