Agent skill
resend
Sends transactional emails with Resend including React Email templates, API integration, and Next.js setup. Use when sending emails, creating email templates, or integrating transactional email in applications.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/resend-mgd34msu-goodvibes-gemini
SKILL.md
Resend
Modern email API for developers with React Email support.
Quick Start
Install:
npm install resend
Environment variable:
# .env.local
RESEND_API_KEY=re_...
Basic Usage
Send Simple Email
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: ['user@example.com'],
subject: 'Hello World',
html: '<p>Welcome to our app!</p>',
});
API Route (Next.js App Router)
// app/api/send/route.ts
import { Resend } from 'resend';
import { NextResponse } from 'next/server';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: Request) {
const { to, subject, message } = await req.json();
try {
const { data, error } = await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: [to],
subject,
html: `<p>${message}</p>`,
});
if (error) {
return NextResponse.json({ error }, { status: 400 });
}
return NextResponse.json({ data });
} catch (error) {
return NextResponse.json(
{ error: 'Failed to send email' },
{ status: 500 }
);
}
}
React Email Templates
Install React Email
npm install @react-email/components
Create Template
// emails/welcome.tsx
import {
Body,
Button,
Container,
Head,
Heading,
Html,
Img,
Link,
Preview,
Section,
Text,
} from '@react-email/components';
interface WelcomeEmailProps {
username: string;
loginUrl: string;
}
export function WelcomeEmail({ username, loginUrl }: WelcomeEmailProps) {
return (
<Html>
<Head />
<Preview>Welcome to Acme - Your account is ready!</Preview>
<Body style={main}>
<Container style={container}>
<Img
src="https://acme.com/logo.png"
width={48}
height={48}
alt="Acme"
/>
<Heading style={h1}>Welcome, {username}!</Heading>
<Text style={text}>
Thanks for signing up for Acme. We're excited to have you on board.
</Text>
<Section style={buttonContainer}>
<Button style={button} href={loginUrl}>
Get Started
</Button>
</Section>
<Text style={footer}>
If you didn't create an account, you can safely ignore this email.
</Text>
</Container>
</Body>
</Html>
);
}
const main = {
backgroundColor: '#f6f9fc',
fontFamily:
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
};
const container = {
backgroundColor: '#ffffff',
margin: '0 auto',
padding: '40px 20px',
borderRadius: '5px',
maxWidth: '465px',
};
const h1 = {
color: '#1f2937',
fontSize: '24px',
fontWeight: '600',
lineHeight: '40px',
margin: '0 0 20px',
};
const text = {
color: '#4b5563',
fontSize: '14px',
lineHeight: '24px',
margin: '0 0 20px',
};
const buttonContainer = {
textAlign: 'center' as const,
margin: '30px 0',
};
const button = {
backgroundColor: '#3b82f6',
borderRadius: '5px',
color: '#fff',
fontSize: '14px',
fontWeight: '600',
textDecoration: 'none',
textAlign: 'center' as const,
display: 'inline-block',
padding: '12px 30px',
};
const footer = {
color: '#9ca3af',
fontSize: '12px',
lineHeight: '16px',
margin: '20px 0 0',
};
export default WelcomeEmail;
Send with Template
// app/api/send-welcome/route.ts
import { Resend } from 'resend';
import { WelcomeEmail } from '@/emails/welcome';
import { NextResponse } from 'next/server';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: Request) {
const { email, username } = await req.json();
try {
const { data, error } = await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: [email],
subject: 'Welcome to Acme!',
react: WelcomeEmail({
username,
loginUrl: `${process.env.NEXT_PUBLIC_APP_URL}/login`,
}),
});
if (error) {
return NextResponse.json({ error }, { status: 400 });
}
return NextResponse.json({ data });
} catch (error) {
return NextResponse.json(
{ error: 'Failed to send email' },
{ status: 500 }
);
}
}
Common Email Templates
Password Reset
// emails/password-reset.tsx
import {
Body,
Button,
Container,
Head,
Heading,
Html,
Preview,
Text,
} from '@react-email/components';
interface PasswordResetProps {
resetUrl: string;
expiresIn: string;
}
export function PasswordResetEmail({ resetUrl, expiresIn }: PasswordResetProps) {
return (
<Html>
<Head />
<Preview>Reset your password</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>Reset Your Password</Heading>
<Text style={text}>
We received a request to reset your password. Click the button below
to create a new password.
</Text>
<Button style={button} href={resetUrl}>
Reset Password
</Button>
<Text style={text}>
This link will expire in {expiresIn}. If you didn't request a
password reset, you can safely ignore this email.
</Text>
</Container>
</Body>
</Html>
);
}
Order Confirmation
// emails/order-confirmation.tsx
import {
Body,
Column,
Container,
Head,
Heading,
Hr,
Html,
Preview,
Row,
Section,
Text,
} from '@react-email/components';
interface OrderItem {
name: string;
quantity: number;
price: number;
}
interface OrderConfirmationProps {
orderNumber: string;
items: OrderItem[];
total: number;
shippingAddress: string;
}
export function OrderConfirmationEmail({
orderNumber,
items,
total,
shippingAddress,
}: OrderConfirmationProps) {
return (
<Html>
<Head />
<Preview>Order {orderNumber} confirmed</Preview>
<Body style={main}>
<Container style={container}>
<Heading style={h1}>Order Confirmed</Heading>
<Text style={text}>
Thanks for your order! Your order number is{' '}
<strong>{orderNumber}</strong>.
</Text>
<Section style={orderSection}>
<Heading as="h2" style={h2}>
Order Summary
</Heading>
{items.map((item, index) => (
<Row key={index} style={itemRow}>
<Column>
<Text style={itemName}>{item.name}</Text>
<Text style={itemQuantity}>Qty: {item.quantity}</Text>
</Column>
<Column style={priceColumn}>
<Text style={itemPrice}>${item.price.toFixed(2)}</Text>
</Column>
</Row>
))}
<Hr style={hr} />
<Row>
<Column>
<Text style={totalLabel}>Total</Text>
</Column>
<Column style={priceColumn}>
<Text style={totalPrice}>${total.toFixed(2)}</Text>
</Column>
</Row>
</Section>
<Section>
<Heading as="h2" style={h2}>
Shipping Address
</Heading>
<Text style={text}>{shippingAddress}</Text>
</Section>
</Container>
</Body>
</Html>
);
}
Email Options
Full Options
const { data, error } = await resend.emails.send({
// Required
from: 'Acme <noreply@acme.com>',
to: ['user@example.com'],
subject: 'Hello',
// Content (one of these)
html: '<p>Hello</p>',
text: 'Hello',
react: EmailTemplate({ props }),
// Optional
cc: ['cc@example.com'],
bcc: ['bcc@example.com'],
replyTo: 'support@acme.com',
headers: {
'X-Custom-Header': 'value',
},
attachments: [
{
filename: 'invoice.pdf',
content: Buffer.from(pdfContent),
},
],
tags: [
{ name: 'category', value: 'transactional' },
],
});
Multiple Recipients
// To multiple addresses
await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: ['user1@example.com', 'user2@example.com'],
subject: 'Team Update',
html: '<p>Hello team!</p>',
});
// Batch send (different emails)
const { data, error } = await resend.batch.send([
{
from: 'Acme <noreply@acme.com>',
to: ['user1@example.com'],
subject: 'Welcome User 1',
html: '<p>Hello User 1!</p>',
},
{
from: 'Acme <noreply@acme.com>',
to: ['user2@example.com'],
subject: 'Welcome User 2',
html: '<p>Hello User 2!</p>',
},
]);
Attachments
import { readFileSync } from 'fs';
// From file
const attachment = readFileSync('./invoice.pdf');
await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: ['user@example.com'],
subject: 'Your Invoice',
html: '<p>Please find your invoice attached.</p>',
attachments: [
{
filename: 'invoice.pdf',
content: attachment,
},
],
});
// From URL
await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: ['user@example.com'],
subject: 'Your Report',
html: '<p>Please find your report attached.</p>',
attachments: [
{
filename: 'report.pdf',
path: 'https://example.com/reports/report.pdf',
},
],
});
Preview Emails
Development Server
npm install react-email -D
{
"scripts": {
"email": "email dev --dir emails"
}
}
npm run email
Opens at http://localhost:3000 to preview templates.
Server Actions
// app/actions/email.ts
'use server';
import { Resend } from 'resend';
import { WelcomeEmail } from '@/emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendWelcomeEmail(email: string, username: string) {
try {
const { data, error } = await resend.emails.send({
from: 'Acme <noreply@acme.com>',
to: [email],
subject: 'Welcome to Acme!',
react: WelcomeEmail({ username, loginUrl: '/login' }),
});
if (error) {
return { success: false, error: error.message };
}
return { success: true, messageId: data?.id };
} catch (error) {
return { success: false, error: 'Failed to send email' };
}
}
Webhooks
// app/api/webhooks/resend/route.ts
import { NextResponse } from 'next/server';
export async function POST(req: Request) {
const payload = await req.json();
switch (payload.type) {
case 'email.sent':
console.log('Email sent:', payload.data.email_id);
break;
case 'email.delivered':
console.log('Email delivered:', payload.data.email_id);
break;
case 'email.bounced':
console.log('Email bounced:', payload.data.email_id);
// Handle bounce - update user record
break;
case 'email.complained':
console.log('Spam complaint:', payload.data.email_id);
// Handle complaint - unsubscribe user
break;
}
return NextResponse.json({ received: true });
}
Best Practices
- Use React Email - Type-safe, reusable templates
- Verify domain - Better deliverability
- Handle errors - Check for error response
- Use batch for bulk - More efficient
- Preview before sending - Use email dev server
Common Mistakes
| Mistake | Fix |
|---|---|
| Unverified domain | Verify in Resend dashboard |
| Missing from address | Use verified domain email |
| Not handling errors | Check error response |
| Inline styles missing | Use style objects in React Email |
| Large attachments | Keep under 40MB |
Reference Files
- references/templates.md - More template examples
- references/webhooks.md - Webhook events
- references/domains.md - Domain verification
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?