How to fit Resend + React Email into a Next.js SaaS. Setup, helpers, deliverability, and common mistakes.
Transactional email is still the most underrated channel in SaaS. People open "your account is ready" more than any LinkedIn post. In 2026, Resend + React Email is the combo that best balances DX and deliverability without the historic markup of SendGrid or Mailgun.
This guide explains how to fit Resend + React Email into a Next.js SaaS and what patterns work.
Combine them: write emails as components, send with the API.
bun add resend @react-email/componentsEnv:
RESEND_API_KEY=re_...
EMAIL_FROM=hello@yourdomain.comClient:
// src/lib/email/client.ts
import { Resend } from 'resend';
export const resend = new Resend(process.env.RESEND_API_KEY);// src/lib/email/templates/welcome.tsx
import { Body, Button, Container, Heading, Html, Text } from '@react-email/components';
export function WelcomeEmail({ name }: { name: string }) {
return (
<Html>
<Body style={{ fontFamily: 'system-ui' }}>
<Container>
<Heading>Welcome, {name}</Heading>
<Text>Thanks for joining. Here's your first step:</Text>
<Button href="https://yourdomain.com/onboarding">Get started</Button>
</Container>
</Body>
</Html>
);
}Zero CSS, zero tangled <table> markup. Components produce HTML compatible with modern and old
email clients.
import { resend } from '@/lib/email/client';
import { WelcomeEmail } from '@/lib/email/templates/welcome';
await resend.emails.send({
from: process.env.EMAIL_FROM!,
to: user.email,
subject: 'Welcome to CREA.MBA',
react: <WelcomeEmail name={user.name} />,
});react: <Component />. No manual HTML rendering, no template-server detour.
React Email ships a preview server:
bunx email devOpen localhost:3000, see all your emails as the recipient would. Hugely helpful for iterating
without flooding your Gmail with test sends.
If you send 4-5 email types, pull them into helpers:
// src/lib/email/index.ts
import { resend } from './client';
import { WelcomeEmail } from './templates/welcome';
import { ResetPasswordEmail } from './templates/reset-password';
export async function sendWelcomeEmail(to: string, name: string) {
return resend.emails.send({
from: process.env.EMAIL_FROM!,
to,
subject: 'Welcome',
react: <WelcomeEmail name={name} />,
});
}
export async function sendResetPasswordEmail(to: string, link: string) {
return resend.emails.send({
from: process.env.EMAIL_FROM!,
to,
subject: 'Reset your password',
react: <ResetPasswordEmail link={link} />,
});
}Use them from server actions, webhooks, cron, etc. No repeating from or the client.
You CANNOT skip this. If you send without SPF/DKIM/DMARC, Gmail buckets you in spam.
In the Resend Dashboard → Domains → add your domain → Resend generates 3 DNS records. Paste them into Cloudflare/Route53/wherever. Resend validates and approves.
Without this: low rate limit, high spam. With it: normal deliverability.
1. from with an unverified domain: Resend blocks you. Verify the domain before sending.
2. Generic subjects: "Your account notification" tanks open rate. Be specific: "Your $49 payment processed successfully".
3. HTML-only email without plain text: some clients flag it as spam. Resend auto-generates the text version from the component — don't disable it.
4. Bulk sending from a user-facing endpoint: if you loop 1000 users and send inline, the endpoint times out. Use a queue (Inngest, BullMQ, or a separate script).
Resend + React Email is 30 minutes of setup and leaves you with modern transactional email in TS, local previews, and decent deliverability.
For indie SaaS up to ~50k users, there's no reason to pay more or configure more. It's the piece of the stack you set up and forget — which is exactly what you want from email.
Subscribe for more tutorials and tips on building products with AI
On Apr 25 2026 MinIO archived its community edition. We migrated Click2Eat and yamltools.dev to self-hosted Garage (S3-compatible, AGPLv3). Four undocumented gotchas, the shared S3 API + product-dedicated CDN pattern, and a complete migration checklist.