Skip to content

Replace MailerSend template sprawl with a repo-owned render endpoint - #1065

Draft
hturnbull93 wants to merge 1 commit into
PauseAI:mainfrom
hturnbull93:feat/onboarding-email-render-endpoint
Draft

Replace MailerSend template sprawl with a repo-owned render endpoint#1065
hturnbull93 wants to merge 1 commit into
PauseAI:mainfrom
hturnbull93:feat/onboarding-email-render-endpoint

Conversation

@hturnbull93

Copy link
Copy Markdown
Collaborator

Summary

Replaces the 7 hand-authored MailerSend templates driven by airtable-mailersend-emails.js with a repo-owned render endpoint, matrixed on intent × chapter × language instead of one template ID per combination. Chapter content (leader, links) now comes live from the same Airtable "National Groups" data /api/national-groups already uses, instead of being hand-copied per template and drifting out of date.

  • src/lib/server/onboardingEmail/ — chapter lookup, intent copy (act-now / keep-informed / volunteer / lead), language handling (en/es/fr), HTML + plain-text renderers
  • src/routes/api/onboarding-email — bearer-secret POST endpoint, returns {subject, html, text}. Render-only — never sends mail itself, never touches the MailerSend API key.
  • src/routes/api/unsubscribe — new. No unsubscribe mechanism existed in any of the 7 templates before this (MailerSend's unsubscribe_rate: 0 reflected "no link offered," not "no one wants out"). Flips the Members Email subscription checkbox and suppresses on both MailerSend domains.
  • src/routes/onboarding-email-preview — dev-only QA page (404s outside dev), renders a sample of intent × chapter × language combos.
  • airtable-mailersend-emails.js — tries the new endpoint first; on any failure (network error, timeout, non-OK response, missing fields) falls through to the original template_id logic, byte-for-byte unchanged. Worst case is today's behavior.
  • email-templates/ — raw MailerSend payloads for all 7 old templates, kept as migration reference and to document routing gaps found along the way (CANADA_FR_TEMPLATE was unreachable in practice — languages is always empty at send time; Lead intent normally hands off via a mailto: link rather than a form submission, per docs/join-form-flow.md).

Please manually check / review / adjust

  • Spanish copy is newly written, not adapted from anything reviewed — no es locale exists elsewhere in the codebase, and the old Spanish template only ever covered the volunteer case. Needs a native/fluent Spanish speaker from the org to read it.
  • French register: the join form's French (messages.ts) uses informal tu; the old Canada-FR MailerSend template used formal vous. Matched vous to stay consistent with the reviewed body copy — meaning the email doesn't literally echo the join form's wording. Confirm that's the right call.
  • Subject line no longer includes the chapter name (previously e.g. "Welcome to PauseAI UK {{first_name}}!") — check /onboarding-email-preview and confirm the new subject is acceptable.
  • Visual simplification: no logo/wordmark image, social/community links render as plain text rather than icons (deliberate — avoids broken-image risk in email clients, but is a visual downgrade from the old templates). Confirm OK for v1.
  • Bluesky link is hardcoded (confirmed global across every old template, including UK's — no per-chapter Bluesky field exists on NationalGroup/Airtable).
  • Actually load /onboarding-email-preview locally and look at real rendered output — only agent/automated smoke-testing has happened so far, no human has eyeballed it.

Pre-merge / pre-launch checklist

  • Set real values for ONBOARDING_EMAIL_RENDER_SECRET and MAILERSEND_API_KEY in prod (Netlify env vars) — both currently placeholder-only in .env (gitignored, no real values committed).
  • Map the same shared secret (name it exactly Onboarding email render secret) and the optional render_endpoint_url override in the Airtable automation's script input config panel — the script references these by name but Airtable-side mapping isn't part of this repo.
  • Confirm with MailerSend support whether raw (non-template_id) sends get any automatic unsubscribe-footer/compliance injection. Docs suggest that's template-engine-only, so the shell here builds its own unsubscribe link + physical address (Box C5957, Kwikstaartlaan 42, 3704GS Zeist, The Netherlands) — never got a definitive answer from MailerSend, worth chasing before this goes live.
  • Trigger one real test send through the Airtable automation once deployed, to confirm the full path end-to-end (not just the isolated endpoint checks done so far).
  • Once confident in the new path, consider whether/when to retire the 7 old MailerSend templates (kept live for now as the fallback).

🤖 Generated with Claude Code

https://claude.ai/code/session_01GtQwhn5Fb9eiC4LsmRs47q

Airtable's onboarding automation sent every welcome email via one of 7
hand-authored MailerSend templates, hardcoding chapter links/leaders that
already drift from the live National Groups data, and only distinguishing
volunteer vs non-volunteer recipients. Adds a render endpoint that composes
subject/html/text from live chapter data, the recipient's actual intent
(act-now/keep-informed/volunteer/lead), and language - so new chapters and
languages no longer need a new MailerSend template + script branch.

- src/lib/server/onboardingEmail/ - chapter lookup (reuses the National
  Groups fetch), intent/language copy, HTML + plain-text renderers
- src/routes/api/onboarding-email - bearer-secret POST endpoint returning
  {subject, html, text}; render-only, never sends mail itself
- src/routes/api/unsubscribe - suppresses on both MailerSend domains and
  flips the Members "Email subscription" checkbox; no unsubscribe
  mechanism existed in any of the 7 templates before this
- src/routes/onboarding-email-preview - dev-only QA page, 404s outside dev
- airtable-mailersend-emails.js - tries the new endpoint first, falls
  through to the untouched template_id logic on any failure
- email-templates/ - raw MailerSend payloads for all 7 templates, kept as
  migration reference and to document the old routing gaps (Canada-FR was
  unreachable in practice; Lead hands off via mailto instead of a form
  submission)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GtQwhn5Fb9eiC4LsmRs47q
@netlify

netlify Bot commented Aug 25, 2026

Copy link
Copy Markdown

👷 Deploy request for pauseai pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 59bbca3

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