managarten/services/mana-mail
Till JS a312d98f09 feat(broadcast): click-link tracking + send throttle
Closes the last two dogfood blockers before real-campaign use.

link-rewriter.ts
- rewriteClickLinks(): walks <a href="http…"> in the HTML body and
  replaces each URL with /api/v1/track/click/{token}?url={original}
  so clicks go through the tracking endpoint. Regex-based because
  Tiptap output is well-formed; returns a count for debugging.
- Leaves mailto: / tel: / anchor fragments alone — wrapping those
  breaks the recipient's native handler and accomplishes nothing.
- `skipUrls` param carries the unsubscribe + web-view URLs (already
  tracking endpoints themselves) so they don't get double-wrapped.
- 11 unit tests covering http/https rewriting, skip list, non-http
  schemes, attribute preservation, multi-link count, quoted-attr
  variants, idempotency.

Orchestrator wiring
- substituteUrls now calls rewriteClickLinks after the preview-
  placeholder swap and before the open-pixel injection. The
  unsubscribe + web-view URLs from this same function are passed
  in as skip entries so they survive the pass untouched.
- Constructor gains `sendThrottleMs` param (default 150ms).
- Main send loop awaits sleep(throttleMs) between iterations. 150ms
  = ~6/sec = ~360/min, safely below most SMTP provider limits.
  100-recipient campaign = ~15s extra wall-clock but that's fine
  for MVP (and most campaigns are way smaller).

Config
- New env BROADCAST_SEND_THROTTLE_MS (default 150). Wired from
  loadConfig to the orchestrator constructor.

The broadcast module is now functionally complete for dogfooding.
Remaining before a real campaign can actually go out: run
`cd services/mana-mail && bun run db:push` to materialise the
broadcast.* schema tables.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 15:07:58 +02:00
..
src feat(broadcast): click-link tracking + send throttle 2026-04-21 15:07:58 +02:00
CLAUDE.md feat(mail): add mana-mail service and frontend module (Phase 1 MVP) 2026-04-13 20:35:54 +02:00
Dockerfile feat(mail): add mana-mail service and frontend module (Phase 1 MVP) 2026-04-13 20:35:54 +02:00
drizzle.config.ts feat(mail): add mana-mail service and frontend module (Phase 1 MVP) 2026-04-13 20:35:54 +02:00
package.json feat(broadcast): M4 bulk-send via mana-mail + tracking infrastructure 2026-04-21 13:53:13 +02:00
tsconfig.json feat(mail): add mana-mail service and frontend module (Phase 1 MVP) 2026-04-13 20:35:54 +02:00