newsletter rollout: target smtp_valid only (was 34% bounce on all-enabled)

First rollout (2026-06-28) targeted ALL enabled trucking subs and hit a 34%
bounce rate: ~80% of 'enabled' are catch_all_domain (accept MX probe, bounce at
the real mailbox). Now joins pw_smtp_valid_stage (verified smtp_valid pool, same
as the drip) and excludes lists 563/564 (already-mailed by the aborted run).
Default batches 14->5 for the smaller ~7.9k clean pool. Engagement on the clean
deliveries was strong (30% open, 28% click-of-openers), so content stays.
This commit is contained in:
justin 2026-06-29 10:12:55 -05:00
parent 141ecd7ff9
commit 329ef398cb

View file

@ -43,10 +43,24 @@ from scripts.workers.campaign_helpers import LISTMONK_URL, AUTH # noqa: E402
# ── Config ───────────────────────────────────────────────────────────────────
SOURCE_DRAFT_ID = int(os.getenv("FUELTAX_SOURCE_DRAFT", "750"))
N_BATCHES = int(os.getenv("FUELTAX_BATCHES", "14")) # one per day
# The SQL predicate that defines the whole warm audience. Each batch ANDs an
N_BATCHES = int(os.getenv("FUELTAX_BATCHES", "5")) # one per day
# The SQL predicate that defines the whole CLEAN audience. Each batch ANDs an
# id-modulo slice onto this so the union == the whole audience, no overlaps.
AUDIENCE_SQL = "subscribers.attribs ? 'dot_number' AND subscribers.status = 'enabled'"
#
# IMPORTANT: only smtp_valid (verified real mailbox) carriers. The first attempt
# (2026-06-28) targeted ALL enabled trucking subs and hit a 34% bounce rate
# because ~80% are catch_all_domain addresses (accept the MX probe, bounce at the
# real mailbox). pw_smtp_valid_stage is a staging table in the listmonk DB holding
# the lowercased smtp_valid/send_confirmed emails from fmcsa_carriers; joining to
# it restricts the audience to the same clean pool the sales drip uses.
AUDIENCE_SQL = (
"subscribers.attribs ? 'dot_number' AND subscribers.status = 'enabled' "
"AND EXISTS (SELECT 1 FROM pw_smtp_valid_stage v WHERE v.email = lower(subscribers.email)) "
# Exclude anyone already mailed by the first (aborted) rollout: list 563 (batch
# 1, fully sent) and 564 (batch 2, partially sent). Skipping the few hundred in
# 564 who didn't actually receive it is the safe tradeoff vs. a double-send.
"AND NOT EXISTS (SELECT 1 FROM subscriber_lists sl WHERE sl.subscriber_id = subscribers.id AND sl.list_id IN (563, 564))"
)
# First send day (default: tomorrow). Sent at SEND_HOUR_UTC each day.
SEND_HOUR_UTC = int(os.getenv("FUELTAX_SEND_HOUR_UTC", "14")) # 14:00 UTC = 9am CT
LIST_TAGS = ["trucking", "newsletter", "fueltax", "auto"]