Postfix Basics
What Postfix is
Postfix is a Mail Transfer Agent (MTA). It handles sending and relaying email between systems. It does not handle mailbox storage or user access — that is Dovecot's job.
Important files
/etc/postfix/main.cf # main configuration
/etc/postfix/master.cf # service process definitions
Key concepts
- relay
- Forwarding mail onward through another mail server (relayhost).
- queue
- Mail waiting to be sent or delivered. Check it when mail is not moving.
- mynetworks
- Trusted client networks allowed to relay mail without authentication. Be conservative — include only your own subnets.
Common settings in 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, 192.168.1.0/24
relayhost = [smtp.example.com]:587
home_mailbox = Maildir/
relayhost to port 587 (the submission port used by most hosted mail providers and internal relays), you almost always need to add SASL authentication and enable STARTTLS. Add these two lines to main.cf:
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
Then create /etc/postfix/sasl_passwd with the credentials and run postmap /etc/postfix/sasl_passwd. Use smtp_tls_security_level = encrypt (or may for opportunistic TLS) rather than the legacy smtp_use_tls. Without these settings, Postfix will connect but authentication will fail and mail will queue.
# Format of /etc/postfix/sasl_passwd (one line per relay):
# [hostname]:port username:password
[smtp.office365.com]:587 user@example.com:AppPassword123
[smtp.gmail.com]:587 user@gmail.com:app-specific-password
# After creating or editing the file:
postmap /etc/postfix/sasl_passwd # creates sasl_passwd.db
chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
systemctl reload postfix
Useful commands
postconf -n
postconf -n
Shows non-default active Postfix settings. Very useful because it cuts through the noise of commented-out defaults.
postfix check
postfix check
Checks the Postfix config for obvious problems. Run this first when troubleshooting.
postfix reload / status
postfix status
postfix reload
postqueue -p / mailq
postqueue -p
mailq
Shows the mail queue — messages waiting to be sent. If messages are piling up, find out why they are not being delivered.
Queue operations
# Flush the deferred queue — attempt delivery now
postqueue -f
# Inspect the content of a specific queued message
# (Queue IDs shown by postqueue -p, e.g. A1B2C3456789)
postcat -q A1B2C3456789
# Delete a specific queued message
postsuper -d A1B2C3456789
# Delete all messages in the deferred queue (stuck, undeliverable)
postsuper -d ALL deferred
# Requeue all held messages (move held → active)
postsuper -H ALL
Use postcat -q QUEUEID to read a queued message's headers and body — useful for confirming what is stuck and why. postsuper -d ALL deferred clears the backlog without touching messages actively being delivered.
Service checks
systemctl status postfix
journalctl -u postfix -n 50
Troubleshooting
- Service status and recent logs
- Config syntax:
postfix check - Non-default config:
postconf -n - Queue status:
postqueue -p - DNS / MX resolution for destination domains
- Relayhost reachable:
nc -zv smtp.example.com 587 - Auth/TLS config if using authenticated relay
Submission port (master.cf)
Port 25 is for server-to-server relay; end-users (and apps) should submit mail on 587 (submission, STARTTLS) or 465 (submissions, implicit TLS). Enabling 587 is a one-line uncomment in /etc/postfix/master.cf plus a handful of service-scoped overrides.
# /etc/postfix/master.cf — submission service on 587
submission inet n - n - - 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_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_tls_auth_only=yes
-o milter_macro_daemon_name=ORIGINATING
Per-service overrides in master.cf take precedence over main.cf, so the submission listener can require TLS and SASL while port 25 remains configured for inbound relay with looser rules. smtpd_tls_security_level=encrypt means TLS is mandatory (not opportunistic) — a client that refuses STARTTLS is rejected before it ever sees AUTH. The smtpd_sasl_path=private/auth line assumes SASL is delegated to Dovecot; see Dovecot for the matching service auth { ... } block.
# Validate and reload, then confirm 587 is listening
postfix check
systemctl reload postfix
ss -tlnp | grep ':587'
# Quick auth+TLS probe (requires the openssl package)
openssl s_client -starttls smtp -crlf -connect mail.example.com:587
postscreen & DNSBL
postscreen is a lightweight pre-filter that weeds out the most obvious bots before Postfix spins up a full smtpd process — it handles pregreet tests, DNSBL lookups (Spamhaus Zen, SpamCop, etc.) and weighted scoring. It lives in master.cf, not main.cf, and only runs on port 25.
smtp service on port 25; you cannot also have a classic smtpd on the same port. Enable postscreen by replacing the smtp inet line in master.cf — do not run both. Submission (587) is unaffected and keeps its own smtpd instance as shown above.
For the tuned DNSBL score thresholds, whitelist/blacklist CIDR lists, and the full smtpd_*_restrictions stack, see Postfix Config. For the TLS-and-DKIM signing side (submission on 587 plus outbound DKIM via opendkim), see Postfix TLS & DKIM.