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:
- https://mxtoolbox.com/SuperTool.aspx for SPF / DKIM / DMARC / Blacklists
- Logs
/var/log/mail.log
Troubleshooting
Mails rejected by Gmail / Outlook
Check:
- rDNS configured
- SPF, DKIM, DMARC published
- IP not blacklisted (https://mxtoolbox.com/blacklists.aspx)
- If recent IP, "warm-up": send progressively
"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
- Postfix docs: http://www.postfix.org/documentation.html
- Dovecot docs: https://doc.dovecot.org
- OpenDKIM: http://www.opendkim.org
- Mail-tester: https://www.mail-tester.com


















