Resend Integration
Knowledge > Integrations > Resend
What it is / why we use it
Resend is the transactional email provider for all three ChurchWiseAI properties. It handles every system-triggered email: magic links, welcome emails, payment failure alerts, trial ending reminders, ops alerts (WatchTower), and contact form notifications. Unlike MailerLite (which handles marketing and subscriber management), Resend is for one-to-one triggered emails. Each property uses Resend directly with its own RESEND_API_KEY env var. Email templates are inline HTML — no React Email or external template service. All templates follow the ChurchWiseAI brand: navy header gradient, cream background, Sacred Gold CTAs.
Account Info
- Platform: Resend (resend.com)
- Account: churchwiseai@gmail.com (assumed; same primary account)
- Key location:
RESEND_API_KEYenv var in all three codebases - Agent access: Full API access via the
resendnpm package. Verify delivery by checking Resend dashboard logs or querying email logs if stored.
Sender Addresses By Property
| Property | From Address | Used For |
|---|---|---|
| ChurchWiseAI | hello@churchwiseai.com | Welcome emails, magic links, trial reminders, payment failed, contact confirmations |
| ChurchWiseAI (WatchTower) | hello@churchwiseai.com (display: WatchTower) | P0 operational alerts to founder |
| PewSearch | hello@pewsearch.com | Magic links, premium welcome, claim notifications, contact form forwarding |
| IllustrateTheWord | hello@illustratetheword.com | Account emails, subscription notifications |
| ShareWiseAI | hello@churchwiseai.com | Social post notifications (Coming Soon; shared sender) |
Email Types Per Product
ChurchWiseAI (churchwiseai-web/src/lib/email.ts)
| Function | Subject Pattern | Trigger |
|---|---|---|
sendPremiumWelcomeEmail | "Your ChurchWiseAI dashboard is ready — {church}" | Stripe checkout completed, or onboard provision |
sendPaymentFailedEmail | "Payment Failed — Action Required" | Stripe invoice.payment_failed |
sendTrialEndingEmail | "Your ChurchWiseAI Trial Ends Soon" | Cron (daily audit) near trial end |
sendVoiceSetupAlertEmail | Voice setup notification | New voice/bundle subscription (internal alert to founder) |
sendStarterKitDeliveryEmail | Starter Kit delivery | One-time Starter Kit purchase |
WatchTower alerts (/api/ops/alert/route.ts):
- Subject:
[WatchTower P0] {source} — {message} - Sent to:
ALERT_EMAILenv var (defaults tosupport@churchwiseai.com) - Triggered by the ops collection cron when a P0 error is detected
Magic link resend (/api/onboard/resend-link/route.ts):
- Same
sendPremiumWelcomeEmailtemplate - Rate limited to 3/hour per IP
- Returns 200 regardless of whether the email exists (prevents enumeration)
PewSearch (pewsearch/web/src/lib/email.ts, notifications.ts)
| Use | Trigger |
|---|---|
| Magic link / dashboard access | Admin token lookup request |
| Premium welcome | PewSearch checkout completed |
| Contact form forwarding | Church website contact form submission (Pro Website feature) |
| Claim notification | New church claim submitted |
| Care broadcast | Pro Website care messaging (sent as {church} via PewSearch) |
IllustrateTheWord (sermon-illustrations/src/lib/email.ts)
| Use | Trigger |
|---|---|
| Welcome / account confirmation | Supabase Auth signup |
| Subscription notification | Stripe ITW Premium checkout |
Key Environment Variables
| Variable | Used In | Purpose |
|---|---|---|
RESEND_API_KEY | All three codebases | Bearer token for Resend API |
ALERT_EMAIL | churchwiseai-web | Destination for WatchTower P0 alerts (defaults to support@churchwiseai.com) |
NEXT_PUBLIC_SITE_URL | churchwiseai-web | Base URL for magic links (defaults to https://churchwiseai.com) |
CLI / API Patterns & Gotchas
Lazy singleton pattern: All three codebases use a lazy singleton for the Resend client to avoid instantiating it outside request scope:
let _resend: Resend | null = null;
function getResend(): Resend {
if (!_resend) _resend = new Resend(process.env.RESEND_API_KEY!);
return _resend;
}
This is safe for Vercel serverless (each invocation reuses the module-level instance within the same warm container).
Magic link format:
CWA magic links use the pattern /auth/magic?t={encoded_token} to set an HttpOnly cookie rather than exposing the admin token in the URL bar. Do not change this pattern without updating the auth flow.
Inline HTML templates only:
No React Email, no MJML, no external template service. All templates are inline HTML strings in email.ts. Pros: simple, no build step, no import issues. Cons: editing is verbose. When modifying templates, test across Gmail, Apple Mail, and Outlook (or use Litmus/Email on Acid).
PewSearch care broadcast uses raw fetch:
PewSearch's care broadcast route (/api/care/broadcast/route.ts) calls the Resend API via raw fetch() rather than the npm package. This is intentional for minimal dependencies on the broadcast route. The pattern is: Authorization: Bearer ${process.env.RESEND_API_KEY} against https://api.resend.com/emails.
FA-007 pending: Agents do not currently have access to john@churchwiseai.com inbox to verify email delivery. Use Resend's dashboard or API logs to confirm deliverability.
Failure Modes & Recovery
| Failure | Behavior | Recovery |
|---|---|---|
RESEND_API_KEY not set | Runtime crash (Resend constructor throws on first send) | Set env var immediately; no silent fail unlike MailerLite |
| Send fails (Resend error) | Error logged to console; user flow continues (errors caught) | Check Resend dashboard for suppressed addresses or domain issues |
| Welcome email not received | User can request resend via /onboard/resend-link | Confirm email not in spam; check Resend logs for bounces |
| Magic link expired or reused | User re-requests via resend endpoint; same welcome email sent | Token is permanent until revoked — link doesn't expire by design |
| WatchTower alert not delivered | Operational alert missed | Check ALERT_EMAIL env var; verify Resend domain DNS (SPF/DKIM) |
| Domain not verified in Resend | Emails go to spam or are rejected | Verify DNS records for churchwiseai.com, pewsearch.com, illustratetheword.com in Resend dashboard |
Resend vs. MailerLite — When to Use Which
| Scenario | Use |
|---|---|
| System-triggered, one-to-one email (magic link, payment alert) | Resend |
| Marketing campaign, newsletter blast | MailerLite |
| Subscriber lifecycle automation (onboarding drips, win-back, cross-promo) | Resend (lifecycle email system via lifecycle-emails.ts + daily cron) |
| Operational alert to founder | Resend (WatchTower) |
| Care message to congregation member | Resend (PewSearch care broadcast) |
Cost Model / Usage Limits
- Free tier: 3,000 emails/month, 100/day
- Pro tier: Starts at $20/month for 50,000 emails
- Current volume: Very low (pre-launch; 4 test accounts). Free tier is sufficient until customer scale.
- Domain verification: Required for custom
fromaddresses. All three property domains must be verified in the Resend account.
See Also
- MailerLite Integration — subscriber CRM, newsletter management, audience segmentation
- Stripe Integration — checkout events that trigger welcome and alert emails
churchwiseai-web/src/lib/email.ts— all CWA email functions