Posted:

E-Mail Done My Way, Part 2 - dovecot

10 minute read

0. The Journey - The basics and outlook (on the series, not the Microsoft mail client ;)
1. Postfix - the in and out, so to say. The robust, battle-hardened connection point for other mail servers on the internet to send emails to and receive emails from your domain(s). Also known as the MTA, the Mail Transfer Agent.
2. Dovecot - where you and your users talk to to get emails to their mail client, be it your smartphone, a mail client on your computer or just even the command line. It’s the IMAP server.
3. DKIM/DMARC/SPF - Just having postfix and dovecot up and running isn’t enough. We will also look at user authentication, letsencrypt certificates, DKIM, DMARC, SPF and the daily checks to make sure everything is humming along nicely.
4. The final stuff - How to make sure my e-mail server is happy and can do its job. Some simple checks, how to use fail2ban to keep bad servers and users away, checking log files, all those little things.

After we learned about my general approach and setup in part 0, the details of my postfix configuration in part 1 it is now time to look at how I use dovecot.

WARNING: This series is not for people trying to set up their first ever email server. I expect readers to know the basics and have some experience with dovecot.

In part 1 we saw how emails from other servers arrive at postfix and get either rejected (spam, bots) or accepted. Now we will talk about what happens after the e-mail gets accepted and handed over from postfix to dovecot. But that’s not the only job dovecot has. It also serves as my imap server, meaning its also talking to my various mail clients on my laptop, phone and iPad.

We will do it the same as before, by going through the config files and I will explain what settings I have changed and why. Ready? OK. Here we go again :)

dovecot.conf

Whereas with postfix we made a lot of changes to the main config file /etc/postfix/main.cf, in /etc/dovecot/ we have to deal with many more files, mostly in the conf.d subdirectory. The top level config file, /etc/dovecot/dovecot.conf only needs one line to be changed:

# Protocols we want to be serving.
protocols = imap lmtp

That’s it. All the rest in the file stays as it is. This tells dovecot that we are going to use two protocols. imap to talk to e-mail clients and lmtp to talk to postfix.

passwd

There’s another very important file in this top level directory - /etc/dovecot/passwd. This is where we store the (hashed, salted) passwords of all e-mail users. As I explained in part 1, we do NOT use local users on the system, we ONLY have users defined in this passwd file.

Here’s a user definition in that file:

user1@tcpid.org:{SSHA256}lOD2+5I3qY4UqRllY8SY6F9eJEBWhkvIdHgF9Av21ZUZuagf:1003:1003::/var/mail/vmail/tcpid.org/user1::

It is important to have the colons at all the right places and the correct parameters, so let’s go through them. user1@tcpid.org is the e-mail address which also doubles as the username when logging in via imap. Next comes the password, which is a salted SHA256 - hence SSHA256 - hash that you can create with the following command:

doveadm pw -s SSHA256
Enter new password: 
Retype new password: 
{SSHA256}lOD2+5I3qY4UqRllY8SY6F9eJEBWhkvIdHgF9Av21ZUZuagf

Here I typed in a password twice and got the hash, that I can now add to the line in the passwd file.

Now, as explained in part 1, all incoming e-mails for all domains are handled by the virtual mail config with a single user called vmail. The next two entries, the :1003:1003 are the UID of the user and group. Now a double colon :: followed by the path to the Maildir of this e-mail address, using the pattern /var/mail/vmail/<DOMAIN>/<USER> and a double colon ::at the end. That’s the full definition of an e-mail account in dovecot.

So when I want to add a new e-mail address, I just add a new line to this file. That’s it.

Let’s move into the conf.d subdirectory that has many files. We don’t need to change them all. But still, quite a few. Let’s work through them!

/conf.d/10-auth.conf

This file defines the authentication process. We want to use just username and passwords as defined in the passwd file, nothing more. No pam, no LDAP, no local users, no databases. - BUT we will NOT allow logins via unencrypted connections. It all MUST go through TLS. Hence we need 4 changes

disable_plaintext_auth = yes

This makes sure we have to use a TLS connection before authentication can happen.

auth_username_format = %Lu

This forces us to use the full e-mail address as username. Important, because at least I use the same local user for several domains and I want to have them clearly separated with different passwords and maildirs.

Unfortunately many companies out there still haven’t learned that the local part (the part before the @ symbol) indeed is case-sensitive, so jan@ and JAN@ are technically different e-mail recipients. That’s why we put in the %L which turns everything to lowercase, so no matter if you send to Jan@, jan@, JAN@ or jAn@ - it all gets moved to jan@.

auth_mechanisms = plain login

This makes sure we can use the username/password way to authenticate. And because we have made sure that there must be a TLS connection, we can safely use the plain method. login is a quirky variant of plain, mainly for Microsoft Outlook users. Not strictly needed for me, as I’d never touch Outlook, but who knows, other users might. So let’s leave it there. Doesn’t hurt.

#!include auth-deny.conf.ext
#!include auth-master.conf.ext
!include auth-vmail.conf.ext
#!include auth-system.conf.ext
#!include auth-sql.conf.ext
#!include auth-ldap.conf.ext
#!include auth-passwdfile.conf.ext
#!include auth-checkpassword.conf.ext
#!include auth-static.conf.ext

And now we disable all authentication mechanisms except auth-vmail.conf.ext which points to the passwd file mentioned earlier. We’ll get to that.

/conf.d/10-logging.conf

This file defines what goes to the logfile. One single change is needed here, to make sure we catch the bots trying many username/passwords combinations to brute-force their way in, trying to turn our mailserver in a spam factory.

# Log unsuccessful authentication attempts and the reasons why they failed.
auth_verbose = yes

By adding this to the logfile, fail2ban can pick up these evil bots and block them. How that works well be in part 3 of this series.

All the rest stays as is.

/conf.d/10-mail.conf

This file defines the location of the maildir, so we make sure it all ends up in /var/mail/vmail/<DOMAIN>/<USER>/Maildir/

mail_location = maildir:~/Maildir

/conf.d/10-master.conf

In this file we define the protocols and the communication via lmtp with postfix. The protocol definitions can stay as they are, we do imap and imaps (with TLS), we don’t care about the other definitions like pop3 because, well, we don’t use them.

We do however have to set up the lmtp connection to postfix with:

service lmtp {
 unix_listener /var/spool/postfix/private/dovecot-lmtp {
   mode = 0600
   user = postfix
   group = postfix
  }
}

and add:

    unix_listener /var/spool/postfix/private/auth {
      mode = 0600
      user = postfix
      group = postfix
    }

to the service auth section in this file.

/conf.d/10-ssl.conf

Now we can define SSL/TLS. As explained before, we use letsencrypt for getting and updating the certificate files. So now we need to tell postfix where it can find the public and private cert files and that SSL/TLS is required:

ssl = required
ssl_cert = </etc/letsencrypt/live/mailhub.wildeboer.net/fullchain.pem
ssl_key = </etc/letsencrypt/live/mailhub.wildeboer.net/privkey.pem

Dovecot also needs a dh.pem file for forward secrecy. This is generated with the command (we use 4096 bits):

openssl dhparam -out /etc/dovecot/dh.pem 4096

And added to the config file with:

ssl_dh = </etc/dovecot/dh.pem

Finally we want to make sure we use known good parameters with safe defaults by adding:

ssl_min_protocol = TLSv1.2

And that’s it.

/conf.d/15-mailboxes.conf

When you first connect to the mailserver to fetch your e-mails, dovecot will set up your maildir. This file tells it what folders to add by default in the namespace inbox section:

  # These mailboxes are widely used and could perhaps be created automatically:
  mailbox Drafts {
    auto = create
    special_use = \Drafts
  }
  mailbox Junk {
    auto = create
    special_use = \Junk
  }
  mailbox Trash {
    auto = create
    special_use = \Trash
  }

  # For \Sent mailboxes there are two widely used names. We'll mark both of
  # them as \Sent. User typically deletes one of them if duplicates are created.
  mailbox Sent {
    auto = create
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }

Just the typical Drafts, Junk, Trash and Sent folders that most mail clients expect to find.

/conf.d/auth-vmail.conf.ext

And finally the vmail authentication:

# Virtual user auth config
mail_location = maildir:~/Maildir
passdb {
  driver = passwd-file
  args = /etc/dovecot/passwd
}
userdb {
 driver = static
 args = uid=vmail gid=vmail username_format=%u home=/var/mail/vmail/%d/%n
}

Here we tell dovecot that passwords can be checked with the passwd file, that users can be found using the staticdriver, which uses the vmail user and group, that the full e-mail address is the username (%u) and that we switch the logged in users to their correct mail directory under `/var/mail/vmail//.

And done

And that’s it! When all of this is set up correctly, the directory /var/mail/vmail is owned by the vmail user, postfix is up and running as described in part 1, we can start dovecot and enjoy the flow of mails coming in and going out.

Comments and tips for an even better configuration are very welcome! Either via Mastodon (see below) or, if you prefer, as issue or maybe even a pull request at the repository that generates this blog:

https://codeberg.org/jwildeboer/jwildeboersource

But we still have a lot of other things to do. SPF, DKIM, DMARC. That will be in:

Part 3: DKIM/DMARC/SPF

COMMENTS

You can use your Mastodon or other ActivityPub account to comment on this article by replying to the associated post.