From 344300ebd42e86c4fbc4fb38e82a1e9ad988c993 Mon Sep 17 00:00:00 2001 From: justin Date: Tue, 2 Jun 2026 12:14:43 -0500 Subject: [PATCH] campaigns: exclude full Yahoo/Verizon-Media domain family from cold email Yahoo operates a large family of consumer domains (AOL, AT&T, Verizon, Frontier, sbcglobal, bellsouth, etc.) that aggressively defer cold senders with 421 'unexpected volume / user complaints', which poisons our self-hosted sending IP for every other provider. Previously we only excluded aol.com/yahoo.com/ymail.com/rocketmail.com. Centralize the authoritative block list in scripts/_email_exclusions.py and import it from both audience builders so they stay in sync. --- scripts/_email_exclusions.py | 45 +++++++++++++++++++ scripts/build_trucking_campaigns.py | 9 +--- .../populate_new_carrier_startup_campaign.py | 3 +- 3 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 scripts/_email_exclusions.py diff --git a/scripts/_email_exclusions.py b/scripts/_email_exclusions.py new file mode 100644 index 0000000..85ee257 --- /dev/null +++ b/scripts/_email_exclusions.py @@ -0,0 +1,45 @@ +"""Shared recipient-domain exclusions for outbound cold-email campaigns. + +We self-host our MTA (transactional relays like SES forbid cold email), so we +must protect our sending-IP reputation manually. The single biggest lever is +NOT mailing the Yahoo/Verizon-Media family: those providers aggressively defer +cold senders with "unexpected volume / user complaints" 421 responses, which +poisons the IP for every other provider too. + +Keep this list authoritative and import it everywhere we build audiences. +""" + +from __future__ import annotations + +# Yahoo / Verizon Media operates ALL of these consumer domains. Legacy AT&T and +# Frontier consumer mail was handed off to Yahoo's infrastructure as well. +YAHOO_FAMILY_DOMAINS: frozenset[str] = frozenset({ + # Yahoo / AOL core + "yahoo.com", "yahoo.com.mx", "yahoo.es", "yahoo.it", "yahoo.ca", + "myyahoo.com", "ymail.com", "rocketmail.com", + "aol.com", "aol.com.mx", "aim.com", "love.com", "games.com", "wow.com", + "netscape.net", "netscape.com", "cs.com", "compuserve.com", + # AT&T family (Yahoo-hosted) + "att.net", "sbcglobal.net", "bellsouth.net", "pacbell.net", + "ameritech.net", "swbell.net", "snet.net", "flash.net", "prodigy.net", + "wans.net", "nvbell.net", + # Verizon family (Yahoo-hosted) + "verizon.net", "verizongni.com", "bellatlantic.net", + # Frontier (Yahoo-hosted) + "frontier.com", "frontiernet.net", +}) + +# The full set of consumer domains we refuse to cold-mail. Extend here as we +# discover other reputation-sensitive providers. +BLOCKED_EMAIL_DOMAINS: frozenset[str] = YAHOO_FAMILY_DOMAINS + + +def domain_of(email: str) -> str: + """Return the lowercased domain part of an email, or '' if malformed.""" + if "@" not in email: + return "" + return email.rsplit("@", 1)[-1].strip().lower() + + +def is_blocked(email: str) -> bool: + return domain_of(email) in BLOCKED_EMAIL_DOMAINS diff --git a/scripts/build_trucking_campaigns.py b/scripts/build_trucking_campaigns.py index 782e7a9..1a07df7 100644 --- a/scripts/build_trucking_campaigns.py +++ b/scripts/build_trucking_campaigns.py @@ -31,6 +31,8 @@ from datetime import date, datetime, timedelta, timezone import psycopg2 +from scripts._email_exclusions import BLOCKED_EMAIL_DOMAINS + LOG = logging.getLogger("build_trucking_campaigns") # ── Listmonk ────────────────────────────────────────────────────────────────── @@ -155,13 +157,6 @@ USABLE_FILTER = ( "('smtp_valid','catch_all_domain','catch_all_detected'))" ) -BLOCKED_EMAIL_DOMAINS = ( - "aol.com", - "yahoo.com", - "ymail.com", - "rocketmail.com", -) - DB_URL = os.getenv("DATABASE_URL", "") diff --git a/scripts/populate_new_carrier_startup_campaign.py b/scripts/populate_new_carrier_startup_campaign.py index 640e0d0..9727990 100644 --- a/scripts/populate_new_carrier_startup_campaign.py +++ b/scripts/populate_new_carrier_startup_campaign.py @@ -31,6 +31,8 @@ from typing import Any import psycopg2 import psycopg2.extras +from scripts._email_exclusions import BLOCKED_EMAIL_DOMAINS + LOG = logging.getLogger("populate_new_carrier_startup_campaign") LISTMONK_URL = os.getenv("LISTMONK_URL", "https://lists.performancewest.net").rstrip("/") @@ -39,7 +41,6 @@ LISTMONK_PASS = os.getenv("LISTMONK_PASS", "6X1rKPea61N4rZ1S65Hx5zvqzbCj30F6nvEe LIST_NAME = os.getenv("NEW_CARRIER_LIST_NAME", "FMCSA Trucking - New Carrier Missing Startup Items") DATABASE_URL = os.getenv("DATABASE_URL", "") -BLOCKED_EMAIL_DOMAINS = {"aol.com", "yahoo.com", "ymail.com", "rocketmail.com"} STARTUP_SERVICE_SLUGS = { "boc3-filing", "ucr-registration",