Server — Mail — Dovecot
Dovecot has two jobs in February’s mail setup. The first is to provide an IMAP server so mail clients can connect, authenticate, and read mailboxes. The second is to provide a local delivery agent for Postfix: rather than Postfix writing mail directly to disk, it hands incoming messages to Dovecot via LMTP, and Dovecot delivers them to the correct virtual mailbox. This arrangement lets Dovecot handle Sieve filtering at delivery time and gives Postfix a clean, simple delivery interface.
The two Postfix connections, LMTP for delivery and SASL for authentication, are the pieces most articles get wrong through incomplete socket configuration. This article covers both.
Installation
sudo apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-sieve dovecot-managesieved
The packages installed here:
dovecot-core — the Dovecot daemon
dovecot-imapd — IMAP protocol support
dovecot-lmtpd — LMTP delivery agent for receiving mail from Postfix
dovecot-sieve — Sieve mail filtering at delivery time
dovecot-managesieved — ManageSieve protocol for remotely managing Sieve scripts
POP3 is not installed. IMAP covers every use case POP3 covers and more. There is no reason to expose POP3 on a new mail server.
Confirm Dovecot is running after installation:
sudo systemctl status dovecot
Dovecot’s configuration structure
Dovecot’s configuration is split across many files in /etc/dovecot/conf.d/. The main /etc/dovecot/dovecot.conf includes them all. This article edits specific conf.d files rather than the main file. The changes are noted by filename throughout.
Mail location and virtual user setup
Dovecot needs to know where to find mailboxes. The virtual mailbox directory structure created in the virtual domains article was /var/vmail/domain/localpart/. Dovecot’s mail location must match.
Edit /etc/dovecot/conf.d/10-mail.conf:
mail_location = maildir:/var/vmail/%d/%n/Maildir
mail_privileged_group = vmail
%d expands to the domain part of the authenticated user’s address. %n expands to the local part. So for you@yourdomain.com, Dovecot looks for mail at /var/vmail/yourdomain.com/you/Maildir.
The mail_privileged_group = vmail line gives Dovecot the ability to access mail owned by the vmail group, which is who owns the mailbox directories.
Authentication
Password file
For a small number of virtual users, a flat password file is simpler than a database backend. Dovecot reads usernames and passwords from a file in its own format.
Create the password file at /etc/dovecot/users:
you@yourdomain.com:{ARGON2I}$argon2i$...
admin@yourdomain.com:{ARGON2I}$argon2i$...
Generate a hashed password using Dovecot’s built-in tool:
sudo doveadm pw -s ARGON2I
Enter the password when prompted. Copy the full output including the {ARGON2I} prefix into the users file, preceded by the email address and a colon. Add one user per line.
Set permissions:
sudo chown root:dovecot /etc/dovecot/users
sudo chmod 640 /etc/dovecot/users
Authentication backend configuration
Edit /etc/dovecot/conf.d/10-auth.conf:
disable_plaintext_auth = yes
auth_mechanisms = plain login
# Comment out the default system user authentication
#!include auth-system.conf.ext
# Enable the password file authentication
!include auth-passwdfile.conf.ext
disable_plaintext_auth = yes refuses plaintext authentication on unencrypted connections. Since TLS is configured below, all client connections will be encrypted, so PLAIN and LOGIN mechanisms are safe to use.
Edit /etc/dovecot/conf.d/auth-passwdfile.conf.ext:
passdb {
driver = passwd-file
args = scheme=ARGON2I /etc/dovecot/users
}
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/vmail/%d/%n
}
The userdb section uses a static driver, meaning all virtual users get the same vmail UID and GID, with home directories derived from their email address. This matches the /var/vmail directory structure.
TLS configuration
Dovecot needs a certificate for IMAPS on port 993. The TLS article from this series generated a certificate for MariaDB; the same internal CA can issue a certificate for the mail server, or you can use a Let’s Encrypt certificate if February is publicly accessible and the domain is publicly resolvable.
For an internal-only certificate signed by February’s internal CA:
cd /etc/ssl/mail
sudo openssl genrsa -out mail.key 4096
sudo openssl req -new -key mail.key -out mail.csr -subj "/CN=mail.yourdomain.com"
sudo openssl x509 -req -days 825 -in mail.csr -CA /etc/mysql/tls/ca-cert.pem -CAkey /etc/mysql/tls/ca-key.pem -CAcreateserial -out mail.crt
sudo chown root:dovecot mail.key
sudo chmod 640 mail.key
Edit /etc/dovecot/conf.d/10-ssl.conf:
ssl = required
ssl_cert = </etc/ssl/mail/mail.crt
ssl_key = </etc/ssl/mail/mail.key
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
ssl = required means Dovecot will not allow connections without TLS. The leading < on the cert and key paths tells Dovecot to read the file contents rather than treating the value as a literal string.
Services and sockets
This is the most important section. Dovecot needs to expose two Unix sockets for Postfix: one for LMTP delivery and one for SASL authentication. Both must be in a location Postfix can reach, which means inside Postfix’s chroot directory at /var/spool/postfix/private/.
Edit /etc/dovecot/conf.d/10-master.conf:
service imap-login {
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
group = vmail
}
}
service auth-worker {
user = vmail
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
}
Setting the plain IMAP port to 0 disables unencrypted IMAP. All client connections must use IMAPS on port 993. The lmtp socket at private/dovecot-lmtp is where Postfix will hand off incoming mail. The auth socket at private/auth is where Postfix will verify submission credentials.
The socket permissions matter precisely. The LMTP socket is 0600 owned by postfix: only the Postfix process can write to it. The auth socket is 0660 owned by postfix with group postfix: the Postfix SMTP daemon can query it for SASL.
LMTP protocol settings
Edit /etc/dovecot/conf.d/20-lmtp.conf:
protocol lmtp {
mail_plugins = $mail_plugins sieve
postmaster_address = postmaster@yourdomain.com
}
The sieve plugin in the LMTP protocol block means Sieve filtering runs at delivery time, before mail reaches the mailbox. This is where spam messages can be automatically sorted to a Junk folder based on Rspamd’s headers.
Sieve configuration
Edit /etc/dovecot/conf.d/90-sieve.conf:
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_default = /etc/dovecot/sieve/default.sieve
sieve_global_dir = /etc/dovecot/sieve/global/
}
Create a default Sieve script that sorts spam into a Junk folder based on the header Rspamd adds:
sudo mkdir -p /etc/dovecot/sieve
sudo nano /etc/dovecot/sieve/default.sieve
require ["fileinto", "mailbox"];
if header :contains "X-Spam-Flag" "YES" {
fileinto :create "Junk";
stop;
}
Compile the script:
sudo sievec /etc/dovecot/sieve/default.sieve
This default script applies to all users. Individual users can override it with their own Sieve scripts managed via ManageSieve on port 4190.
Connecting Postfix to Dovecot
Two changes are needed in Postfix’s /etc/postfix/main.cf to complete the connection:
# Deliver mail via Dovecot LMTP
virtual_transport = lmtp:unix:private/dovecot-lmtp
# Use Dovecot for SASL authentication on submission
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = noanonymous
The virtual_transport line replaces Postfix’s direct virtual mailbox delivery with LMTP delivery to Dovecot. This is a change from the virtual domains article, which used Postfix’s own virtual delivery agent. With this in place, Postfix hands mail to Dovecot for delivery, and Dovecot handles writing to the Maildir and running Sieve filters.
Remove virtual_mailbox_maps, virtual_uid_maps, and virtual_gid_maps from main.cf if they are present. Dovecot is now responsible for the delivery details that those settings previously controlled.
Auto-creating IMAP folders
Mail clients expect certain folders to exist: Sent, Drafts, Trash, Junk. Dovecot can create these automatically when a user first logs in. Edit /etc/dovecot/conf.d/15-mailboxes.conf:
namespace inbox {
mailbox Drafts {
special_use = Drafts
auto = subscribe
}
mailbox Junk {
special_use = Junk
auto = subscribe
}
mailbox Sent {
special_use = Sent
auto = subscribe
}
mailbox "Sent Messages" {
special_use = Sent
}
mailbox Trash {
special_use = Trash
auto = subscribe
}
}
The auto = subscribe directive creates the folder and subscribes the client to it automatically on first login.
Restart and verify
Restart both Dovecot and Postfix:
sudo systemctl restart dovecot
sudo systemctl restart postfix
Check both started cleanly:
sudo systemctl status dovecot
sudo journalctl -u dovecot -n 30
sudo journalctl -u postfix -n 30
Confirm the sockets exist and have the correct permissions:
sudo ls -la /var/spool/postfix/private/dovecot-lmtp
sudo ls -la /var/spool/postfix/private/auth
Both should exist with the ownership and permissions defined in the Dovecot master config.
Testing authentication
Test that Dovecot’s IMAP authentication is working using doveadm:
sudo doveadm auth test you@yourdomain.com yourpassword
A successful result shows:
passdb: you@yourdomain.com auth succeeded
extra fields:
user=you@yourdomain.com
A failure shows the reason: usually either the user is not in the password file, or the password does not match.
Test an IMAP connection with openssl:
openssl s_client -connect february.home.arpa:993 -quiet
After the TLS handshake, you should see a Dovecot greeting:
* OK [CAPABILITY IMAP4rev1 ...] Dovecot ready.
Type a LOGIN you@yourdomain.com yourpassword to authenticate. A successful login shows a OK Logged in.
Adding a user
When a new mail address is needed, two steps are required. First, add the address to Postfix’s virtual mailbox map as described in the virtual domains article. Second, add the user to Dovecot’s password file:
sudo doveadm pw -s ARGON2I
# Copy the output
sudo nano /etc/dovecot/users
# Add: newuser@yourdomain.com:{ARGON2I}output_from_above
No restart is needed. Dovecot re-reads the password file on each authentication attempt.
UFW
Allow IMAPS from the LAN and VPN only:
sudo ufw allow from 192.168.1.0/24 to any port 993
sudo ufw allow from 10.10.0.0/24 to any port 993
Allow ManageSieve if you want users to manage their own Sieve scripts remotely:
sudo ufw allow from 192.168.1.0/24 to any port 4190
sudo ufw allow from 10.10.0.0/24 to any port 4190
What is next
Dovecot is running, authenticated, and connected to Postfix. Mail delivered by Postfix via LMTP lands in the correct virtual mailbox, Sieve sorts spam to Junk, and mail clients can connect via IMAPS. The remaining articles in the mail sub-series cover Postfix itself, DNS records for mail authentication, and end-to-end testing.