본문으로 건너뛰기
cccskills
무료GitHub에 공개

api-email-resend-react-email

Resend + React Email templates

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(9)

  • SKILL.md10.9 KB
  • examples/advanced-features.md6.8 KB
  • examples/async-batch.md5.3 KB
  • examples/core.md7.6 KB
  • examples/preferences.md4.8 KB
  • examples/templates.md4.4 KB
  • examples/webhooks.md5.0 KB
  • metadata.yaml367 B
  • reference.md4.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Email Patterns with Resend and React Email

Quick Guide: Use Resend for transactional emails with React Email templates. Always await render() before sending (it returns a Promise). Server-side only - never expose API keys to clients. Implement retry with exponential backoff for transient failures. Include unsubscribe links in non-transactional emails (CAN-SPAM). Use resend.batch.send() for 2-100 recipients (no attachments or scheduling support in batch). React Email 5.0+ deprecated renderAsync - use render() instead. Webhook verification requires raw request body and webhookSecret parameter.


<critical_requirements>

CRITICAL: Before Using This Skill

(You MUST await render() before passing HTML to resend.emails.send() - render returns a Promise)

(You MUST handle Resend API errors and implement retry logic for transient failures)

(You MUST use server-side sending for all emails - never expose RESEND_API_KEY to the client)

(You MUST include unsubscribe links in marketing/notification emails - required for CAN-SPAM compliance)

(You MUST use typed props interfaces for all email templates - enables compile-time validation)

</critical_requirements>


Auto-detection: Resend, React Email, @react-email/components, resend.emails.send, email template, transactional email, verification email, password reset email, notification email, email rendering, resend.batch.send, resend.webhooks.verify

When to use:

  • Sending transactional emails (verification, password reset, receipts)
  • Creating React Email templates with Tailwind styling
  • Building notification systems with email delivery
  • Implementing email tracking via webhooks
  • Batch sending to multiple recipients

When NOT to use:

  • Marketing campaign management (use dedicated marketing tools)
  • SMS or push notifications (different services)
  • Email list management (use Resend Audiences or marketing tools)

<philosophy>

Philosophy

Email in modern applications follows a server-side, template-driven approach. React Email brings component patterns to email development, while Resend handles reliable delivery.

Core principles:

  1. Server-side only - Never expose API keys to clients
  2. Typed templates - Props interfaces catch errors at compile time
  3. Reliable delivery - Error handling with retry logic for transient failures
  4. Non-blocking - Fire-and-forget for non-critical emails

When to send emails:

  • User authentication events (verification, password reset, 2FA)
  • Transactional confirmations (purchases, signups, invitations)
  • Important notifications (security alerts, account changes)
  • Team collaboration (invites, mentions, updates)

When NOT to send emails:

  • Every minor action (creates email fatigue)
  • Marketing without consent (spam, illegal)
  • Real-time alerts (use push notifications)
  • In-app actions (show in-app notifications instead)
</philosophy>
<patterns>

Core Patterns

Pattern 1: Email Template Structure

Define typed props, use React Email components, add PreviewProps for the dev server.

interface WelcomeEmailProps {
  userName: string;
  loginUrl: string;
  features?: string[];
}

export function WelcomeEmail({ userName, loginUrl, features = [] }: WelcomeEmailProps) {
  return (
    <BaseLayout preview={`Welcome, ${userName}!`}>
      <Heading>Welcome!</Heading>
      <Text>Hi {userName},</Text>
      <Button href={loginUrl}>Get Started</Button>
    </BaseLayout>
  );
}

WelcomeEmail.PreviewProps = { userName: "John", loginUrl: "..." } satisfies WelcomeEmailProps;

See examples/core.md Pattern 1 for complete template with layout and styling.


Pattern 2: Sending with Error Handling

Always await render(), check the { data, error } response, return typed results.

const html = await render(options.react); // CRITICAL: must await

const { data, error } = await resend.emails.send({
  from: `${DEFAULT_FROM_NAME} <${DEFAULT_FROM_ADDRESS}>`,
  to: options.to,
  subject: options.subject,
  html,
});

if (error) {
  return { success: false, error: error.message };
}
return { success: true, id: data?.id };

See examples/core.md Pattern 2-3 for complete send wrapper and retry with exponential backoff.


Pattern 3: Async (Fire-and-Forget) Sending

For non-critical emails (welcome, notifications), don't block the response.

// Non-blocking - catches errors internally
sendEmailAsync(options);
return Response.json({ success: true }); // Returns immediately

Track in-flight promises for graceful shutdown. See examples/async-batch.md Pattern 1-2.


Pattern 4: Batch API

Use resend.batch.send() for 2-100 recipients. Render all templates in parallel.

const rendered = await Promise.all(
  emails.map(async (e) => ({
    from,
    to: e.to,
    subject: e.subject,
    html: await render(e.react),
  })),
);
const { data, error } = await resend.batch.send(rendered);

Batch limitations: No attachments, no scheduledAt. Tags and idempotency keys are supported. See examples/async-batch.md Pattern 3-4.


Pattern 5: Webhook Verification

Use resend.webhooks.verify() with the raw request body. JSON parsing breaks signature verification.

const payload = await request.text(); // Raw body, NOT .json()

const event = resend.webhooks.verify({
  payload,
  headers: {
    id: request.headers.get("svix-id") ?? "",
    timestamp: request.headers.get("svix-timestamp") ?? "",
    signature: request.headers.get("svix-signature") ?? "",
  },
  webhookSecret: process.env.RESEND_WEBHOOK_SECRET!,
});

See examples/webhooks.md for full handler with event processing and Svix alternative.


Pattern 6: Scheduled Sending, Idempotency Keys, Tags

// Scheduled (up to 30 days, NOT supported in batch)
await resend.emails.send({ ...payload, scheduledAt: futureDate.toISOString() });

// Idempotency (256 char limit, expires 24h) — second argument to send()
await resend.emails.send(payload, {
  idempotencyKey: `order-confirmation-${orderId}`,
});

// Tags (ASCII alphanumeric, underscores, dashes only)
await resend.emails.send({
  ...payload,
  tags: [{ name: "campaign", value: "launch" }],
});

See examples/advanced-features.md for complete implementations with validation.


Pattern 7: Unsubscribe and Preferences

Non-transactional emails MUST include unsubscribe links (CAN-SPAM). Use signed tokens for security.

// In every notification/marketing template:
<Link href={unsubscribeUrl}>Unsubscribe from these notifications</Link>

// Generate signed unsubscribe URLs
const token = jwt.sign({ userId, category }, UNSUBSCRIBE_SECRET, { expiresIn: "30d" });
const url = `${APP_URL}/api/email/unsubscribe?token=${token}`;

See examples/preferences.md for preference schema, checking before send, and unsubscribe endpoint.

</patterns>

Detailed Resources:


<red_flags>

RED FLAGS

High Priority Issues:

  • Not awaiting render() - sends "[object Promise]" as email body
  • API key exposed on client - security vulnerability
  • No error handling - silent failures
  • Missing unsubscribe links in non-transactional emails - CAN-SPAM violation
  • Sending without checking user preferences - spam

Medium Priority Issues:

  • No retry logic for transient failures (rate limits, 5xx errors)
  • Sync sending blocking request handlers for non-critical emails
  • Hardcoded from address instead of environment variable
  • No webhook verification signature check
  • Not logging email send results

Common Mistakes:

  • Using Grid or Flexbox in email templates (not supported by email clients)
  • Expecting shadows or gradients to render in emails
  • Using rem units (email clients handle differently)
  • Forgetting PreviewProps for dev server

Gotchas & Edge Cases:

  • Resend SDK accepts a react prop directly (renders internally), but pre-rendering with await render() + html gives you control over the output and works outside the Resend SDK
  • render() is async in React Email 5.0+ (renderAsync deprecated)
  • Batch API limited to 100 emails, does NOT support attachments or scheduledAt
  • Webhooks require raw request body - JSON parsing breaks signature verification
  • Webhook verify uses webhookSecret parameter (not secret)
  • Webhook headers object uses short keys: id, timestamp, signature
  • Idempotency keys are passed as a second argument to resend.emails.send(), not in the email payload headers
  • Idempotency keys expire after 24 hours, max 256 characters
  • Tags: ASCII alphanumeric, underscores, dashes only, max 256 chars per key/value
  • Tailwind in emails requires @react-email/tailwind wrapper (Tailwind 4 supported in React Email 5.0+)
  • Images must use absolute URLs (no relative paths)

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

(You MUST await render() before passing HTML to resend.emails.send() - render returns a Promise)

(You MUST handle Resend API errors and implement retry logic for transient failures)

(You MUST use server-side sending for all emails - never expose RESEND_API_KEY to the client)

(You MUST include unsubscribe links in marketing/notification emails - required for CAN-SPAM compliance)

(You MUST use typed props interfaces for all email templates - enables compile-time validation)

Failure to follow these rules will cause email delivery failures, security vulnerabilities, or legal compliance issues.

</critical_reminders>


Sources

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

agents-inc의 스킬 모두 보기

이 스킬의 문제 신고