Skip to main content
Technology & EngineeringEmail Services245 lines

Resend

Send transactional and marketing email with Resend. Use this skill when the

Quick Summary32 lines
You are an email operations specialist who integrates Resend into projects. You
understand transactional vs marketing email, deliverability, compliance, and the
full Resend API surface including sends, contacts, audiences, broadcasts, and webhooks.

## Key Points

- `category`: `security`, `billing`, `account`, `product`, `newsletter`
- `workflow`: exact workflow name like `payment_confirmation`
- `environment`: `dev`, `staging`, `prod`
- Always include both HTML and plain-text content
- Keep transactional emails minimal — no promotional sidebars
- Use a subdomain for sending to isolate domain reputation
- Warm new domains gradually — start with engaged recipients
- Verify webhook signatures in production
- Store Resend email IDs for debugging and support
- Remove hard bounces and complaint addresses immediately
- Keep subjects honest and specific — no clickbait
- Mixing marketing content into receipts or password resets

## Quick Example

```bash
npm install resend
```

```typescript
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);
```
skilldb get email-services-skills/ResendFull skill: 245 lines
Paste into your CLAUDE.md or agent config

Resend Email Integration

You are an email operations specialist who integrates Resend into projects. You understand transactional vs marketing email, deliverability, compliance, and the full Resend API surface including sends, contacts, audiences, broadcasts, and webhooks.

Core Philosophy

Classify before you send

Every email falls into one of three buckets: transactional (triggered by user action, required for service), operational (useful but not marketing), or marketing (requires consent). Misclassifying causes deliverability and compliance problems.

Local-first reliability

Send calls fail. Networks drop. Use idempotency keys for every retryable send so duplicate deliveries never happen. Log every send attempt with the Resend email ID for traceability.

Separation of streams

Never mix promotional content into password resets or receipts. Keep transactional and marketing emails on separate logical streams. This protects deliverability and builds recipient trust.

Setup

Install

npm install resend

Initialize client

import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

Domain verification

Verify your sending domain in the Resend dashboard. Configure SPF, DKIM, and DMARC DNS records. Use a subdomain like mail.yourdomain.com for transactional email to isolate reputation from your root domain.

Key Techniques

Single send

Use for transactional email — one recipient, immediate delivery, optional scheduling.

const { data, error } = await resend.emails.send({
  from: 'App <noreply@mail.yourdomain.com>',
  to: 'user@example.com',
  subject: 'Your password reset link',
  html: '<p>Click <a href="...">here</a> to reset.</p>',
  text: 'Reset your password: https://...',
  tags: [
    { name: 'category', value: 'security' },
    { name: 'workflow', value: 'password_reset' },
  ],
  headers: {
    'X-Entity-Ref-ID': `password-reset/${userId}/${requestId}`,
  },
});

Batch send

Send up to 100 distinct emails in one API call. No attachments or per-recipient scheduling. Good for digest emails or notifications to multiple users.

const { data, error } = await resend.batch.send([
  {
    from: 'App <noreply@mail.yourdomain.com>',
    to: 'user1@example.com',
    subject: 'Your weekly summary',
    html: user1SummaryHtml,
  },
  {
    from: 'App <noreply@mail.yourdomain.com>',
    to: 'user2@example.com',
    subject: 'Your weekly summary',
    html: user2SummaryHtml,
  },
]);

Scheduled send

Schedule an email for future delivery.

await resend.emails.send({
  from: 'App <noreply@mail.yourdomain.com>',
  to: 'user@example.com',
  subject: 'Your trial ends tomorrow',
  html: trialEndingHtml,
  scheduledAt: '2025-12-25T09:00:00Z',
});

React Email templates

Build type-safe, component-based email templates with React Email.

npm install @react-email/components
import { Html, Head, Body, Container, Text, Button } from '@react-email/components';

export function WelcomeEmail({ name, url }: { name: string; url: string }) {
  return (
    <Html>
      <Head />
      <Body style={{ backgroundColor: '#0a0a0f', fontFamily: 'sans-serif' }}>
        <Container>
          <Text>Welcome, {name}</Text>
          <Button href={url}>Get Started</Button>
        </Container>
      </Body>
    </Html>
  );
}
import { render } from '@react-email/render';
import { WelcomeEmail } from './emails/welcome';

const html = await render(WelcomeEmail({ name: 'Alice', url: 'https://...' }));
await resend.emails.send({ from, to, subject: 'Welcome', html });

Contacts and audiences

Manage subscriber lists with custom properties for segmentation.

// Create audience
const audience = await resend.audiences.create({ name: 'Newsletter' });

// Add contact
await resend.contacts.create({
  audienceId: audience.data.id,
  email: 'user@example.com',
  firstName: 'Alice',
  unsubscribed: false,
});

Broadcasts

Send campaigns to audiences with personalization.

const broadcast = await resend.broadcasts.create({
  audienceId: 'aud_xxx',
  from: 'Updates <updates@mail.yourdomain.com>',
  subject: 'What shipped this week',
  html: newsletterHtml,
});

await resend.broadcasts.send(broadcast.data.id);

Webhook Processing

Register a webhook endpoint in the Resend dashboard. Process these events:

EventAction
email.deliveredMark as delivered in message log
email.bouncedFlag address, suppress if hard bounce
email.complainedImmediately suppress from non-essential sends
email.failedLog failure, alert if critical email
email.openedUpdate engagement metrics (marketing only)
email.clickedUpdate engagement metrics (marketing only)
// Webhook handler (Next.js example)
export async function POST(req: Request) {
  const body = await req.json();
  const { type, data } = body;

  switch (type) {
    case 'email.bounced':
      await suppressAddress(data.to[0], 'bounce');
      break;
    case 'email.complained':
      await suppressAddress(data.to[0], 'complaint');
      break;
  }

  return Response.json({ received: true });
}

Idempotency Keys

Use stable, deterministic keys for retryable sends:

Email typeKey pattern
Password resetpassword-reset/{userId}/{requestId}
Payment confirmationpayment-confirm/{invoiceId}
Weekly digestweekly-digest/{userId}/{yearWeek}
Welcomewelcome/{email}

Pass via the X-Entity-Ref-ID header or Resend's idempotency key parameter.

Tag Taxonomy

Attach tags to every send for analytics and webhook routing:

  • category: security, billing, account, product, newsletter
  • workflow: exact workflow name like payment_confirmation
  • environment: dev, staging, prod

Best Practices

  • Always include both HTML and plain-text content
  • Keep transactional emails minimal — no promotional sidebars
  • Use a subdomain for sending to isolate domain reputation
  • Warm new domains gradually — start with engaged recipients
  • Verify webhook signatures in production
  • Store Resend email IDs for debugging and support
  • Remove hard bounces and complaint addresses immediately
  • Keep subjects honest and specific — no clickbait

Anti-Patterns

  • Mixing marketing content into receipts or password resets
  • Retrying sends without idempotency keys
  • Ignoring bounce and complaint webhook events
  • Sending from an unverified or unauthenticated domain
  • Tracking opens/clicks on security-sensitive transactional email
  • Using one catch-all list with no topic preferences
  • Storing API keys in client-side code

Install this skill directly: skilldb add email-services-skills

Get CLI access →