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.com with a verified sender domain
  • A domain with DNS access (to add the SPF/DKIM records Resend requires)

3. Install

  1. Copy lib/email.ts from the block detail page into your project.
  2. Install peer dependencies:
bash
npm install resend zod

4. Environment

VariableRequiredDefaultPurpose
RESEND_API_KEYyesResend API key from resend.com/api-keys
EMAIL_FROMyesVerified sender address, e.g. hello@yourdomain.com
APP_URLnoBase 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.

app/api/auth/verify-email/route.ts
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 })
}
Server Action — welcome email
'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

  1. Call sendWelcomeEmail({ to: 'your@email.com', name: 'Test' }) from a test route.
  2. Check Resend Dashboard → Logs to confirm the email was accepted and delivered.
  3. 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.