WARNING: Dovecot has breaking changes in the configuration between 2.3 and 2.4. Be sure to update the configuration files according to the version you are using.

Install Postfix

sudo apt install postfix postfix-lmdb

The installer will ask two questions.

  • General mail configuration type: Internet Site
  • System mail name: mail.example.jp (The installer will pick up the server FQDN by default)

Open ports for SMTP (25) and Submissions (formerly SMTPS, 465).

sudo firewall-cmd --add-service=smtp --permanent
sudo firewall-cmd --add-service=smtps --permanent
sudo firewall-cmd --reload

LMDB

Update /etc/postfix/main.cf to use LMDB instead of Berkeley DB (hash, or btree).

# Update hash: to lmdb:
alias_maps = lmdb:/etc/aliases
alias_database = lmdb:/etc/aliases

# Update btree: to lmdb:
smtp_tls_session_cache_database = lmdb:${data_directory}/smtp_scache

# Set default DB to LMDB
default_database_type = lmdb
  • default_cache_db_type cannot be added because it’s available from Postfix 3.11 (Debian 13 Postfix is 3.10)

Migrate alias database to LMDB.

sudo newaliases
sudo rm /etc/aliases.db

CrowdSec collection for Postfix

Install CrowdSec collection for Postfix to block malicious activities.

sudo cscli collections install crowdsecurity/postfix
sudo systemctl reload crowdsec

Virtual Mailbox

To isolate the email accounts from Unix user accounts, set up the virtual mailbox.

Create Mail Storage User

Make a new user vmail and store all mails under its home directory /home/vmail.

$ sudo adduser vmail
New password: <password>
Retype new password: <password>
passwd: password updated successfully
Changing the user information for vmail
Enter the new value, or press ENTER for the default
        Full Name []:
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] y

Disable shell login because this account is only for the mail storage.

sudo usermod -s /usr/sbin/nologin vmail

Configure Virtual Users

The Postfix documentation has an example of the Non-Postfix mailbox store: separate domains, non-UNIX accounts.

Modify /etc/postfix/main.cf to send all emails to the virtual mailbox.

# Delete domains for the virtual mailbox
mydestination = localhost

# Add virtual mailbox configurations
virtual_mailbox_domains = mail.example.jp, example.jp
virtual_mailbox_maps = lmdb:/etc/dovecot/users
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_alias_maps = lmdb:/etc/postfix/virtual
  • virtual_mailbox_maps will be generated later from the Dovecot user database.

To catch local system mails (e.g. cron job), edit /etc/postfix/virtual.

admin@mail.example.jp info@mail.example.jp
mailer-daemon@mail.example.jp info@mail.example.jp
postmaster@mail.example.jp info@mail.example.jp
root@mail.example.jp info@mail.example.jp

Make LMDB file of /etc/postfix/virtual.

sudo postmap virtual

Reload Postfix to apply changes to main.cf

sudo systemctl reload postfix

Dovecot-LMTP

Install Dovecot-LMTPd

Dovecot-LMTP will take over emails from Postfix and deliver them to the final destination directories in /home/vmail/.

sudo apt install dovecot-lmtpd

Configure Dovecot

As explained in the Postfix and Dovecot LMTP, dovecot-lmtpd is integrated with Postfix via the unix socket.
Configure the lmtp section in /etc/dovecot/conf.d/10-master.conf to open the socket where Postfix can access.

  • The socket must be in /var/spool/postfix because Postfix is chrooted.
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
   }
}

Update Debian defaults in /etc/dovecot/conf.d/10-mail.conf to specify the mail defaults.

# Debian defaults
# Note that upstream considers mbox deprecated and strongly recommends
# against its use in production environments. See further information
# at
# https://doc.dovecot.org/2.4.1/core/config/mailbox/formats/mbox.html

# Update defaults to mdbox (NOT mbox) on virtual mailbox
mail_driver = mdbox
mail_home = /home/vmail/%{user | domain}/%{user | username}
mail_path = %{home}/mdbox
# Comment out (or delete) mail_inbox_path (it's for mbox)
#mail_inbox_path = /var/mail/%{user}

(snip)

# System user and group used to access mails. If you use multiple, userdb
# can override these by returning uid or gid fields. You can use either numbers
# or names. <https://doc.dovecot.org/latest/core/config/system_users.html#uids>
mail_uid = vmail
mail_gid = vmail

Comment out auth_username_format default in /etc/dovecot/conf.d/20-lmtp.conf.

protocol lmtp {
  #mail_plugins {
  #  sieve = yes
  #}

  # This strips the domain name before delivery, since the default
  # userdb in Debian is /etc/passwd, which doesn't include domain
  # names in the user.  If you're using a different userdb backend
  # that does include domain names, you may wish to remove this.  See
  # https://doc.dovecot.org/2.4.1/howto/lmtp/exim.html and
  # https://doc.dovecot.org/2.4.1/core/summaries/settings.html#auth_username_format
  #auth_username_format = %{user | username | lower}
}

Configure /etc/dovecot/conf.d/10-auth.conf to choose how to control the user list.

  • Comment out auth-system (mail accounts are isolated to the virtual mailbox)
  • Uncomment auth-passwdfile (a simple text file is enough to handle users)
#!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

Configure passdb and userdb locations in /etc/dovecot/conf.d/auth-passwdfile.conf.ext.

passdb passwd-file {
  auth_username_format = %{user | lower}
  passwd_file_path = /etc/dovecot/users
}

userdb passwd-file {
  auth_username_format = %{user | lower}
  passwd_file_path = /etc/dovecot/users
}
  • passdb and userdb can be the same file
  • Dovecot will look up the user list with the full email address in lowercase
  • Other configurations are left as default or set in the other conf files

For more details, see official documentation.

Reload Dovecot to apply new configurations.

sudo systemctl reload dovecot

Userdb

The userdb /etc/dovecot/users will keep the list of usernames (email addresses) and their encrypted passwords. The command doveadm will generate the encrypted password.

$ sudo doveadm pw
Enter new password: 
Retype new password: 
{CRYPT}$2y$0...(snip)...Iiy0.

Copy and paste the above encrypted password to Userdb as a part of the info@example.jp information.

info@example.jp:{CRYPT}$2y$0...(snip)...W5Qa::::::
  • The trailing six colons :::::: are for uid/gid/home/mail_location. All of them are left blank to use the default values.

Dovecot checks this every time it gets an email. After updating this userdb, no reload or db compile is required.

Userdb for Postfix

Generate postfix lmdb file from this userdb.

Create a new shell script /etc/dovecot/postfix_lmdb.sh to generate the lmdb file.

#!/bin/bash
awk -F: 'NF > 0 && $1 != "" {print $1 " OK"}' /etc/dovecot/users > /etc/dovecot/users.tmp
postmap lmdb:/etc/dovecot/users.tmp
mv /etc/dovecot/users.tmp.lmdb /etc/dovecot/users.lmdb
rm /etc/dovecot/users.tmp
  • This lmdb has usernames and dummy OK values because it’s only for the user existence check by Postfix. (The value should be the mailbox location, but never used in this case.)

Add execute permission to this script.

sudo chmod +x /etc/dovecot/postfix_lmdb.sh

Whenever the userdb is updated, run this script to update the lmdb file for Postfix.

sudo /etc/dovecot/postfix_lmdb.sh

Test

Follow the logs with journalctl and send a test mail to the valid user on this server.

sudo journalctl -f SYSLOG_FACILITY=2

If you need detailed logs, turn on debug switches in /etc/dovecot/conf.d/10-logging.conf.

auth_verbose = yes
auth_debug_passwords = yes