Add postscreen to Postfix Without Blocking Mail First
Turn on postscreen and start rejecting real mail before you have tested it, and you have made things worse, not better. This walks through the safe order: listen in observation mode first, watch the logs, then flip on the controls that turn watching into rejecting. Uses Postfix 3.8.6, the Ubuntu postfix package on the reference machine. Budget 20 to 30 minutes for inspection and a reload; longer if you want to test against a real external sender.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need root for changes under /etc/postfix and for postfix reload. The inspection commands are ordinary and unprivileged. Do not put postscreen in front of submission traffic on port 587: the manual is explicit that it is for MX traffic, not for authenticated end-user clients.
1. Confirm the installed version and service layout
Check the binary, the Postfix version, and the current master service table:
$ dpkg-query -W -f='${Package} ${Version}\n' postfix
postfix 3.8.6-1ubuntu0.1
$ postconf mail_version
mail_version = 3.8.6
$ postconf -Mf | grep -E '^(smtp|postscreen|smtpd|dnsblog|tlsproxy) '
smtp inet n - y - - smtpd
submission inet n - y - - smtpd
Exact service rows vary by installation. On the reference machine there is no postscreen row yet, so it is not handling the public SMTP listener. The daemon lives at /usr/lib/postfix/sbin/postscreen, normally started by the Postfix master service rather than run directly.
Checkpoint
Save the output of postconf -Mf before touching master.cf. It is your rollback reference.
2. Record the non-destructive defaults
Postscreen ships deliberately safe defaults for an initial observation period. Ask Postfix for the values that matter:
$ postconf -d postscreen_access_list postscreen_dnsbl_action \
postscreen_dnsbl_sites postscreen_greet_action postscreen_greet_wait \
postscreen_pipelining_enable postscreen_non_smtp_command_enable \
postscreen_bare_newline_enable postscreen_cache_retention_time
postscreen_access_list = permit_mynetworks
postscreen_dnsbl_action = ignore
postscreen_dnsbl_sites =
postscreen_greet_action = ignore
postscreen_greet_wait = ${stress?{2}:{6}}s
postscreen_pipelining_enable = no
postscreen_non_smtp_command_enable = no
postscreen_bare_newline_enable = no
postscreen_cache_retention_time = 7d
In this mode postscreen only logs what it finds and hands the connection to a Postfix SMTP server. permit_mynetworks keeps trusted networks out of the tests. An empty postscreen_dnsbl_sites means there is no DNS blocklist scoring to act on, even once you set an action later.
The wait value tracks stress: up to six seconds normally, up to two under overload. That delay alone is reason enough to test mail flow and watch logs before making postscreen a permanent fixture on the MX path.
3. Add postscreen to the MX path
Before editing anything, check the active configuration and make a dated copy as root:
$ sudo postconf -h config_directory
/etc/postfix
$ sudo cp --preserve=all /etc/postfix/master.cf /etc/postfix/master.cf.before-postscreen
Warning
The next change affects inbound SMTP service. Work in a maintenance window, and keep a second administrative session open. Do not replace the submission service. The usual arrangement has the public smtp service run postscreen, with a separate smtpd pass-through service handling connections postscreen has already accepted. The dnsblog and tlsproxy services are also needed if the chosen configuration does DNS lookups or TLS.
Use the exact service stanza your installed Postfix documentation recommends, keeping existing indentation and any local overrides intact. Do not copy a stanza from an unrelated host: chroot settings, process limits, TLS overrides and service names are all deployment-specific. The one boundary that matters is that port 25 is the postscreen entry point, and port 587 stays an authenticated smtpd service.
After editing, ask Postfix to parse the service table before reloading anything:
$ sudo postfix check
$ postconf -Mf | grep -E '^(smtp|postscreen|smtpd|dnsblog|tlsproxy) '
smtp inet ... postscreen ...
postscreen ... ... postscreen
smtpd pass ... smtpd
dnsblog unix ... dnsblog
tlsproxy unix ... tlsproxy
Spacing and which rows print depend on the local file. Treat any error from postfix check as a stop signal: restore the saved file with sudo cp --preserve=all /etc/postfix/master.cf.before-postscreen /etc/postfix/master.cf, then run sudo postfix check again.
4. Reload and verify observation mode
Only reload once the configuration check passes:
$ sudo postfix reload
postfix/postfix-script: refreshing the Postfix mail system
Wording can differ, and a successful reload is not proof an outside host can actually deliver. Watch the mail log while making one controlled SMTP connection from a permitted test host:
$ sudo journalctl -u postfix --since '5 minutes ago' --no-pager
$ sudo postconf -h maillog_file 2>/dev/null
/var/log/mail.log
$ sudo tail -f /var/log/mail.log
Look for postscreen's decisions, the client address, and the hand-off to smtpd. Do not assume a DNSBL lookup or pre-greeting test has blocked anything while its action is still ignore. If nothing is listening, check ss -ltnp | grep ':25 ', the host firewall and the MX address before touching postscreen policy at all.
5. Add one controlled blocking policy
Do not switch on every test at once. Start with a DNS reputation policy only after choosing DNSBL providers, reading their usage rules, and deciding how you will handle false positives. The manual defines postscreen_dnsbl_action as the action taken once the combined score reaches the threshold, and its default is ignore. A typical policy has three deliberate parts:
postscreen_dnsbl_sites = YOUR_DNSBL_1*2, YOUR_DNSBL_2
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_action = enforce
YOUR_DNSBL_1 and YOUR_DNSBL_2 are placeholders, not real provider names: only fill in services you have actually selected and configured. Test the syntax with sudo postfix check, then reload with sudo postfix reload. Keep soft_bounce = yes as a temporary safety net only if you understand what it does: it turns rejections into temporary failures, and can leave senders retrying for days. Take it back out once testing is done.
For protocol tests, enable one feature at a time, such as postscreen_pipelining_enable = yes or postscreen_non_smtp_command_enable = yes, and pick its action explicitly. After-greeting tests can make a client reconnect from the same address before delivery, and they can interfere with clients that need AUTH, XCLIENT or XFORWARD. The manual specifically warns against enabling those tests on a port that must advertise those services.
6. Recover quickly if mail flow changes
If legitimate delivery gets delayed or rejected, return the action to ignore first, rather than deleting the cache or guessing at a DNSBL score:
$ sudo postconf -e 'postscreen_dnsbl_action = ignore'
$ sudo postfix check
$ sudo postfix reload
For a full service-level rollback, restore the saved master.cf, validate it, and reload:
$ sudo cp --preserve=all /etc/postfix/master.cf.before-postscreen /etc/postfix/master.cf
$ sudo postfix check
$ sudo postfix reload
Keep the cache while you investigate. It records temporary decisions, is normally stored at btree:$data_directory/postscreen_cache, and expires entries after seven days by default. Removing it is not a general fix, and it forces legitimate clients back through the tests again.
Done means
- Version and layout checked. Postfix 3.8.6 and the active service table confirmed before editing.
- Port 25 only. Postscreen sits in front of port 25; authenticated submission stays separate.
- Config validated every time.
postfix checkpasses before every reload. - Observation confirmed first. Mail log checked before any rejection action was switched on.
- DNSBL policy documented. Providers, scores and false-positive handling written down before enforcement.
- Rollback ready. A tested
master.cfbackup and an action-level rollback command both on hand.