legal: permanent do-not-contact for dataspindle.com + close re-import gap

David Sgro (PA OAG complaint BCP-26-05-025816) opted out 2026-04-13; response
emailed to the AG 2026-06-11. To make the suppression bulletproof and keep the
response's representations true:
- Added a legal do-not-contact list (DO_NOT_CONTACT_DOMAINS/_EMAILS) to
  _email_exclusions.py with dataspindle.com / dave@dataspindle.com; folded into
  BLOCKED_EMAIL_DOMAINS and is_blocked().
- listmonk_import.upsert_subscriber now refuses to import/re-confirm any
  suppressed address. This closes the exact gap that re-added him on 2026-04-26:
  the duplicate-import branch re-added an existing unsubscribed subscriber to
  lists with status=confirmed, overriding the opt-out.
This commit is contained in:
justin 2026-06-11 13:24:10 -05:00
parent 32623d36b8
commit 773c443079
3 changed files with 56 additions and 2 deletions

View file

@ -75,8 +75,27 @@ def api_post(path: str, payload: dict, session: requests.Session) -> Optional[di
def upsert_subscriber(email: str, name: str, lists: list[int],
attribs: dict, session: requests.Session) -> Optional[int]:
"""Create or update a Listmonk subscriber. Returns subscriber ID or None."""
clean = (email or "").lower().strip()
# Do-not-contact / legal suppression gate. NEVER (re-)import or re-confirm a
# suppressed address. This is the guard that was missing when a duplicate
# import re-added a previously-unsubscribed contact to lists with
# status="confirmed" (the David Sgro / dataspindle.com case). is_blocked
# covers both consumer-domain reputation blocks and the legal do-not-contact
# list in scripts/_email_exclusions.py.
try:
from scripts._email_exclusions import is_blocked
except Exception:
try:
from _email_exclusions import is_blocked # type: ignore
except Exception:
is_blocked = lambda _e: False # noqa: E731 (fail-open only if module missing)
if is_blocked(clean):
LOG.info("Skipping suppressed/do-not-contact address: %s", clean)
return None
payload = {
"email": email.lower().strip(),
"email": clean,
"name": (name or "").strip() or email.split("@")[0],
"status": "enabled",
"lists": lists,