resend

Integrate Resend email API for sending transactional and marketing emails with TypeScript/Node.js. Covers all Resend APIs: sending single/batch emails, React Email templates, domain setup and DNS verification, contact and audience management, broadcasts, webhooks, and API key management. Use when the user mentions 'resend,' 'send email,' 'email API,' 'transactional email,' 'react email,' 'email template,' or needs to integrate email sending into a TypeScript/Next.js application using Resend.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "resend" with this command: npx skills add jsv-capital/resend-skill/jsv-capital-resend-skill-resend

Resend

Email API integration for TypeScript/Node.js applications. Covers transactional email, React Email templates, domains, contacts, broadcasts, and webhooks.

Quick Start

npm install resend
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);

const { data, error } = await resend.emails.send({
  from: "App <hello@yourdomain.com>",
  to: "user@example.com",
  subject: "Hello",
  html: "<p>Hello world</p>",
});

Environment variable: RESEND_API_KEY (get from https://resend.com/api-keys).

Task Decision Tree

  1. Sending a single email → Use resend.emails.send(). See Send Email.
  2. Sending bulk emails (same API call) → Use resend.batch.send(). Max 100 per call. No attachments or scheduling.
  3. Building email templates → Use React Email components. See references/react_email.md.
  4. Setting up a domain → Use resend.domains.create(). Then add DNS records. See Domain Setup.
  5. Tracking email events → Configure webhooks in dashboard. Verify with svix. See Webhooks.
  6. Managing contacts/audiences → Use contacts API with audience IDs. See references/api_reference.md > Contacts.
  7. Sending marketing campaigns → Use broadcasts API. See references/api_reference.md > Broadcasts.
  8. Full API details for any endpoint → See references/api_reference.md.

Send Email

Single Email

const { data, error } = await resend.emails.send({
  from: "App <hello@yourdomain.com>",
  to: ["user@example.com"],
  subject: "Order Confirmed",
  html: "<h1>Your order is confirmed</h1>",
  // Optional:
  cc: ["cc@example.com"],
  bcc: ["bcc@example.com"],
  replyTo: "support@yourdomain.com",
  scheduledAt: "in 1 hour",           // or ISO 8601
  headers: { "X-Entity-Ref-ID": "123" },
  tags: [{ name: "category", value: "order" }],
  attachments: [{
    filename: "receipt.pdf",
    content: buffer,                   // Buffer or base64 string
  }],
});

With React Email

import { OrderConfirmation } from "@/emails/order-confirmation";

const { data, error } = await resend.emails.send({
  from: "App <hello@yourdomain.com>",
  to: "user@example.com",
  subject: "Order Confirmed",
  react: OrderConfirmation({ orderId: "12345", items }),
});

For React Email component patterns and the full template reference, see references/react_email.md.

Batch Send

const { data, error } = await resend.batch.send([
  { from: "App <hello@yourdomain.com>", to: "a@example.com", subject: "Hi A", html: "<p>Hello A</p>" },
  { from: "App <hello@yourdomain.com>", to: "b@example.com", subject: "Hi B", html: "<p>Hello B</p>" },
]);

Limits: max 100 emails per request, 50 recipients per email. No attachments or scheduledAt in batch.

Idempotency

Prevent duplicate sends with the Idempotency-Key header (expires 24h):

const { data, error } = await resend.emails.send(
  { from: "...", to: "...", subject: "...", html: "..." },
  { headers: { "Idempotency-Key": "order-12345-confirmation" } }
);

Check Email Status

const { data } = await resend.emails.get("email-id");
// data.last_event: "sent" | "delivered" | "bounced" | "opened" | "clicked" | "complained"

Domain Setup

1. Create Domain

const { data } = await resend.domains.create({
  name: "yourdomain.com",
  region: "us-east-1", // us-east-1 | eu-west-1 | sa-east-1 | ap-northeast-1
});

2. Add DNS Records

The response includes data.records — an array of DNS records to add:

TypePurpose
MXMail routing
TXT (SPF)Authorize Resend to send
CNAME (DKIM)Cryptographic signing (3 records)

Add all records to your DNS provider. TTL: use Auto or the value from the response.

3. Verify

await resend.domains.verify("domain-id");

Verification can take minutes to hours depending on DNS propagation.

Domain Options

  • openTracking: true — track email opens (adds tracking pixel)
  • clickTracking: true — track link clicks (rewrites links)
  • tlsMode: "enforced" — require TLS (blocks delivery to servers without TLS)
  • capabilities: { sending: "enabled", receiving: "enabled" } — enable inbound email

Webhooks

Event Types

EventDescription
email.sentEmail sent to recipient server
email.deliveredAccepted by recipient server
email.delivery_delayedTemporary delivery failure
email.bouncedPermanent delivery failure
email.complainedMarked as spam
email.openedOpened (requires open tracking)
email.clickedLink clicked (requires click tracking)

Webhook Handler (Next.js)

// app/api/webhooks/resend/route.ts
import { Webhook } from "svix";

const webhookSecret = process.env.RESEND_WEBHOOK_SECRET;

export async function POST(request: Request) {
  const body = await request.text();
  const headers = Object.fromEntries(request.headers);

  const wh = new Webhook(webhookSecret);
  let payload: any;

  try {
    payload = wh.verify(body, {
      "svix-id": headers["svix-id"],
      "svix-timestamp": headers["svix-timestamp"],
      "svix-signature": headers["svix-signature"],
    });
  } catch {
    return new Response("Invalid signature", { status: 400 });
  }

  switch (payload.type) {
    case "email.delivered":
      // Handle delivery confirmation
      break;
    case "email.bounced":
      // Handle bounce — remove/flag email address
      break;
    case "email.complained":
      // Handle spam complaint — unsubscribe user
      break;
  }

  return new Response("OK", { status: 200 });
}

Install svix: npm install svix

Next.js Integration Pattern

app/
├── api/
│   ├── send/route.ts          # Email send endpoint
│   └── webhooks/resend/route.ts  # Webhook handler
├── emails/                     # React Email templates
│   ├── welcome.tsx
│   ├── password-reset.tsx
│   └── order-confirmation.tsx
└── lib/
    └── resend.ts              # Shared Resend client

Shared client (lib/resend.ts):

import { Resend } from "resend";

if (!process.env.RESEND_API_KEY) {
  throw new Error("RESEND_API_KEY is required");
}

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

Key Constraints

  • to field: max 50 addresses per email
  • Batch send: max 100 emails per request
  • Tags: max 256 chars per name/value
  • Idempotency keys: expire after 24 hours
  • react param: Node.js SDK only (not available via REST/cURL)
  • Batch does not support attachments or scheduledAt
  • Domain must be verified before sending (use onboarding@resend.dev for testing)
  • Broadcasts can only be updated/deleted while in draft status

References

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

email-best-practices

No summary provided by upstream source.

Repository SourceNeeds Review
3.7K-resend
General

resend

No summary provided by upstream source.

Repository SourceNeeds Review
3.4K-resend
General

react-email

No summary provided by upstream source.

Repository SourceNeeds Review
3.1K-resend
General

send-email

No summary provided by upstream source.

Repository SourceNeeds Review
464-resend