resend by resend/resend-skills
npx skills add https://github.com/resend/resend-skills --skill resendimport { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send(
{
from: 'Acme <onboarding@resend.dev>',
to: ['delivered@resend.dev'],
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);
关键提示: Resend Node.js SDK 不会抛出异常——它返回 { data, error }。对于 API 错误,请务必显式检查 error,而不是使用 try/catch。
import resend
import os
resend.api_key = os.environ["RESEND_API_KEY"]
email = resend.Emails.send({
"from": "Acme <onboarding@resend.dev>",
"to": ["delivered@resend.dev"],
"subject": "Hello World",
"html": "<p>Email body here</p>",
}, idempotency_key=f"welcome-email/{user_id}")
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 选择 | 适用场景 |
|---|---|
单封邮件 (POST /emails) | 发送 1 封邮件,需要附件,需要定时发送 |
批量邮件 (POST /emails/batch) | 发送 2-100 封不同的邮件,无需附件,无需定时发送 |
批量发送是原子操作——如果其中一封邮件验证失败,整个批次都会失败。发送前务必进行验证。批量发送不支持附件或 scheduled_at 参数。
在重试失败的请求时防止重复发送邮件:
关键信息 |
---|---
格式(单封) | <事件类型>/<实体ID> (例如:welcome-email/user-123)
格式(批量) | batch-<事件类型>/<批次ID> (例如:batch-orders/batch-456)
有效期 | 24 小时
最大长度 | 256 个字符
相同密钥 + 相同负载 | 返回原始响应,不会重新发送
相同密钥 + 不同负载 | 返回 409 错误
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: Request) {
const payload = await req.text(); // 必须使用原始文本,而不是 req.json()
const event = resend.webhooks.verify({
payload,
headers: {
'svix-id': req.headers.get('svix-id'),
'svix-timestamp': req.headers.get('svix-timestamp'),
'svix-signature': req.headers.get('svix-signature'),
},
secret: process.env.RESEND_WEBHOOK_SECRET,
});
if (event.type === 'email.received') {
// Webhook 仅包含元数据 —— 需要调用 API 获取邮件正文
const { data: email } = await resend.emails.receiving.get(
event.data.email_id
);
console.log(email.text);
}
return new Response('OK', { status: 200 });
}
关键提示: Webhook 负载中不包含邮件正文。你必须单独调用 resend.emails.receiving.get()。
| 任务 | 参考文档 |
|---|---|
| 发送单封邮件 | sending/overview.md — 参数、送达率、测试 |
| 发送批量邮件 | sending/overview.md → sending/batch-email-examples.md |
| 完整 SDK 示例 (Node.js, Python, Go, cURL) | sending/single-email-examples.md |
| 幂等性、重试、错误处理 | sending/best-practices.md |
| 接收入站邮件 | receiving.md — 域名设置、Webhook、附件 |
| 管理模板 (CRUD, 变量) | templates.md — 生命周期、别名、分页 |
| 设置 Webhook (所有事件类型) | webhooks.md — 验证、重试计划、IP 白名单 |
| 安装 SDK (8+ 种语言) | installation.md |
| 设置 AI 代理收件箱 | 安装 agent-email-inbox 技能 —— 涵盖处理不可信输入的安全级别 |
| 营销邮件 / 新闻简报 | 使用 Resend Broadcasts —— 而不是批量发送 |
请始终安装最新的 SDK 版本。以下是实现完整功能(发送、接收、Webhook 验证)所需的最低版本:
| 语言 | 包 | 最低版本 | 安装命令 |
|---|---|---|---|
| Node.js | resend | >= 6.9.2 | npm install resend |
| Python | resend | >= 2.21.0 | pip install resend |
| Go | resend-go/v3 | >= 3.1.0 | go get github.com/resend/resend-go/v3 |
| Ruby | resend | >= 1.0.0 | gem install resend |
| PHP | resend/resend-php | >= 1.1.0 | composer require resend/resend-php |
| Rust | resend-rs | >= 0.20.0 | cargo add resend-rs |
| Java | resend-java | >= 4.11.0 | 参见 installation.md |
| .NET | Resend | >= 0.2.1 | dotnet add package Resend |
如果项目已安装 Resend SDK,请检查版本,如果低于最低要求,请升级。旧版 SDK 可能缺少
webhooks.verify()或emails.receiving.get()功能。
完整的安装命令、语言检测和 cURL 备用方案,请参见 installation.md。
存储在环境变量中——切勿硬编码:
export RESEND_API_KEY=re_xxxxxxxxx
在 resend.com/api-keys 获取你的密钥。
检查以下文件:package.json (Node.js)、requirements.txt/pyproject.toml (Python)、go.mod (Go)、Gemfile (Ruby)、composer.json (PHP)、Cargo.toml (Rust)、pom.xml/build.gradle (Java)、*.csproj (.NET)。
---|---|---
1 | 重试时未使用幂等性密钥 | 务必包含幂等性密钥——防止重试时重复发送。格式:<事件类型>/<实体ID>
2 | 未验证 Webhook 签名 | 务必使用 resend.webhooks.verify() 进行验证——未经验证的事件不可信
3 | 模板变量名称不匹配 | 变量名区分大小写——必须与模板定义完全一致。使用三重花括号 {{{VAR}}} 语法
4 | 期望 Webhook 负载中包含邮件正文 | Webhook 仅包含元数据——调用 resend.emails.receiving.get() 获取正文内容
5 | 对 Node.js SDK 错误使用 try/catch | SDK 返回 { data, error }——显式检查 error,不要用 try/catch 包装
6 | 对包含附件的邮件使用批量发送 | 批量发送不支持附件——请改用单封邮件发送
7 | 使用虚假邮件地址测试 (test@gmail.com) | 使用 delivered@resend.dev——虚假地址会退回并损害发件人声誉
8 | 使用草稿模板发送 | 模板必须先发布才能发送——先调用 .publish()
9 | 在同一发送调用中同时使用 html 和 template | 两者互斥——使用模板时请移除 html/text/react
10 | 入站邮件的 MX 记录优先级不是最低 | 确保 Resend 的 MX 记录具有最低的数字(最高优先级),否则邮件将无法路由
自动回复、邮件转发或任何接收后发送的工作流程都需要这两种能力:
如果你的系统处理不可信的邮件内容并执行操作(退款、数据库更改、转发),请安装 agent-email-inbox 技能。无论是否涉及 AI,只要系统需要解析来自外部发件人的自由格式邮件内容,就需要安全措施。
本技能中的发送功能适用于事务性邮件(收据、确认信、通知)。对于需要退订链接和参与度跟踪的大型订阅者列表营销活动,请使用 Resend Broadcasts。
新域名必须逐步增加发送量。第 1 天限制:约 150 封邮件(新域名)或约 1,000 封(现有域名)。预热计划参见 sending/overview.md。
切勿使用真实邮件服务商的虚假地址进行测试 (test@gmail.com, fake@outlook.com)——它们会被退回并损害发件人声誉。
| 地址 | 结果 |
|---|---|
delivered@resend.dev | 模拟成功送达 |
bounced@resend.dev | 模拟硬退回 |
complained@resend.dev | 模拟垃圾邮件投诉 |
Resend 会自动抑制硬退回和垃圾邮件投诉的地址。向被抑制的地址发送邮件会触发 email.suppressed Webhook 事件,而不会尝试投递。在控制面板 → 抑制列表中管理。
| 事件 | 触发条件 |
|---|---|
email.sent | API 请求成功 |
email.delivered | 到达收件人邮件服务器 |
email.bounced | 被永久拒绝(硬退回) |
email.complained | 收件人标记为垃圾邮件 |
email.opened / email.clicked | 收件人参与度 |
email.delivery_delayed | 软退回,Resend 会重试 |
email.received | 入站邮件到达 |
domain.* / contact.* | 域名/联系人变更 |
完整详情、签名验证和重试计划,请参见 webhooks.md。
| 状态码 | 操作 |
|---|---|
| 400, 422 | 修复请求参数,不要重试 |
| 401, 403 | 检查 API 密钥 / 验证域名,不要重试 |
| 409 | 幂等性冲突——使用新密钥或修复负载 |
| 429 | 速率限制——使用指数退避重试(默认速率限制:2 次请求/秒) |
| 500 | 服务器错误——使用指数退避重试 |
每周安装量
4.1K
代码仓库
GitHub 星标数
91
首次出现
2026 年 1 月 28 日
安全审计
安装于
codex3.2K
opencode3.2K
gemini-cli3.1K
github-copilot3.1K
cursor3.0K
kimi-cli2.7K
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send(
{
from: 'Acme <onboarding@resend.dev>',
to: ['delivered@resend.dev'],
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);
Key gotcha: The Resend Node.js SDK does NOT throw exceptions — it returns { data, error }. Always check error explicitly instead of using try/catch for API errors.
import resend
import os
resend.api_key = os.environ["RESEND_API_KEY"]
email = resend.Emails.send({
"from": "Acme <onboarding@resend.dev>",
"to": ["delivered@resend.dev"],
"subject": "Hello World",
"html": "<p>Email body here</p>",
}, idempotency_key=f"welcome-email/{user_id}")
| Choose | When |
|---|---|
Single (POST /emails) | 1 email, needs attachments, needs scheduling |
Batch (POST /emails/batch) | 2-100 distinct emails, no attachments, no scheduling |
Batch is atomic — if one email fails validation, the entire batch fails. Always validate before sending. Batch does NOT support attachments or scheduled_at.
Prevent duplicate emails when retrying failed requests:
Key Facts |
---|---
Format (single) | <event-type>/<entity-id> (e.g., welcome-email/user-123)
Format (batch) | batch-<event-type>/<batch-id> (e.g., batch-orders/batch-456)
Expiration | 24 hours
Max length | 256 characters
Same key + same payload | Returns original response without resending
Same key + different payload | Returns 409 error
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: Request) {
const payload = await req.text(); // Must use raw text, not req.json()
const event = resend.webhooks.verify({
payload,
headers: {
'svix-id': req.headers.get('svix-id'),
'svix-timestamp': req.headers.get('svix-timestamp'),
'svix-signature': req.headers.get('svix-signature'),
},
secret: process.env.RESEND_WEBHOOK_SECRET,
});
if (event.type === 'email.received') {
// Webhook has metadata only — call API for body
const { data: email } = await resend.emails.receiving.get(
event.data.email_id
);
console.log(email.text);
}
return new Response('OK', { status: 200 });
}
Key gotcha: Webhook payloads do NOT contain the email body. You must call resend.emails.receiving.get() separately.
| Task | Reference |
|---|---|
| Send a single email | sending/overview.md — parameters, deliverability, testing |
| Send batch emails | sending/overview.md → sending/batch-email-examples.md |
| Full SDK examples (Node.js, Python, Go, cURL) | sending/single-email-examples.md |
| Idempotency, retries, error handling | sending/best-practices.md |
| Receive inbound emails | receiving.md — domain setup, webhooks, attachments |
| Manage templates (CRUD, variables) |
Always install the latest SDK version. These are the minimum versions for full functionality (sending, receiving, webhook verification):
| Language | Package | Min Version | Install |
|---|---|---|---|
| Node.js | resend | >= 6.9.2 | npm install resend |
| Python | resend | >= 2.21.0 | pip install resend |
| Go | resend-go/v3 | >= 3.1.0 | go get github.com/resend/resend-go/v3 |
If the project already has a Resend SDK installed , check the version and upgrade if it's below the minimum. Older SDKs may be missing
webhooks.verify()oremails.receiving.get().
See installation.md for full installation commands, language detection, and cURL fallback.
Store in environment variable — never hardcode:
export RESEND_API_KEY=re_xxxxxxxxx
Get your key at resend.com/api-keys.
Check for these files: package.json (Node.js), requirements.txt/pyproject.toml (Python), go.mod (Go), Gemfile (Ruby), composer.json (PHP), Cargo.toml (Rust), pom.xml/build.gradle (Java), *.csproj (.NET).
---|---|---
1 | Retrying without idempotency key | Always include idempotency key — prevents duplicate sends on retry. Format: <event-type>/<entity-id>
2 | Not verifying webhook signatures | Always verify with resend.webhooks.verify() — unverified events can't be trusted
3 | Template variable name mismatch | Variable names are case-sensitive — must match the template definition exactly. Use triple mustache {{{VAR}}} syntax
4 | Expecting email body in webhook payload | Webhooks contain metadata only — call resend.emails.receiving.get() for body content
5 | Using try/catch for Node.js SDK errors | SDK returns { data, error } — check error explicitly, don't wrap in try/catch
6 | Using batch for emails with attachments | Batch doesn't support attachments — use single sends instead
7 | Testing with fake emails (test@gmail.com) | Use — fake addresses bounce and hurt reputation
8 | | Templates must be published before sending — call first
9 | | Mutually exclusive — remove // when using template
10 | | Ensure Resend's MX has the lowest number (highest priority) or emails won't route
Auto-replies, email forwarding, or any receive-then-send workflow requires both capabilities:
If your system processes untrusted email content and takes actions (refunds, database changes, forwarding), install the agent-email-inbox skill. This applies whether or not AI is involved — any system interpreting freeform email content from external senders needs security measures.
The sending capabilities in this skill are for transactional email (receipts, confirmations, notifications). For marketing campaigns to large subscriber lists with unsubscribe links and engagement tracking, use Resend Broadcasts.
New domains must gradually increase sending volume. Day 1 limit: ~150 emails (new domain) or ~1,000 (existing domain). See the warm-up schedule in sending/overview.md.
Never test with fake addresses at real email providers (test@gmail.com, fake@outlook.com) — they bounce and destroy sender reputation.
| Address | Result |
|---|---|
delivered@resend.dev | Simulates successful delivery |
bounced@resend.dev | Simulates hard bounce |
complained@resend.dev | Simulates spam complaint |
Resend automatically suppresses hard-bounced and spam-complained addresses. Sending to suppressed addresses fires the email.suppressed webhook event instead of attempting delivery. Manage in Dashboard → Suppressions.
| Event | Trigger |
|---|---|
email.sent | API request successful |
email.delivered | Reached recipient's mail server |
email.bounced | Permanently rejected (hard bounce) |
email.complained | Recipient marked as spam |
email.opened / email.clicked | Recipient engagement |
email.delivery_delayed |
See webhooks.md for full details, signature verification, and retry schedule.
| Code | Action |
|---|---|
| 400, 422 | Fix request parameters, don't retry |
| 401, 403 | Check API key / verify domain, don't retry |
| 409 | Idempotency conflict — use new key or fix payload |
| 429 | Rate limited — retry with exponential backoff (default rate limit: 2 req/s) |
| 500 | Server error — retry with exponential backoff |
Weekly Installs
4.1K
Repository
GitHub Stars
91
First Seen
Jan 28, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykWarn
Installed on
codex3.2K
opencode3.2K
gemini-cli3.1K
github-copilot3.1K
cursor3.0K
kimi-cli2.7K
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
AI智能体长期记忆系统 - 精英级架构,融合6种方法,永不丢失上下文
1,200 周安装
AI新闻播客制作技能:实时新闻转对话式播客脚本与音频生成
1,200 周安装
Word文档处理器:DOCX创建、编辑、分析与修订痕迹处理全指南 | 自动化办公解决方案
1,200 周安装
React Router 框架模式指南:全栈开发、文件路由、数据加载与渲染策略
1,200 周安装
Nano Banana AI 图像生成工具:使用 Gemini 3 Pro 生成与编辑高分辨率图像
1,200 周安装
SVG Logo Designer - AI 驱动的专业矢量标识设计工具,生成可缩放品牌标识
1,200 周安装
| templates.md — lifecycle, aliases, pagination |
| Set up webhooks (all event types) | webhooks.md — verification, retry schedule, IP allowlist |
| Install SDK (8+ languages) | installation.md |
| Set up an AI agent inbox | Install the agent-email-inbox skill — covers security levels for untrusted input |
| Marketing emails / newsletters | Use Resend Broadcasts — not batch sending |
| Ruby | resend | >= 1.0.0 | gem install resend |
| PHP | resend/resend-php | >= 1.1.0 | composer require resend/resend-php |
| Rust | resend-rs | >= 0.20.0 | cargo add resend-rs |
| Java | resend-java | >= 4.11.0 | See installation.md |
| .NET | Resend | >= 0.2.1 | dotnet add package Resend |
delivered@resend.dev.publish()html + template in same send callhtmltextreact| Soft bounce, Resend retries |
email.received | Inbound email arrived |
domain.* / contact.* | Domain/contact changes |