Skip to content

Mail safety: internal-domain exclusion in reactivation + active-dev outreach script - #111

Merged
Deesmo merged 1 commit into
mainfrom
mail-safety-internal-exclusion
Jul 31, 2026
Merged

Mail safety: internal-domain exclusion in reactivation + active-dev outreach script#111
Deesmo merged 1 commit into
mainfrom
mail-safety-internal-exclusion

Conversation

@Deesmo

@Deesmo Deesmo commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Why

The 2026-07-31 reactivation dry-run (Render job job-d9mcdd6gekts7389tcb0) reported eligible=183 with the first 10 recipients ALL internal @archtools.dev aliases (lucius*/brad*/mc*). Verified live: Cloudflare Email Routing for archtools.dev forwards ONLY abuse@/security@/privacy@/support@ and the catch-all is DISABLED — so marketing sends to those aliases hard-bounce at SMTP and burn Resend sender reputation.

Change 1 — api/src/scripts/reactivationEmail.ts: internal-domain exclusion

  • New env EXCLUDE_EMAIL_DOMAINS (comma-separated, default archtools.dev; explicit "" disables). Matching recipients are skipped entirely — no email, no top-up (exclusion runs before SEND_LIMIT slicing and top-up selection).
  • Dry-run output now includes a per-domain recipient histogram (e.g. gmail.com: 57) and an "Excluded as internal: N" line; the summary JSON gains excludedInternal + excludeDomains.
  • Existing safety model untouched (CONFIRM_SEND, BUSINESS_ADDRESS, SEND_LIMIT, RFC 8058 headers, live opt-out recheck).
  • ⚠️ Copy strings deliberately untouched — a parallel in-flight PR owns the copy (chain claims); this PR only touches selection/reporting logic to avoid conflicts.

Change 2 — new api/src/scripts/outreachActiveDevs.ts

Personal-ask email to the ~13-15 developers with real API activity in the last 30 days.

  • Selection: ApiRequest rows with status="SUCCESS" grouped by agentId (the exact pattern funnelReport.ts uses for its "made ≥1 successful call" stage), bounded to ACTIVE_WINDOW_DAYS (default 30, within the 90-day ApiRequest retention window), MIN_CALLS default 1. Internal/seed/self accounts are removed by the same EXCLUDE_EMAIL_DOMAINS filter (internal traffic = the @archtools.dev aliases; funnelReport has no separate seed flag).
  • Safety model mirrors reactivationEmail.ts exactly: DRY-RUN by default; CONFIRM_SEND=YES + real BUSINESS_ADDRESS required to send; SEND_LIMIT; RFC 8058 one-click unsubscribe via signUnsubscribeToken + List-Unsubscribe headers; sendMarketingEmail; emailVerified/emailOptOut filters with live opt-out recheck per send; isMainModule guard.
  • Copy: plain + short, subject "Quick question from the Arch Tools builder", signed Brad, minimal HTML + text. Payment-chain claim is USDC on Base or Polygon ONLY — a test asserts no other chain names appear.
  • Never runs without Brad's explicit GO (dry-run default; documented in header).

Tests / verification

  • api/tests/reactivation-render.test.mjs: +5 cases for parseExcludeDomains / emailDomain (default, parsing, explicit-disable, case-insensitivity, internal-alias matching). It renders copy but asserts none of the parallel-PR copy strings changed here.
  • New api/tests/outreach-active-devs.test.mjs: CAN-SPAM elements, personal ask, MCP URL, honest-claims guard (Base+Polygon only), personalization, HTML escaping. Wired into npm test.
  • Verified locally in the worktree: npx tsc --noEmit → clean; both test files pass (25 + 17 assertions).
  • Tracked api/dist / api/node_modules deliberately not committed (build churn reverted).

🤖 Generated with Claude Code


Note

Medium Risk
Touches production marketing scripts that query agents, may top up credits, and send bulk email when CONFIRM_SEND=YES; logic is dry-run by default and adds exclusion rather than widening sends.

Overview
Adds internal-domain exclusion to marketing one-off scripts so @archtools.dev aliases (and other configured domains) are never emailed or topped up—addressing dry-run findings that internal addresses would hard-bounce and hurt Resend reputation.

reactivationEmail.ts gains EXCLUDE_EMAIL_DOMAINS (default archtools.dev), shared helpers (parseExcludeDomains, emailDomain, exported escapeHtml/maskEmail), filtering before SEND_LIMIT and credit top-ups, plus dry-run per-domain histogram and excludedInternal in JSON logs.

New outreachActiveDevs.ts targets verified, non–opted-out agents with successful API calls in a configurable window (funnelReport-style ApiRequest grouping), reuses the same exclusion and CAN-SPAM/send safeguards (dry-run default, live opt-out recheck, List-Unsubscribe). Copy is a short personal ask from Brad; payment claims limited to USDC on Base/Polygon.

Tests: domain-exclusion cases in reactivation-render.test.mjs, new outreach-active-devs.test.mjs (CAN-SPAM, honest chain claims, HTML escape), wired into npm test.

Reviewed by Cursor Bugbot for commit 64e63a2. Configure here.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

CHANGE 1 — reactivationEmail.ts internal-domain exclusion:
The 2026-07-31 dry-run (Render job job-d9mcdd6gekts7389tcb0) showed
eligible=183 with the first 10 recipients ALL internal @archtools.dev
aliases. Cloudflare Email Routing for archtools.dev forwards only
abuse@/security@/privacy@/support@ and the catch-all is DISABLED, so
marketing sends to those aliases hard-bounce at SMTP and damage Resend
sender reputation.
- New env EXCLUDE_EMAIL_DOMAINS (comma-separated, default archtools.dev);
  matching recipients are skipped entirely — no email, no top-up
  (exclusion runs before SEND_LIMIT slicing and top-up selection).
- Dry-run now prints a per-domain recipient histogram plus the count
  excluded as internal; summary JSON gains excludedInternal/excludeDomains.
- Copy strings untouched (a parallel PR owns them); existing safety model
  (CONFIRM_SEND, BUSINESS_ADDRESS, SEND_LIMIT) unchanged.

CHANGE 2 — new outreachActiveDevs.ts:
Personal-ask email to developers with real API activity in the last 30
days (ApiRequest SUCCESS rows grouped by agentId — funnelReport's
stage-2 pattern, time-bounded). Mirrors the reactivation safety model
exactly: dry-run by default, CONFIRM_SEND=YES + BUSINESS_ADDRESS gates,
SEND_LIMIT, RFC 8058 one-click unsubscribe, live opt-out recheck,
emailVerified/emailOptOut filters, EXCLUDE_EMAIL_DOMAINS. Copy claims
USDC on Base or Polygon ONLY (the only live chains) — enforced by test.

Tests: exclusion-helper cases added to reactivation-render.test.mjs;
new outreach-active-devs.test.mjs (render + honest-claims guard);
both wired into npm test. Verified: npx tsc --noEmit clean; both test
files pass. dist/node_modules churn deliberately not committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Deesmo
Deesmo force-pushed the mail-safety-internal-exclusion branch from 64e63a2 to a1f51a5 Compare July 31, 2026 16:47
@Deesmo
Deesmo merged commit 15150b1 into main Jul 31, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant