Ops — Email (Resend)
Transactional email runs through Resend from `lib/email/client.ts`. All notification emails are sent server-side from API routes using React Email templates.
Transactional email runs through Resend from lib/email/client.ts.
All notification emails are sent server-side from API routes using React
Email templates.
The sender
notifications@mail.greenbook.legal— verified Resend domain (verified 2026-08-06, pass 11). This supersedes the BUILD-SPEC §7.4guild.appplaceholder, which is not a registered/verified domain.- Free-tier cap: ~100 emails/day (Resend free tier). The platform sends at most one email per notification event (7 event types), so this is ample for the MVP — but a seed script or demo loop that proposes many matches will exhaust the daily budget. Watch the Resend dashboard if emails suddenly stop.
What sends what (7 triggers, 7 templates)
| Trigger | Template | Recipient |
|---|---|---|
POST /api/matches (match proposed) | match-proposed | the practitioner receiving the proposal |
PATCH /api/matches/[id] → accepted | match-accepted | the proposer |
PATCH /api/matches/[id] → declined | match-declined | the proposer |
POST /api/messages | new-message | the other participant in the match |
POST /api/referrals | referral-proposed | the referral recipient |
PATCH /api/referrals/[id] → accepted | referral-accepted | the referral sender |
POST /api/bids | bid-approval-needed | the case owner |
Templates live in lib/email/templates/; styles.ts is the shared layout.
tests/email-render.test.ts verifies all templates render.
How sending works
// lib/email/client.ts — constructed lazily so the app builds without a key
await sendEmail(to, subject, <Template />);
Key properties:
- No-op safe. Without
RESEND_API_KEY,sendEmaillogs a warning and returns — the app builds and runs with no email configured (pass-11 verified the silent no-op path). - Fail-soft. A Resend error logs
Failed to send emailand does not fail the request — a 500 from an email provider never fails the API call that triggered it. appUrl(path)builds absolute links fromNEXT_PUBLIC_APP_URL(local:http://localhost:3000; prod:https://guild.pages.dev).
Debugging
- Emails missing? Check the Resend dashboard for send status, then confirm
RESEND_API_KEYis set in the environment that actually ran the request (.env.localfor dev, Cloudflare Pages dashboard for prod) and that the daily cap isn't exhausted. - Test receipts: pass-11 used reserved-domain addresses (e.g.
test-pass10-b@example.com— no MX, harmless). - Domain change (pass 13, optional): verify the new domain in Resend and
update the
fromaddress inlib/email/client.ts.