Email delivery for mention notifications
Opened by stack72 · 4/20/2026
Summary
Follow-up to #127. The first cut of the mentions system delivers notifications only to the in-app inbox. This issue tracks the second channel: emailing the mentioned operative when they have a verified email and haven't opted out.
Prerequisites
- #127 merged and shipped. That issue establishes the
Notificationaggregate, the Mongo collection, and the write-path hooks that produce notification rows. This issue piggy-backs on those rows — it does not re-implement mention parsing or fan-out.
Desired behavior
When a Notification row is created for a recipient whose operative profile has emailMentions === true AND emailVerified === true, an email is sent via the existing Resend integration with a link back to the issue/comment. Self-mentions are already filtered out upstream by #127.
Scope suggestions
- Add an
emailMentions: booleanpreference toOperativeProfileData(defaulttrue). Expose in the profile editor with a labelled toggle. Decide whether to add a numbered migration undermigrations/or just default-on-read in the Operative entity when the stored doc lacks the field. - Add a
NotificationEmailQueue(new Mongo collection) with the same shape asevent_queue:status,nextAttemptAt,attempts, exponential backoff on failure. - Write-path: when
processMentionscreates a Notification row, enqueue an email job IFF the recipient hasemailMentions === trueAND a verified email. - Background watcher: mirror
startEventQueueWatcherin structure. Wire intostartBackgroundServices()inmain.ts(NOTimport.meta.main— see CLAUDE.md). Drain the queue, send via Resend, mark delivered or retry. - Email template:
content/emails/mention.mdwith{{actor_username}},{{issue_title}},{{issue_number}},{{excerpt}},{{cta_url}},{{cta_label}},{{settings_url}}. HTML-escape all user-controlled fields via the existingescapeHtmlinlib/email.ts. - Pin the public-facing origin for
cta_url/settings_url. BetterAuth'sBETTER_AUTH_URLmay or may not be the right source — Railway prod, keeb.dev, and docker-compose all differ. Fail loudly at send time if the env var is unset rather than sendinglocalhost:8000links to users.
Out of scope
- Mention notifications themselves (owned by #127)
- Digest emails (batch multiple mentions into one send)
- Email for non-mention notification kinds (future expansion)
Privacy
If the referenced issue is reclassified to security between enqueue and send, the worker must re-check canAccessIssue before sending. Notifications for issues the recipient can no longer access must be dropped, not delivered.
Why this matters
Many operatives only check their email, not the in-app inbox. Without the email channel, the mention system only closes the loop for people who happen to visit swamp.club between the mention and when they're in a hurry to respond.
Open
No activity in this phase yet.
Sign in to post a ripple.