Resend: Transactional Email Done Right in 2026
Production-ready guide to Resend's email API. Real error patterns, working code, and when to actually use it versus alternatives.
TL;DR
Resend is a modern transactional email service built for developers. Send emails via REST API or React Email component library. Pricing starts free tier (100 emails/day), then $0.20/1000 emails. Best for startups shipping fast; overkill if you're already deep in SendGrid/AWS SES. This guide covers v3.x API patterns, common console errors, and production patterns.
---
The Problem Resend Solves
Transactional email has a trust problem. You want reliable delivery. You need HTML that doesn't look like 2003. You're tired of fighting SMTP configuration.
Resend strips this down: API key + POST request = email sent. That's it. The team built [React Email](https://react.email) alongside it—components over string concatenation.
But here's the real talk: Resend isn't universally better. It's better *if you're sending less than 100k emails/month and want dev ergonomics*. If you're sending millions or need advanced analytics (ISP feedback loops, authentication monitoring), AWS SES or Postmark might fit better.
---
Getting Started: Authentication & Setup
Grab your API key from [Resend dashboard](https://resend.com). Verify in official docs that current SDK is resend@3.2.0 or later (verify exact version).
```typescript import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY); ```
Environment variable checklist:
RESEND_API_KEY – never commit this---
Real Console Errors You'll Hit
Error 1: Missing From Address
``` ResendError: Invalidfrom email address.
It should either be only a valid email, or have the format 'name <email>' with a valid email.
Code: INVALID_FROM_ADDRESS
```Why it happens: You passed from: "My App" instead of from: "noreply@myapp.com".
Fix: ```typescript // ❌ Wrong await resend.emails.send({ from: "My App", to: user.email, subject: "Welcome" });
// ✅ Right await resend.emails.send({ from: "noreply@myapp.com", to: user.email, subject: "Welcome" }); ```
Error 2: Unverified Sender Domain
``` ResendError: The from email address is not verified. Please add and verify your domain. Code: UNVERIFIED_FROM_ADDRESS ```Why it happens: You added a custom domain but haven't verified SPF/DKIM records yet. Verification takes 5-30 minutes after DNS updates propagate.
Fix: In Resend dashboard, go to Senders → verify your domain follows the SPF/DKIM records provided. Verify in official docs for latest DNS requirements.
Error 3: Invalid JSON in HTML
``` SyntaxError: Unexpected token in JSON at position 142 ```Why it happens: You're using template literals with unescaped quotes or newlines in html field.
Fix: ```typescript // ❌ Wrong const html = ` <p>User said: "I love this"</p> `;
// ✅ Right (option 1: escape) const html = ` <p>User said: "I love this"</p> `;
// ✅ Right (option 2: use React Email) import { Html, Body, Text } from 'react-email'; const template = ( <Html> <Body> <Text>User said: "I love this"</Text> </Body> </Html> ); ```
---
Production Pattern: With React Email
This is the pattern that scales. React Email compiles to bulletproof HTML.
```typescript import { Resend } from 'resend'; import { ConfirmationEmail } from '@/emails/ConfirmationEmail';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendConfirmationEmail(
userEmail: string,
token: string
) {
try {
const response = await resend.emails.send({
from: 'onboarding@yourapp.com',
to: userEmail,
subject: 'Confirm your email',
react: <ConfirmationEmail confirmUrl={https://yourapp.com/confirm?token=${token}} />,
});
if (response.error) {
console.error('Resend error:', response.error);
throw new Error(Failed to send email: ${response.error.message});
}
return response.data.id; // Store for logging/debugging } catch (error) { console.error('Email send failed:', error); // Decide: retry, queue for later, or notify ops throw error; } } ```
React Email component:
```typescript import { Html, Body, Container, Text, Link, Button } from 'react-email';
interface ConfirmationEmailProps { confirmUrl: string; }
export const ConfirmationEmail = ({ confirmUrl }: ConfirmationEmailProps) => { return ( <Html> <Body style={{ fontFamily: 'sans-serif' }}> <Container style={{ maxWidth: '600px' }}> <Text>Welcome! Confirm your email to get started:</Text> <Button href={confirmUrl} style={{ background: '#000', color: '#fff', padding: '12px 20px', textDecoration: 'none', borderRadius: '4px', }} > Confirm Email </Button> </Container> </Body> </Html> ); }; ```
---
When NOT to Use Resend
---
Debugging & Monitoring
Resend provides a webhook API for bounce/complaint events. Set this up early:
```typescript // Webhook handler in your API route export async function POST(req: Request) { const event = await req.json(); if (event.type === 'email.bounced') { // Mark user email as invalid await db.users.update({ email: event.email }, { bounced: true }); } if (event.type === 'email.complained') { // User marked as spam—remove from future sends await db.users.update({ email: event.email }, { unsubscribed: true }); }
return Response.json({ success: true }); } ```
Verify webhook setup in [official docs](https://resend.com/docs/webhooks).
---
Pricing Reality Check (verify in official docs)
At 50k emails/month: ~$10 (base $20 minus credit). At 1M/month: $220. Compare to AWS SES ($0.10/1000 after free tier) if scale matters.
---
See Also
---
What am I missing?
Have you hit other Resend errors? Found better patterns? Using it in production with millions of sends? Drop corrections and additions below—this guide should reflect real-world experience.