docs/developer/storefront/nextjs/emails.mdx
The storefront can own its customer-facing transactional emails instead of the Spree backend. Emails are rendered with react-email and sent via Resend; the Spree backend delivers order, shipment, and account events to the storefront over webhooks.
Spree Backend → Webhook POST → /api/webhooks/spree → render email → send via Resend
(signed HMAC) (signature verified) (react-email) (or write to disk in dev)
Email templates are React components in src/lib/emails/:
| File | Event | Description |
|---|---|---|
order-confirmation.tsx | order.completed | Items, totals, addresses, delivery method |
order-canceled.tsx | order.canceled | Cancellation notice with items |
shipment-shipped.tsx | order.shipped | Tracking number and link |
password-reset.tsx | customer.password_reset_requested | Reset button and fallback link |
Customize a template by editing its file directly — they use @react-email/components for email-safe layout primitives.
Run the storefront in development and open http://localhost:3001/dev/emails:
npm run dev
Each template renders with sample data via @react-email/render. The route is gated to non-production environments.
Add these to .env.local:
SPREE_WEBHOOK_SECRET=your_webhook_endpoint_secret_key
RESEND_API_KEY=re_your_resend_api_key # production only
EMAIL_FROM=Your Store <[email protected]> # production only
In development no RESEND_API_KEY is needed — emails are written to .next/emails/ as HTML files with a file:// link logged to the console.
The webhook route (src/app/api/webhooks/spree/route.ts) wires events to handlers with createWebhookHandler from src/lib/spree/webhooks. Signature verification and event routing are handled for you:
import { createWebhookHandler } from '@/lib/spree/webhooks'
const handler = createWebhookHandler({
secret: process.env.SPREE_WEBHOOK_SECRET!,
handlers: {
'order.completed': handleOrderCompleted,
'order.canceled': handleOrderCanceled,
'order.shipped': handleOrderShipped,
'customer.password_reset_requested': handlePasswordReset,
},
})
To add a new email type:
src/lib/emails/.src/lib/webhooks/handlers.ts.route.ts.Create a webhook endpoint in Spree Admin → Settings → Developers → Webhooks. Subscribe to order.completed, order.canceled, order.shipped, and customer.password_reset_requested, and copy the secret key into SPREE_WEBHOOK_SECRET.
Receive webhooks locally. Expose the storefront with a public URL so Spree can reach it — the simplest option is a Cloudflare Tunnel:
brew install cloudflared
cloudflared tunnel --url http://localhost:3001
Use the tunnel URL as the webhook endpoint URL in Spree Admin.
For the backend perspective on delivering these events, see Sending out Emails.