Dovecot Basics
What Dovecot is
Dovecot handles:
- IMAP and POP3 access — letting users read their mail from clients
- Mailbox storage and management
- Authentication for mail access (and sometimes as an auth backend for Postfix via SASL)
Postfix moves mail between servers. Dovecot lets users access their mailboxes. They work alongside each other — Postfix delivers incoming mail into the mailbox; Dovecot serves it to clients.
Listener ports
# Default listener ports:
143 IMAP (STARTTLS upgrades from plaintext)
993 IMAPS (TLS from the start — older but still widely used)
110 POP3 (STARTTLS)
995 POP3S (TLS from the start)
# Check which ports Dovecot is actually listening on
ss -tlnp | grep dovecot
lsof -i -P -n | grep dovecot
LMTP — receiving mail from Postfix
In a typical setup, Postfix delivers locally-addressed mail to Dovecot via LMTP rather than writing mailbox files directly. This lets Dovecot handle delivery, indexing, and sieve filters.
# In Postfix main.cf — deliver via Dovecot LMTP socket
virtual_transport = lmtp:unix:private/dovecot-lmtp
# or over TCP:
virtual_transport = lmtp:inet:localhost:24
# In Dovecot /etc/dovecot/conf.d/20-lmtp.conf:
protocols = imap pop3 lmtp
# The LMTP socket is created by Dovecot at: /var/spool/postfix/private/dovecot-lmtp
TLS check
# Verify Dovecot TLS certificate and connection
openssl s_client -connect mail.example.com:993 -quiet
# Look for: subject, issuer, verify return code = 0 (ok)
# Test IMAP over STARTTLS (port 143)
openssl s_client -connect mail.example.com:143 -starttls imap
Common files
/etc/dovecot/dovecot.conf
/etc/dovecot/conf.d/
Main config is dovecot.conf. The conf.d/ directory contains split configuration files loaded in order. Key files:
10-auth.conf— authentication settings10-mail.conf— mailbox location10-ssl.conf— TLS settings20-imap.conf,20-pop3.conf— protocol settings
Useful commands
doveconf
doveconf
doveconf -n
Shows the effective Dovecot configuration. -n shows non-default values only — like postconf -n for Postfix.
doveadm who
doveadm who
Shows currently connected users and sessions.
doveadm user
doveadm user '*'
Shows mailbox and user info for all users (depending on auth backend setup).
Service checks
systemctl status dovecot
journalctl -u dovecot -n 50
Troubleshooting
- Service status and recent logs
- Config check:
doveconf— look for errors - Login failures in logs — check for bad password or unknown user
- Mailbox location permissions — can Dovecot read the mailbox directory?
- Auth backend issues (PAM, LDAP, SQL, FreeIPA/SSSD)
- TLS cert valid and permissions correct on key file
Sieve filtering (pigeonhole)
Dovecot's pigeonhole plugin implements RFC 5228 Sieve — server-side filters that run at LMTP delivery time, before the message reaches the user's INBOX. Users can edit their own rules (via ManageSieve on 4190/tcp) and the admin keeps a default rule set.
# /etc/dovecot/conf.d/90-sieve.conf
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_default = /var/lib/dovecot/sieve/default.sieve
sieve_extensions = +imap4flags +fileinto +envelope
}
# Enable the sieve plugin on LMTP and LDA
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
protocol lda {
mail_plugins = $mail_plugins sieve
}
Per-user ~/.dovecot.sieve — route spam into a Junk folder based on the header set by Rspamd/SpamAssassin:
require ["fileinto", "imap4flags"];
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
stop;
}
if header :contains "List-Id" "announce.example.com" {
fileinto "Lists/Announce";
}
After editing a script, compile it so the binary (.svbin) is cached: sievec ~/.dovecot.sieve. See Dovecot Sieve & Quotas for ManageSieve on 4190, quota-warning hooks, and shared-folder ACLs.
Debugging with doveadm
doveadm is the Swiss-army knife for mailbox inspection — it talks directly to the backend so it works even when IMAP clients are misbehaving. Three commands cover 90% of incident work:
doveadm fetch — read message content without a client
# First 20 messages in alice's INBOX with headers and flags
doveadm fetch -u alice 'hdr flags' mailbox INBOX 1:20
# Full raw RFC822 for a specific UID (useful for rebuilding a message)
doveadm fetch -u alice 'text' mailbox INBOX uid 42
# List every folder across every user
doveadm mailbox list -A
doveadm search — find a missing message
# Find a message by subject, across all folders, for one user
doveadm search -u alice mailbox-guid all subject "invoice #4711"
# Find messages older than 30 days, system-wide (all users with -A)
doveadm search -A mailbox INBOX savedbefore 30d
# Was anything delivered in the last 5 minutes?
doveadm search -A mailbox INBOX savedsince 5mins
doveadm who / kick — live sessions
# Who is connected right now, from where, and how many connections
doveadm who
doveadm who -1 # one line per session (useful for grep)
# Force-disconnect an abusive client
doveadm kick 203.0.113.42
doveadm kick alice # kick all sessions for a user
If doveadm fetch succeeds but the IMAP client cannot see the same message, the fault is almost always a stale client-side index — doveadm index -u alice INBOX rebuilds it.
passdb options
passdb (password database) tells Dovecot how to verify credentials; userdb tells it where that user's mail lives. Several drivers are available and can be stacked — the first passdb that returns "user found" wins.
passdb { driver = pam }— delegate to Linux PAM (the default on new installs). Easy to integrate with SSSD/FreeIPA but forks adovecot-auth-workerper request.passdb { driver = sql }— query a MySQL/Postgres/SQLite table via/etc/dovecot/dovecot-sql.conf.ext. Best for virtual-domain hosting where users are not Linux accounts.passdb { driver = ldap }— bind or compare against LDAP/389DS/AD using/etc/dovecot/dovecot-ldap.conf.ext. Supportsauth_bind = yesfor bind-as-user verification.passdb { driver = passwd-file }— a plain file (user:{SCHEME}hash:uid:gid::home::). Handy for a small fixed user list or test environments.
auth_cache_size = 10M in 10-auth.conf to cache successful lookups in memory — critical for sql/ldap backends so every IMAP NOOP doesn't hit the database. Pair with auth_cache_ttl = 1 hour and auth_cache_negative_ttl = 1 hour to bound the staleness. Pre-auth failures are covered by SSSD in most FreeIPA setups; see SSSD & Auth Flow.