Resend Integration for Transactional Email
Resend — a modern email API with native React Email support, clear documentation, and a generous free tier (3,000 emails/month). Good for SaaS startups and applications that want to quickly add reliable transactional email.
Installation and First Send
npm install resend
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
// Simple send
const { data, error } = await resend.emails.send({
from: 'Acme <[email protected]>',
to: ['[email protected]'],
subject: 'Welcome to Acme!',
html: '<h1>Hello!</h1><p>Thank you for signing up.</p>',
});
if (error) {
console.error('Email error:', error);
}
With React Email Templates
import { Resend } from 'resend';
import { render } from '@react-email/render';
import WelcomeEmail from './emails/WelcomeEmail';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcomeEmail(user: { email: string; name: string }) {
const html = render(
<WelcomeEmail name={user.name} loginUrl="https://app.acme.com/login" />
);
await resend.emails.send({
from: 'Acme Team <[email protected]>',
to: user.email,
subject: 'Welcome to Acme!',
html,
});
}
Batch Sending
// Up to 100 emails in a single request
await resend.batch.send([
{
from: '[email protected]',
to: '[email protected]',
subject: 'Your invoice is ready',
html: invoiceHtml1,
},
{
from: '[email protected]',
to: '[email protected]',
subject: 'Your invoice is ready',
html: invoiceHtml2,
},
]);
Webhooks for Status Tracking
Resend sends webhooks when email status changes:
// POST /api/webhooks/resend
app.post('/api/webhooks/resend', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['resend-signature'];
// Verify signature via svix
const event = JSON.parse(req.body);
switch (event.type) {
case 'email.sent':
await db.emailLogs.update({ emailId: event.data.email_id, status: 'sent' });
break;
case 'email.delivered':
await db.emailLogs.update({ emailId: event.data.email_id, status: 'delivered' });
break;
case 'email.bounced':
await db.users.markEmailBounced(event.data.to[0]);
break;
case 'email.complained':
await db.users.unsubscribe(event.data.to[0]);
break;
}
res.status(200).end();
});
Timeline
Integration with Resend and setting up transactional email templates — 2–3 days.







