Logo

Postfix + Dovecot: complete mail server

Postfix + Dovecot: complete mail server

Build your own mail server from A to Z with Postfix (SMTP) and Dovecot (IMAP/POP3). Secure auth, TLS, SPF/DKIM/DMARC, anti-spam. The reference combo for self-hosted mail.

Introduction

Postfix: MTA (Mail Transfer Agent), handles SMTP send and receive. Dovecot: MDA (Mail Delivery Agent) + IMAP/POP3, lets clients (Thunderbird, Outlook) fetch mail.

Self-hosted mail:

  • True privacy (vs Gmail)
  • Unlimited aliases
  • No tracking, no ads
  • But: IP reputation to maintain, anti-spam to configure, lots of DNS

Prerequisites

  • Linux VPS Debian 12 / Ubuntu 24.04
  • Public IP with rDNS configured (CRUCIAL for deliverability)
  • Domain (example.com) with DNS access
  • Root access
  • Port 25 open (check with provider, some block by default)

Step 1: Prerequisites check

nc -zv smtp.google.com 25

host YOUR_IP
# Should return mail.example.com

If rDNS wrong, configure at your provider.

Domain DNS, configure first:

example.com.     MX 10 mail.example.com.
mail.example.com.   A     YOUR_IP
example.com.     TXT   "v=spf1 mx -all"

Step 2: Postfix install

sudo apt update
sudo apt install -y postfix postfix-mysql

Installer asks:

  • Choose "Internet Site"
  • System mail name: example.com

Step 3: Postfix base config

sudo nano /etc/postfix/main.cf
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
mydestination = $myhostname, localhost.$mydomain, localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

home_mailbox = Maildir/
mailbox_command =

smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no

# Basic anti-spam restrictions
smtpd_helo_required = yes
smtpd_helo_restrictions = reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname

smtpd_sender_restrictions = reject_unknown_sender_domain, reject_non_fqdn_sender

smtpd_recipient_restrictions = 
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unauth_destination,
    reject_unknown_recipient_domain

message_size_limit = 26214400          # 25 MB max
mailbox_size_limit = 0

Step 4: TLS for Postfix

Let's Encrypt:

sudo apt install -y certbot
sudo certbot certonly --standalone -d mail.example.com

Add to main.cf:

# Inbound TLS
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_use_tls = yes
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

# Outbound TLS
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_loglevel = 1

Step 5: SMTP submission (ports 587 and 465)

master.cf:

sudo nano /etc/postfix/master.cf

Enable these blocks:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject

smtps     inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
sudo systemctl restart postfix

Step 6: Dovecot install

sudo apt install -y dovecot-imapd dovecot-pop3d dovecot-lmtpd

Step 7: Dovecot config

/etc/dovecot/dovecot.conf:

protocols = imap pop3 lmtp

/etc/dovecot/conf.d/10-mail.conf:

mail_location = maildir:~/Maildir

/etc/dovecot/conf.d/10-auth.conf:

disable_plaintext_auth = yes
auth_mechanisms = plain login

/etc/dovecot/conf.d/10-ssl.conf:

ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2

/etc/dovecot/conf.d/10-master.conf (auth block for Postfix SASL):

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}
sudo systemctl restart dovecot postfix

Step 8: First mail account

Dovecot can use system accounts:

sudo adduser alice
sudo mkdir -p /home/alice/Maildir
sudo chown -R alice:alice /home/alice/Maildir

Test send (from server):

echo "Hello" | mail -s "Test" [email protected]
ls /home/alice/Maildir/new/

If a mail appears, local delivery works.

Step 9: SPF, DKIM, DMARC

SPF: declare which IPs can send for your domain.

DNS:

example.com.   TXT   "v=spf1 mx ip4:YOUR_IP -all"

DKIM: sign your mails.

sudo apt install -y opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys/example.com
cd /etc/opendkim/keys/example.com
sudo opendkim-genkey -s mail -d example.com
sudo chown opendkim:opendkim mail.private

mail.txt contains the DNS record to publish:

mail._domainkey.example.com.   TXT   "v=DKIM1; h=sha256; k=rsa; p=MIIBIj..."

Configure opendkim:

sudo nano /etc/opendkim.conf
Syslog                  yes
UMask                   002
Domain                  example.com
KeyFile                 /etc/opendkim/keys/example.com/mail.private
Selector                mail
SOCKET                  inet:8891@localhost
Mode                    sv

Postfix integration:

# /etc/postfix/main.cf
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
milter_default_action = accept
sudo systemctl restart opendkim postfix

DMARC: policy.

_dmarc.example.com.   TXT   "v=DMARC1; p=quarantine; rua=mailto:[email protected]"

p=quarantine (non-compliant -> spam) or p=reject (rejected) for stricter.

Step 10: Configure Thunderbird / Outlook

  • Incoming: mail.example.com, port 993 IMAP SSL/TLS
  • Outgoing: mail.example.com, port 587 STARTTLS
  • Auth: Linux login + password

Connect, send, receive.

Step 11: Anti-spam with Rspamd

Install Rspamd (see tutorial 40) for incoming spam filtering:

sudo apt install -y rspamd

Postfix integration in main.cf:

smtpd_milters = inet:localhost:11332, inet:localhost:8891

(rspamd on 11332, opendkim on 8891)

Step 12: Deliverability test

Send mail to https://www.mail-tester.com for a /10 score. Target: 10/10.

Also check:

Troubleshooting

Mails rejected by Gmail / Outlook

Check:

"Connection refused" on port 25

Provider blocks port. OVH, Hetzner often block outbound by default. Request opening via ticket.

IMAP auth fails

sudo tail -f /var/log/mail.log
sudo journalctl -u dovecot -f

Check disable_plaintext_auth and that you're using SSL/TLS.

DKIM not signing

sudo journalctl -u opendkim -f

Check mail.private permissions (opendkim:opendkim 600).

Mail delivered to wrong folder

mailbox_command must be empty for Maildir + Dovecot. If using procmail, configure it specifically.

Useful commands

# Postfix
sudo systemctl status postfix
sudo postfix check
sudo postconf -n
sudo postqueue -p
sudo postqueue -f
sudo postsuper -d ALL

# Dovecot
sudo systemctl status dovecot
sudo doveconf -n
sudo doveadm who
sudo doveadm mailbox list -u alice

# Logs
sudo tail -f /var/log/mail.log
sudo journalctl -u postfix -f
sudo journalctl -u dovecot -f

echo "body" | mail -s "subject" [email protected]

swaks --to [email protected] --from [email protected] --server mail.example.com:587 --tls --auth LOGIN --auth-user [email protected]

echo "test" | opendkim-testmsg -s mail -d example.com -p /etc/opendkim/keys/example.com/mail.private

Conclusion

Postfix + Dovecot gives you:

  • Complete self-hosted mail server
  • Total privacy
  • Unlimited aliases and accounts

Limits:

  • Setup and maintenance heavy
  • IP reputation to maintain (deliverability)
  • No integrated webmail (add Roundcube)

Going further:

  • Add Roundcube or SnappyMail as webmail
  • For turnkey approach, see Mailcow (tutorial 39)
  • For HA, look at OpenSMTPD or Mailu

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members