mcpField
A
api-email-resend-react-email

api-email-resend-react-email

github.com/agents-inc开发2674 次安装2 天前更新
代码仓库

关于 api-email-resend-react-email

面向使用 Resend 和 React Email 构建事务邮件的开发者技能,涵盖类型化模板、安全的服务端发送、重试、批量投递与 Webhook 验证。

主要功能

  1. 01类型化 React Email 模板
  2. 02发送前异步渲染
  3. 03服务端发送与错误处理
  4. 04指数退避重试
  5. 05批量投递与 Webhook 验证

适用场景

  1. 01构建验证和密码重置邮件
  2. 02发送事务收据与通知
  3. 03向多个收件人批量发送
  4. 04验证 Resend Webhook 事件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/agents-inc/skills --skill api-email-resend-react-email

安装后在 Claude Code 中输入/api-email-resend-react-email确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.yaml
reference.md
examples/
advanced-features.md
async-batch.md
core.md
preferences.md
templates.md
webhooks.md

详细介绍

使用 Resend 和 React Email 构建电子邮件模式

快速指南: 使用 Resend 和 React Email 模板发送事务性电子邮件。发送前务必 await render()(它会返回一个 Promise)。仅限服务端使用——切勿向客户端暴露 API 密钥。对于暂时性故障,实现带指数退避的重试。非事务性电子邮件中应包含取消订阅链接(符合 CAN-SPAM 规定)。向 2–100 位收件人批量发送时使用 resend.batch.send()(批量发送不支持附件或定时发送)。React Email 5.0+ 已弃用 renderAsync——请改用 render()。验证 Webhook 需要原始请求正文和 webhookSecret 参数。


<critical_requirements>

关键:使用此技能前须知

所有代码必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、import type、命名常量)

(将 HTML 传递给 resend.emails.send() 前,必须先 await render()——render 会返回一个 Promise)

(必须处理 Resend API 错误,并为暂时性故障实现重试逻辑)

(所有电子邮件都必须在服务端发送——切勿向客户端暴露 RESEND_API_KEY)

(营销/通知电子邮件必须包含取消订阅链接——这是符合 CAN-SPAM 规定的要求)

(所有电子邮件模板都必须使用带类型的 props 接口——以便在编译时进行验证)

</critical_requirements>


自动检测: Resend、React Email、@react-email/components、resend.emails.send、电子邮件模板、事务性电子邮件、验证电子邮件、密码重置电子邮件、通知电子邮件、电子邮件渲染、resend.batch.send、resend.webhooks.verify

适用场景:

  • 发送事务性电子邮件(验证、密码重置、收据)
  • 使用 Tailwind 样式创建 React Email 模板
  • 构建通过电子邮件发送通知的系统
  • 通过 Webhook 实现电子邮件跟踪
  • 向多个收件人批量发送

不适用场景:

  • 营销活动管理(使用专门的营销工具)
  • SMS 或推送通知(需要使用其他服务)
  • 电子邮件列表管理(使用 Resend Audiences 或营销工具)

理念

现代应用中的电子邮件采用服务端、模板驱动的方式。React Email 将组件模式引入电子邮件开发,而 Resend 则负责可靠投递。

核心原则:

  1. 仅限服务端——切勿向客户端暴露 API 密钥
  2. 带类型的模板——props 接口可在编译时捕获错误
  3. 可靠投递——通过错误处理和重试逻辑应对暂时性故障
  4. 非阻塞——对于非关键电子邮件,采用发后即忘模式

适合发送电子邮件的场景:

  • 用户身份验证事件(验证、密码重置、2FA)
  • 事务性确认(购买、注册、邀请)
  • 重要通知(安全警报、账户变更)
  • 团队协作(邀请、提及、更新)

不适合发送电子邮件的场景:

  • 每个细微操作都发送通知(会造成电子邮件疲劳)
  • 未经同意发送营销邮件(属于垃圾邮件,且可能违法)
  • 实时警报(使用推送通知)
  • 应用内操作(改为显示应用内通知)

核心模式

模式 1:电子邮件模板结构

定义带类型的 props,使用 React Email 组件,并为开发服务器添加 PreviewProps。

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;

完整的模板(包含布局和样式)请参阅 examples/core.md 中的模式 1。


模式 2:带错误处理的发送方式

务必 await render(),检查 { data, error } 响应,并返回带类型的结果。

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 };

完整的发送封装和指数退避重试实现请参阅 examples/core.md 中的模式 2-3。


模式 3:异步(发后即忘)发送

对于非关键电子邮件(欢迎邮件、通知),不要阻塞响应。

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

跟踪正在执行的 Promise,以便优雅关闭。请参阅 examples/async-batch.md 中的模式 1-2。


模式 4:批量 API

对 2-100 位收件人使用 resend.batch.send()。并行渲染所有模板。

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);

**批量发送限制:**不支持 attachments 和 scheduledAt。支持标签和幂等键。参见 examples/async-batch.md 中的模式 3-4。


模式 5:Webhook 验证

使用原始请求正文调用 resend.webhooks.verify()。解析 JSON 会破坏签名验证。

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!,
});

完整的处理程序(包括事件处理和 Svix 替代方案)请参见 examples/webhooks.md。


模式 6:定时发送、幂等键、标签
// 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" }],
});

包含验证的完整实现请参见 examples/advanced-features.md。


模式 7:取消订阅和偏好设置

非事务性邮件必须包含取消订阅链接(CAN-SPAM)。请使用签名令牌来确保安全。

// 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}`;

偏好设置架构、发送前检查以及取消订阅端点,请参见 examples/preferences.md。


详细资源:


<red_flags>

危险信号

高优先级问题:

  • 未等待 render() - 将 "[object Promise]" 作为邮件正文发送
  • API 密钥暴露在客户端 - 安全漏洞
  • 没有错误处理 - 故障无提示
  • 非事务性邮件缺少取消订阅链接 - 违反 CAN-SPAM
  • 发送前未检查用户偏好设置 - 垃圾邮件

中优先级问题:

  • 瞬时故障(速率限制、5xx 错误)没有重试逻辑
  • 为非关键邮件进行同步发送,阻塞请求处理程序
  • 发件人地址硬编码,而不是使用环境变量
  • 没有 Webhook 验证签名检查
  • 不记录邮件发送结果

常见错误:

  • 在邮件模板中使用 Grid 或 Flexbox(邮件客户端不支持)
  • 期望阴影或渐变在邮件中正常呈现
  • 使用 rem 单位(不同邮件客户端的处理方式不同)
  • 忘记为开发服务器设置 PreviewProps

注意事项和边界情况:

  • Resend SDK 接受直接传入的 react 属性(会在内部渲染),但使用 await render() 预渲染并传入 html,可以让你控制输出内容,并且适用于 Resend SDK 之外的场景
  • React Email 5.0+ 中的 render() 是异步的(renderAsync 已弃用)
  • 批量 API 最多支持 100 封邮件,不支持 attachments 或 scheduledAt
  • Webhook 需要原始请求正文 - 解析 JSON 会破坏签名验证
  • Webhook 验证使用 webhookSecret 参数(不是 secret)
  • Webhook 标头对象使用简短键名:id、timestamp、signature
  • 幂等键作为第二个参数传入 resend.emails.send(),而不是放在邮件负载标头中
  • 幂等键 24 小时后过期,最长 256 个字符
  • 标签仅支持 ASCII 字母数字字符、下划线和连字符;每个键/值最多 256 个字符
  • 在邮件中使用 Tailwind 需要 @react-email/tailwind 包装器(React Email 5.0+ 支持 Tailwind 4)
  • 图片必须使用绝对 URL(不能使用相对路径)

</red_flags>


<critical_reminders>

关键提醒

所有代码都必须遵循项目中 CLAUDE.md 的约定(kebab-case、命名导出、导入排序、import type、命名常量)

(将 HTML 传递给 resend.emails.send() 前,必须等待 render() 完成——render 会返回一个 Promise)

(必须处理 Resend API 错误,并为暂时性故障实现重试逻辑)

(所有邮件都必须通过服务端发送——切勿向客户端暴露 RESEND_API_KEY)

(营销邮件和通知邮件中必须包含退订链接——这是符合 CAN-SPAM 规范的要求)

(所有邮件模板都必须使用带类型的 props 接口——以便在编译时进行验证)

不遵守这些规则将导致邮件发送失败、安全漏洞或法律合规问题。

</critical_reminders>


来源

评论

支持 Markdown