关于 send-email
send-email 是面向开发者的 Resend 邮件发送技能,涵盖单封与批量邮件的实现选择及生产注意事项。它还说明重试、投递能力、模板和测试方法。
主要功能
- 01单封与批量发送选择
- 02幂等键与错误重试建议
- 03附件、定时发送与模板
- 04投递事件和标签说明
- 05投递测试与送达率建议
适用场景
- 01发送事务性邮件或附件邮件
- 02一次提交多封通知邮件
- 03处理限流和服务器错误重试
- 04测试退信、投诉与投递事件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ resend/ resend-skills --skill send-email安装后在 Claude Code 中输入/send-email确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/batch-email-examples.mdbest-practices.mdinstallation.mdsingle-email-examples.mdwebhooks.md详细介绍
使用 Resend 发送邮件
概述
Resend 提供两个用于发送邮件的端点:
| 方式 | 端点 | 使用场景 |
|---|---|---|
| 单封 | POST /emails | 单封事务性邮件、带附件的邮件、定时发送 |
| 批量 | POST /emails/batch | 在一次请求中发送多封不同的邮件(最多 100 封)、批量通知 |
在以下情况下选择批量发送:
- 一次发送 2 封或更多不同的邮件
- 减少 API 调用很重要(默认速率限制为每秒 2 次请求)
- 不需要附件或定时发送
在以下情况下选择单封发送:
- 发送一封邮件
- 邮件需要附件
- 邮件需要定时发送
- 不同收件人需要不同的发送时间
快速开始
- 检测项目语言,查看配置文件(package.json、requirements.txt、go.mod 等)
- 安装 SDK(首选)或使用 cURL——参见 references/installation.md
- 根据上述决策表选择单封或批量发送
- 实施最佳实践——幂等键、错误处理、重试
最佳实践(生产环境至关重要)
在生产环境发送邮件时,务必实施以下做法。完整实现请参见 references/best-practices.md。
幂等键
重试失败的请求时,防止重复发送邮件。
| 键事实 | |
|---|---|
| 格式(单封) | <event-type>/<entity-id>(例如,welcome-email/user-123) |
| 格式(批量) | batch-<event-type>/<batch-id>(例如,batch-orders/batch-456) |
| 有效期 | 24 小时 |
| 最大长度 | 256 个字符 |
| 重复的负载 | 返回原始响应,不会重新发送 |
| 不同的负载 | 返回 409 错误 |
错误处理
| 代码 | 操作 |
|---|---|
| 400、422 | 修正请求参数,不要重试 |
| 401、403 | 检查 API 密钥 / 验证域名,不要重试 |
| 409 | 幂等性冲突——使用新键或修正负载 |
| 429 | 触发速率限制——采用指数退避重试(默认速率限制为每秒 2 次请求) |
| 500 | 服务器错误——采用指数退避重试 |
重试策略
- 退避: 指数退避(1 秒、2 秒、4 秒……)
- 最大重试次数: 大多数场景下为 3–5 次
- 仅重试: 429(速率限制)和 500(服务器错误)
- 重试时始终使用: 幂等键
单封邮件
端点: POST /emails(优先使用 SDK,而非 cURL)
必需参数
| 参数 | 类型 | 描述 |
|---|---|---|
from | string | 发件人地址。格式:"Name <[email protected]>" |
to | string[] | 收件人地址(最多 50 个) |
subject | string | 邮件主题 |
html 或 text | string | 邮件正文内容 |
可选参数
| 参数 | 类型 | 描述 |
|---|---|---|
cc | string[] | 抄送收件人 |
bcc | string[] | 密送收件人 |
reply_to* | string[] | 回复地址 |
scheduled_at* | string | 定时发送时间(ISO 8601) |
attachments | array | 文件附件(总计最多 40MB) |
tags | array | 用于跟踪的键值对(参见 标签) |
headers | object | 自定义标头 |
*参数命名因 SDK 而异(例如,Node.js 中为 replyTo,Python 中为 reply_to)。
最简示例(Node.js)
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send(
{
from: 'Acme <[email protected]>',
to: ['[email protected]'],
subject: 'Hello World',
html: '<p>Email body here</p>',
},
{ idempotencyKey: `welcome-email/${userId}` }
);
if (error) {
console.error('Failed:', error.message);
return;
}
console.log('Sent:', data.id);
所有包含错误处理和重试逻辑的 SDK 实现,请参见 references/single-email-examples.md。
批量邮件
端点: POST /emails/batch(但优先使用 SDK,而非 cURL)
限制
- 不支持附件——带附件的邮件请使用单封发送
- 不支持定时发送——定时邮件请使用单封发送
- 原子性——如果一封邮件未通过验证,整个批次都会失败
- 每次请求最多 100 封邮件
- 批次中的每封邮件最多包含 50 位收件人
预验证
由于任何验证错误都会导致整个批次发送失败,请在发送前验证所有邮件:
- 检查必填字段(from、to、subject、html/text)
- 验证邮件格式
- 确保批次大小 <= 100
最简示例(Node.js)
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.batch.send(
[
{
from: 'Acme <[email protected]>',
to: ['[email protected]'],
subject: 'Order Shipped',
html: '<p>Your order has shipped!</p>',
},
{
from: 'Acme <[email protected]>',
to: ['[email protected]'],
subject: 'Order Confirmed',
html: '<p>Your order is confirmed!</p>',
},
],
{ idempotencyKey: `batch-orders/${batchId}` }
);
if (error) {
console.error('Batch failed:', error.message);
return;
}
console.log('Sent:', data.map(e => e.id));
有关包含验证、错误处理和重试逻辑的所有 SDK 实现,请参阅 references/batch-email-examples.md。
大批量发送(100+ 封邮件)
发送超过 100 封邮件时,请拆分为多个批次请求:
- 拆分为多个分块,每块 100 封邮件
- 为每个分块使用唯一的幂等键:
<batch-prefix>/chunk-<index> - 并行发送各分块,以提高吞吐量
- 跟踪每个分块的结果,以处理部分失败
有关完整的分块实现,请参阅 references/batch-email-examples.md。
投递能力
遵循以下做法,以尽可能提高邮件进入收件箱的概率。
如需更多投递能力方面的帮助,请通过 npx skills add resend/email-best-practices 安装 email-best-practices 技能。
必须遵循
| 做法 | 原因 |
|---|---|
| 有效的 SPF、DKIM、DMARC 记录 | 对邮件进行身份验证并防止伪造 |
| 链接与发件域名一致 | 如果发件地址来自 @acme.com,链接应指向 https://acme.com——域名不匹配会触发垃圾邮件过滤器 |
| 包含纯文本版本 | 为了提高无障碍性和投递能力,请同时使用 html 和 text 参数(如果未提供,Resend 会生成纯文本版本) |
| 避免使用“no-reply”地址 | 使用真实地址(例如 support@),有助于提升信任度 |
| 正文少于 102KB | Gmail 会截断较大的邮件 |
建议遵循
| 做法 | 原因 |
|---|---|
| 使用子域名 | 用 notifications.acme.com 发送事务性邮件,用 mail.acme.com 发送营销邮件——以保护域名声誉 |
| 为事务性邮件停用跟踪 | 开启/点击跟踪可能会导致密码重置、收据等邮件触发垃圾邮件过滤器 |
跟踪(打开和点击)
跟踪在 Resend 控制面板的域名级别进行配置,而非针对单封邮件配置。
| 设置 | 工作方式 | 建议 |
|---|---|---|
| 打开跟踪 | 插入一个 1x1 透明像素 | 对事务性邮件停用,以免影响投递能力 |
| 点击跟踪 | 通过重定向改写链接 | 对敏感邮件(密码重置、安全警报)停用 |
适合启用跟踪的情况:
- 关注互动指标的营销邮件
- 新闻简报和公告
适合停用跟踪的情况:
- 事务性邮件(收据、确认邮件、密码重置)
- 涉及安全敏感内容的邮件
- 优先考虑尽可能提高投递能力时
通过控制面板配置:Domain → Configuration → Click/Open Tracking
Webhook(事件通知)
使用 webhook 实时跟踪邮件投递状态。事件发生时,Resend 会向你的端点发送 HTTP POST 请求。
| 事件 | 使用时机 |
|---|---|
email.delivered | 确认成功投递 |
email.bounced | 从邮件列表中移除,并提醒用户 |
email.complained | 取消订阅用户(垃圾邮件投诉) |
email.opened / email.clicked | 跟踪互动情况(仅限营销邮件) |
务必验证每个请求的 webhook 签名。 如果不验证,任何人都可以向你的端点发送伪造事件。
有关设置、签名验证代码和所有事件类型,请参阅 references/webhooks.md。
标签
标签是键值对,可帮助你跟踪和筛选邮件。
tags: [
{ name: 'user_id', value: 'usr_123' },
{ name: 'email_type', value: 'welcome' },
{ name: 'plan', value: 'enterprise' }
]
使用场景:
- 将邮件与系统中的客户关联
- 按邮件类型分类(欢迎邮件、收据、密码重置)
- 在 Resend 控制面板中筛选邮件
- 将 webhook 事件关联回你的应用程序
**限制:**标签名称和值只能包含 ASCII 字母、数字、下划线或连字符。每项最多 256 个字符。
模板
使用预构建模板,而不是在每次请求中发送 HTML。
const { data, error } = await resend.emails.send({
from: 'Acme <[email protected]>',
to: ['[email protected]'],
subject: 'Welcome!',
template: {
id: 'tmpl_abc123', // or alias: 'welcome-email'
variables: {
USER_NAME: 'John', // Case-sensitive! Must match template exactly.
ORDER_TOTAL: '$99.00'
}
}
});
注意:变量名区分大小写,且必须与模板定义完全一致。大小写形式不限——USER_NAME、userName 或 user_name 均可,只要发送调用中使用的大小写与定义一致。
| 事实 | 详情 |
|---|---|
| 保留名称 | FIRST_NAME、LAST_NAME、EMAIL、UNSUBSCRIBE_URL、contact、this |
| 回退值 | 可选——如果未设置且发送时缺少变量,发送将失败(422) |
| 不能与以下参数组合使用 | html、text 或 react 参数 |
| subject / from | 可在每次发送时覆盖模板默认值 |
模板必须先发布才能使用。草稿模板无法发送。
若要通过 API 创建、更新、发布或删除模板,请使用 templates 技能。
测试
避免使用虚假地址在真实邮件服务商处进行测试。
使用 [email protected]、[email protected] 或 [email protected] 之类的地址会:
- 退信——这些地址并不存在
- 损害发件人信誉——高退信率会触发垃圾邮件过滤器
- 导致域名被列入屏蔽名单——服务商会标记退信率高的域名
安全的测试选项
| 方法 | 地址 | 结果 |
|---|---|---|
| 已送达 | [email protected] | 模拟成功送达 |
| 退信 | [email protected] | 模拟硬退信 |
| 投诉 | [email protected] | 模拟垃圾邮件投诉 |
| 你自己的邮箱 | 你的实际地址 | 真实送达测试 |
**开发环境:**使用 resend.dev 测试地址模拟不同场景,避免影响发件人信誉。
**预发布环境:**发送到你能控制的真实地址(团队成员、你拥有的测试账户)。
域名预热
新域名必须逐步增加发送量,以建立信誉。
**重要原因:**新域名突然发送大量邮件会触发垃圾邮件过滤器。ISP 预期发送量会逐步增长。
推荐计划
现有域名
| 天数 | 每日邮件数 | 每小时邮件数 |
|---|---|---|
| 1 | 最多 1,000 封邮件 | 最多 100 封 |
| 2 | 最多 2,500 封邮件 | 最多 300 封 |
| 3 | 最多 5,000 封邮件 | 最多 600 封 |
| 4 | 最多 5,000 封邮件 | 最多 800 封 |
| 5 | 最多 7,500 封邮件 | 最多 1,000 封 |
| 6 | 最多 7,500 封邮件 | 最多 1,500 封 |
| 7 | 最多 10,000 封邮件 | 最多 2,000 封 |
新域名
| 天数 | 每日邮件数 | 每小时邮件数 |
|---|---|---|
| 1 | 最多 150 封邮件 | |
| 2 | 最多 250 封邮件 | |
| 3 | 最多 400 封邮件 | |
| 4 | 最多 700 封邮件 | 最多 50 封 |
| 5 | 最多 1,000 封邮件 | 最多 75 封 |
| 6 | 最多 1,500 封邮件 | 最多 100 封 |
| 7 | 最多 2,000 封邮件 | 最多 150 封 |
监控以下指标
| 指标 | 目标 | 超出目标时的操作 |
|---|---|---|
| 退信率 | < 4% | 放慢发送速度,清理邮件列表 |
| 垃圾邮件投诉率 | < 0.08% | 放慢发送速度,检查内容 |
**不要使用第三方预热服务。**重点向真实且积极互动的收件人发送相关内容。
抑制列表
Resend 会自动管理一份抑制列表,其中列出不应接收邮件的地址。
以下情况会将地址添加到列表:
- 邮件发生硬退信(地址不存在)
- 收件人将邮件标记为垃圾邮件
- 你通过控制台手动添加地址
**处理方式:**Resend 不会尝试向受抑制的地址投递邮件,而是触发 email.suppressed webhook 事件。
**重要原因:**继续向退信或投诉过的地址发送邮件会损害你的信誉。抑制列表会自动保护你。
**管理:**在 Resend 控制台的 Suppressions 下查看和管理受抑制的地址。
常见错误
| 错误 | 修正方法 |
|---|---|
| 重试时未使用幂等键 | 始终包含幂等键——防止重试时重复发送 |
| 使用批量发送来发送带附件的邮件 | 批量发送不支持附件——请改用单次发送 |
| 发送前未验证批次 | 先验证所有邮件——一封无效邮件就会导致整个批次失败 |
| 重试 400/422 错误 | 这些是验证错误——请修正请求,不要重试 |
| 相同的幂等键,不同的负载 | 会返回 409 错误——每种不同的邮件内容都使用唯一的键 |
| 为事务性邮件启用跟踪 | 对密码重置邮件、收据禁用打开/点击跟踪——否则会损害送达率 |
| 使用“no-reply”发件人地址 | 使用 support@ 这样的真实地址——有助于提升邮件服务商对你的信任 |
| 未验证 Webhook 签名 | 始终进行验证——未经验证的事件不可信 |
| 使用虚假邮箱([email protected])测试 | 使用 [email protected]——虚假地址会退信并损害发件人信誉 |
| 模板变量名称不匹配 | 变量名称区分大小写——必须与模板定义完全一致。大小写格式不限;只要发送调用中的名称匹配,USER_NAME 和 firstName 都可以使用。 |
| 从新域名发送大量邮件 | 逐步预热——流量突然激增会触发垃圾邮件过滤器 |
备注
from地址必须使用已验证的域名- 如果发件地址无法接收回复,请将
reply_to参数设置为有效地址。 - 将 API 密钥存储在
RESEND_API_KEY环境变量中 - Node.js SDK 的
react参数支持 React Email 组件 - Resend 在响应中返回
error、data、headers。 - 成功时,Data 会返回
{ id: "email-id" }(单次发送)或 ID 数组(批量发送) - 对于面向大型列表的营销活动,请改用 Resend Broadcasts