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.
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.
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
.
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
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.
# /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
# /etc/postfix/main.cf
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept