Communication · Intermediate
Email System
Transactional email via Resend — welcome, verify, password reset, purchase receipt, refund, team invite, affiliate payout, and newsletter templates sharing one branded HTML layout.
Read the Getting Access guideif you haven't yet.
1. Get the file
Sign in at marrowstack.dev, open the Email System block, and click Copy all files. Paste lib/email.ts into your project. All templates share a single branded HTML layout — edit the BRAND constant at the top of the file to set your colors, logo URL, and company name.
2. Prerequisites
- Next.js 14 or 15, App Router
- Resend account at
resend.comwith a verified sender domain - A domain with DNS access (to add the SPF/DKIM records Resend requires)
3. Install
- Copy
lib/email.tsfrom the block detail page into your project. - Install peer dependencies:
npm install resend zod4. Environment
| Variable | Required | Default | Purpose |
|---|---|---|---|
| RESEND_API_KEY | yes | — | Resend API key from resend.com/api-keys |
| EMAIL_FROM | yes | — | Verified sender address, e.g. hello@yourdomain.com |
| APP_URL | no | — | Base URL for action links in emails, e.g. https://yourdomain.com |
5. Wire it in
All functions are called server-side only. Import and call them from API routes, Server Actions, or route handlers.
import { sendVerifyEmail } from '@/lib/email'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest) {
const { email, verifyUrl } = await req.json()
await sendVerifyEmail({
to: email,
verifyUrl,
})
return NextResponse.json({ ok: true })
}'use server'
import { sendWelcomeEmail } from '@/lib/email'
export async function onUserSignUp(email: string, name: string) {
await sendWelcomeEmail({ to: email, name })
}Available send functions:
- sendWelcomeEmail({ to, name })
- sendVerifyEmail({ to, verifyUrl })
- sendPasswordResetEmail({ to, resetUrl })
- sendPurchaseReceiptEmail({ to, orderDetails })
- sendRefundEmail({ to, refundDetails })
- sendTeamInviteEmail({ to, inviteUrl, workspaceName })
- sendNewsletterEmail({ to, subject, content })
6. Verify it works
- Call
sendWelcomeEmail({ to: 'your@email.com', name: 'Test' })from a test route. - Check Resend Dashboard → Logs to confirm the email was accepted and delivered.
- Open the email in a real inbox and verify the layout renders correctly across Gmail, Outlook, and Apple Mail.
7. Failure modes & fixes
API key is invalid
Cause: RESEND_API_KEY is wrong or expired.
Fix: Regenerate the API key in Resend Dashboard → API Keys.
From address is not verified
Cause: EMAIL_FROM uses a domain that hasn't been verified in Resend.
Fix: Add your domain in Resend Dashboard → Domains and add the required DNS records.
Emails delivered but landing in spam
Cause: SPF/DKIM records not set, or sending from a shared domain.
Fix: Verify a custom domain in Resend and ensure all DNS records are propagated. Avoid sending from resend.dev in production.