# 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 off `email_verify_result` (never the broken `email_verified` boolean), and defaults to **recovery mode = `smtp_valid` only** until reputation recovers. Set `CAMPAIGN_INCLUDE_CATCH_ALL=1` to re-add catch-all domains afterward. - **Healthcare is fine** — separate instance (`listmonk-hc` / DB `listmonk_hc`), cleaned list (`clean_hc_warmup_list.py` already drops `mx_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 1. **Dedicated throwaway verification domain** (NOT performancewest.net and NOT carrierone.com — both are reputation assets we must protect). Register a cheap neutral `.com` via 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). 2. **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 ?" 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. 3. **Catch bounces from that domain's own MTA log** (reuse `bounce-watcher.sh`'s `status=bounced` tail pattern) and **write the result back to `fmcsa_carriers.email_verify_result`**: - delivered (no bounce within N hours) → upgrade to a new `send_confirmed` result that the PW campaign filter treats as sendable. - hard-bounced → mark `hard_bounced`, permanently excluded from PW sends. 4. **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 - [x] Fix the PW trucking send filter (drop `mx_unreachable`; recovery mode). - [x] Confirm healthcare unaffected. - [ ] Add `send_confirmed` / `hard_bounced` result 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_unreachable` pools through the burner to grow the PW-sendable list.