Improve deliverability with activated postscreen - #59
Open
chrisblech wants to merge 2 commits into
Open
Conversation
Without any reputation signal, postscreen forces every source IP it hasn't seen before through a mandatory temp-reject-then-retry cycle before handing off to smtpd (documented "PASS NEW" behavior), even when the client behaves perfectly. For senders with small, stable outbound IP pools this only costs one retry, cached for postscreen_cache_retention_time afterwards. For senders that spread retries across a large, frequently-rotating pool (M365, Google, ...) every attempt can look "new" again, causing repeated delivery delays. Score reputable senders from list.dnswl.org negative enough to clear postscreen_dnsbl_threshold, so postscreen fast-passes them straight to smtpd instead of forcing the retry. Re-adds the dnsblog(8) auxiliary service to master.cf (dropped in the postscreen PR since it deliberately skipped DNSBL/DNSWL scoring) - postscreen delegates all DNS-based lookups to it.
Contributor
Author
|
After running this in production for two days, I observed a significant reduction in spam volume. However, some legitimate emails were delivered with a substantial delay of up to 20 hours, despite the persistence of the postscreen cache and an active DNSBL whitelist. For this reason, I recommend disabling some of the filters again - see bfcc02e |
postscreen_bare_newline_enable, postscreen_non_smtp_command_enable and postscreen_pipelining_enable each unconditionally force postscreen's PASS_NEW temp-reject-then-reconnect cycle on every first-time client, regardless of whether that client actually violates the test - this is not tied to the *_action setting (confirmed empirically: even with action=ignore, merely enabling one of these three still forces the retry). Since the retry timing is entirely up to the sending MTA's own backoff schedule, this held up real deliveries by hours (observed: up to ~20h in production), and recurs for any correspondent postscreen hasn't already cached, not just as one-off "cold cache" cost. postscreen_greet_action (the PREGREET test) does not have this problem - confirmed locally that a clean client passes straight through with no forced reconnect when only greet_action + the DNSWL scoring from the previous commit are configured. PREGREET alone already caught 100% of the bot traffic observed in production logs (including a live exploit-scan attempt), so this keeps the protection that was actually earning its keep while dropping the tests that only imposed cost.
chrisblech
force-pushed
the
feature/postscreen-dnswl
branch
from
August 28, 2026 12:38
bfcc02e to
380ea6a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
After enabling postscreen (#55) on a production instance, we observed that mail from several large senders (e.g. Microsoft 365 / Outlook outbound) was either delayed by a significant margin or not delivered within a reasonable time at all.
The cause is postscreen's documented
PASS NEWbehavior: any client postscreen hasn't seen before is disconnected with a temporary450 4.3.2after passing the enabled tests, and only allowed straight through tosmtpdon a subsequent connection. For senders with a small, stable set of outbound IPs this costs one retry and is then cached forpostscreen_cache_retention_time. For senders that spread retries across a large, frequently-rotating IP pool, every attempt can look "new" to postscreen again, so the delay keeps recurring instead of resolving after the first retry.Change
Add
list.dnswl.orgas a reputation source inpostscreen_dnsbl_sites, weighted negative enough to clearpostscreen_dnsbl_threshold. Reputable senders (most large providers are listed) then get scored before the greeting and are passed straight tosmtpd, skipping the mandatory first-contact retry entirely. Unlisted/unknown clients are unaffected and keep going through the existing tests as before.This also re-adds the
dnsblog(8)service tomaster.cf, which PR #55 had dropped since it deliberately didn't use any DNSBL/DNSWL scoring —dnsblogis what postscreen delegates its DNS-based lookups to.Testing
Verified locally with a Docker build of this branch: a compliant test client still receives the standard
450+PASS NEWtreatment when unlisted (no regression), and the resolver correctly reacheslist.dnswl.organd evaluates the response against the configured weight patterns (confirmed viadnsbloglog output). The container's own healthcheck (loopback, covered bypermit_mynetworks) is unaffected and still gets an immediate banner.