Add newsletter send workflows (test pool + real pool)

scripts/send-newsletter.mjs sends newsletter/<issue>/index.html via the
Resend batch API (100/batch, paced under the 10 req/s team limit, retries
rate-limit 429s/5xx, idempotency keys so re-runs resume without dupes) to
the active subscribers of a pool fetched with the scoped send key.
Adds one-click List-Unsubscribe headers. Never logs subscriber emails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 17:34:56 -07:00
co-authored by Claude Opus 5.5
parent dd9ac9bb3f
commit 52fea0bf07
3 changed files with 166 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
name: "Newsletter: SEND to subscribers (pool apophenia)"
on:
workflow_dispatch:
inputs:
issue:
description: "Issue dir under newsletter/ (e.g. issue-2026.10.07). Sends to ALL subscribers."
required: true
type: string
permissions:
contents: read
# Never run two real sends at once
concurrency:
group: newsletter-send
cancel-in-progress: false
jobs:
send:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Send to pool "apophenia"
run: node scripts/send-newsletter.mjs
env:
ISSUE: ${{ inputs.issue }}
POOL: apophenia
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
NEWSLETTER_SEND_KEY: ${{ secrets.NEWSLETTER_SEND_KEY }}
NEWSLETTER_FROM: ${{ secrets.NEWSLETTER_FROM }}
+32
View File
@@ -0,0 +1,32 @@
name: "Newsletter: test send (pool test)"
on:
workflow_dispatch:
inputs:
issue:
description: "Issue dir under newsletter/ (e.g. issue-2026.10.07)"
required: true
type: string
permissions:
contents: read
jobs:
send:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Send to pool "test"
run: node scripts/send-newsletter.mjs
env:
ISSUE: ${{ inputs.issue }}
POOL: test
SUBJECT_PREFIX: "[TEST] "
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
NEWSLETTER_SEND_KEY: ${{ secrets.NEWSLETTER_SEND_KEY }}
NEWSLETTER_FROM: ${{ secrets.NEWSLETTER_FROM }}