fix(campaigns): stop sending trucking blasts to mx_unreachable dead domains

Root cause of zero conversions since Jun 9 + the Gmail/Outlook block storm:
the send filter was '(email_verified IS TRUE OR result IN ...)'. The verifier
sets email_verified=TRUE optimistically for mx_unreachable (domain exists but
its mail server never answered the RCPT probe) — 438,163 such rows. Those HARD
BOUNCE on send, producing ~1,100 bounces/day (~47% rate) and blocklisting half
the 120k subscriber base, so real prospects never saw the offer.

Fix: key the send filter ONLY off email_verify_result, never the broken boolean.
Recovery mode (default): send only 'smtp_valid' to drive bounce rate to ~0 and
rebuild reputation; set CAMPAIGN_INCLUDE_CATCH_ALL=1 to re-add catch-all domains
once recovered. Mirrors the healthcare list-cleaning approach (HC bounces ~2-3%,
which proves the fix). Note: only ~3k smtp_valid unsent remain — list growth via
real-send bounce verification (separate burner domain) is the follow-up.
This commit is contained in:
justin 2026-06-16 22:24:15 -05:00
parent 35f204c2b8
commit 1652a3b8bc

View file

@ -331,9 +331,25 @@ TEST_EMAIL = os.getenv("CAMPAIGN_TEST_EMAIL", "carrierone@gmx.com")
REPLY_TO_EMAIL = os.getenv("CAMPAIGN_REPLY_TO", "info@performancewest.net") REPLY_TO_EMAIL = os.getenv("CAMPAIGN_REPLY_TO", "info@performancewest.net")
REPLY_TO_HEADERS = [{"name": "Reply-To", "value": REPLY_TO_EMAIL}] REPLY_TO_HEADERS = [{"name": "Reply-To", "value": REPLY_TO_EMAIL}]
# Which verification results are safe to SEND to. We key ONLY off
# email_verify_result, never the email_verified boolean: the verifier sets
# email_verified=TRUE optimistically for 'mx_unreachable' (domain exists but its
# mail server didn't answer the probe) — those addresses HARD-BOUNCE when we
# actually send, which is what tanked deliverability (≈47% bounce, half the list
# blocklisted). So 'mx_unreachable' and all error/reject results are excluded.
#
# Recovery mode (default ON while reputation is damaged): send ONLY 'smtp_valid'
# — addresses an MX explicitly accepted at RCPT time — to drive the bounce rate
# to near-zero and rebuild sender reputation. Once recovered, set
# CAMPAIGN_INCLUDE_CATCH_ALL=1 to re-add catch-all domains (which accept at SMTP
# time but can still bounce later, so they stay out during recovery).
_SENDABLE_RESULTS = ["smtp_valid"]
if os.getenv("CAMPAIGN_INCLUDE_CATCH_ALL", "0") not in ("0", "false", ""):
_SENDABLE_RESULTS += ["catch_all_domain", "catch_all_detected"]
USABLE_FILTER = ( USABLE_FILTER = (
"(email_verified IS TRUE OR email_verify_result IN " "email_verify_result IN ("
"('smtp_valid','catch_all_domain','catch_all_detected'))" + ", ".join(f"'{r}'" for r in _SENDABLE_RESULTS)
+ ")"
) )
DB_URL = os.getenv("DATABASE_URL", "") DB_URL = os.getenv("DATABASE_URL", "")