The smtp_valid pool is only ~3k unsent — too small to sustain campaigns. SMTP probing can't confirm catch-all/mx_unreachable deliverability; only a REAL send can. burner_list_verify.py reconciles a verification send from a DISPOSABLE burner domain (isolated from PW/carrierone reputation): - hard bounce -> fmcsa_carriers.email_verify_result='hard_bounced' (excluded) - delivered -> 'send_confirmed' (proven deliverable; PW campaigns send to it) It tails the burner MTA mail.log (reuses bounce-watcher's status= pattern) and writes back idempotently. The PW trucking filter now treats smtp_valid + send_confirmed as sendable. docs/campaign-deliverability-plan.md captures the full diagnosis, the burner design, and CAN-SPAM guardrails. Remaining (needs a domain + isolated MTA identity — operator/infra decision): stand up the burner domain, the verification-send worker, and a writeback cron.
4.8 KiB
Campaign Deliverability — Diagnosis & List-Verification Plan
Created 2026-06-17 after trucking conversions went to zero.
TL;DR
Trucking conversions stopped on June 9 not because campaigns stopped sending
(they send ~2,400/day with ~1,800 opens/3 days) but because a filter bug was
blasting ~438k dead mx_unreachable domains, producing a ~47% hard-bounce
rate (~1,100/day) that blocklisted half the 120k subscriber base and
torched sender reputation, so real prospects never saw the offer.
- Fixed (
build_trucking_campaigns.py): send filter now keys only offemail_verify_result(never the brokenemail_verifiedboolean), and defaults to recovery mode =smtp_validonly until reputation recovers. SetCAMPAIGN_INCLUDE_CATCH_ALL=1to re-add catch-all domains afterward. - Healthcare is fine — separate instance (
listmonk-hc/ DBlistmonk_hc), cleaned list (clean_hc_warmup_list.pyalready dropsmx_unreachable), bounce rate ~2-3%. No change needed; it proves the fix is correct.
Why the SMTP-probe verification under-counts deliverable addresses
email_verifier.py does syntax → MX → SMTP RCPT TO. Results:
| result | count | sendable? | why |
|---|---|---|---|
catch_all_domain |
1,082,817 | risky | domain accepts ALL rcpts at SMTP time, then may bounce later |
mx_unreachable |
438,163 | NO | MX exists but never answered the probe — hard-bounces on real send |
smtp_valid |
11,774 | YES | an MX explicitly accepted this exact mailbox |
no_mx_records / invalid_syntax / smtp_rejected_550 |
~46k | no | dead |
The probe can only confirm a mailbox on non-catch-all domains that answer the
RCPT handshake — which is a small slice. Only ~3,042 smtp_valid are still
unsent, so recovery mode will exhaust the clean pool in ~1 day. We need a way
to grow the verified-deliverable list without burning PW's reputation.
The real fix: burner-domain bounce verification
SMTP-probe verification is unreliable (catch-alls mask validity; many MTAs refuse probes but accept real mail). The only ground truth is actually send a message and see if it bounces. But doing that from PW's domain is what got us here. So:
Design
-
Dedicated throwaway verification domain (NOT performancewest.net and NOT carrierone.com — both are reputation assets we must protect). Register a cheap neutral
.comvia Porkbun (we already have the Porkbun integration). Give it its own SPF/DKIM/DMARC and a dedicated sending IP/identity (separate postfix instance or a transactional provider sub-account that isolates reputation). -
Send a low-key, CAN-SPAM-compliant, non-commercial verification email to the unverified pool (e.g. a plain "is this the right contact for <DOT#>?" or a bland newsletter-style note with a working unsubscribe). It must be a real, legitimate message — never deceptive — but its ONLY purpose is to elicit a delivered-vs-bounced signal. Throttled and warmed like any send.
-
Catch bounces from that domain's own MTA log (reuse
bounce-watcher.sh'sstatus=bouncedtail pattern) and write the result back tofmcsa_carriers.email_verify_result:- delivered (no bounce within N hours) → upgrade to a new
send_confirmedresult that the PW campaign filter treats as sendable. - hard-bounced → mark
hard_bounced, permanently excluded from PW sends.
- delivered (no bounce within N hours) → upgrade to a new
-
PW campaigns then send only to
smtp_valid+send_confirmed— addresses proven deliverable by a real send — keeping PW's bounce rate near zero.
Why a separate domain/IP
Reputation is per sending-domain + per-IP. If the burner domain gets blocklisted from the inevitable bounces during scrubbing, PW and carrierone are untouched. The burner is disposable: if it burns, rotate to a new one. PW only ever sends to the cleaned output.
Compliance guardrails (must-haves)
- Real CAN-SPAM compliance: truthful from/subject, physical address, working one-click unsubscribe, honor opt-outs immediately (sync opt-outs back to PW's suppression list too).
- Not deceptive: the email is a genuine message (these are public FMCSA business contacts for B2B outreach), not a fake/pretext. The bounce signal is a byproduct, not a trick.
- Suppress anyone who ever bounced or opted out from ALL future sends (burner and PW).
Status / next steps
- Fix the PW trucking send filter (drop
mx_unreachable; recovery mode). - Confirm healthcare unaffected.
- Add
send_confirmed/hard_bouncedresult handling to the campaign filter + a writeback path from bounce processing. - Stand up the burner verification domain + isolated MTA identity.
- Build the verification-send + bounce-writeback worker.
- Re-verify the
catch_all_domain+mx_unreachablepools through the burner to grow the PW-sendable list.