send-email
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSend Email with Resend
使用Resend发送邮件
Overview
概述
Resend provides two endpoints for sending emails:
| Approach | Endpoint | Use Case |
|---|---|---|
| Single | | Individual transactional emails, emails with attachments, scheduled sends |
| Batch | | Multiple distinct emails in one request (max 100), bulk notifications |
Choose batch when:
- Sending 2+ distinct emails at once
- Reducing API calls is important (by default, rate limit is 2 requests per second)
- No attachments or scheduling needed
Choose single when:
- Sending one email
- Email needs attachments
- Email needs to be scheduled
- Different recipients need different timing
Resend提供两个用于发送邮件的端点:
| 方式 | 端点 | 使用场景 |
|---|---|---|
| 单次发送 | | 单个事务性邮件、带附件的邮件、定时发送的邮件 |
| 批量发送 | | 一次请求发送多封不同的邮件(最多100封)、批量通知 |
选择批量发送的场景:
- 同时发送2封及以上不同的邮件
- 减少API调用次数很重要(默认速率限制为每秒2次请求)
- 不需要附件或定时发送
选择单次发送的场景:
- 发送单封邮件
- 邮件需要包含附件
- 邮件需要定时发送
- 不同收件人需要不同的发送时间
Quick Start
快速开始
- Detect project language from config files (package.json, requirements.txt, go.mod, etc.)
- Install SDK (preferred) or use cURL - See references/installation.md
- Choose single or batch based on the decision matrix above
- Implement best practices - Idempotency keys, error handling, retries
- 从配置文件(package.json、requirements.txt、go.mod等)检测项目语言
- 安装SDK(推荐)或使用cURL - 详见 references/installation.md
- 根据上述决策矩阵选择单次或批量发送方式
- 实施最佳实践 - 幂等键、错误处理、重试机制
Best Practices (Critical for Production)
最佳实践(生产环境必备)
Always implement these for production email sending. See references/best-practices.md for complete implementations.
生产环境发送邮件时必须实施这些措施。完整实现详见 references/best-practices.md。
Idempotency Keys
幂等键
Prevent duplicate emails when retrying failed requests.
| Key Facts | |
|---|---|
| Format (single) | |
| Format (batch) | |
| Expiration | 24 hours |
| Max length | 256 characters |
| Duplicate payload | Returns original response without resending |
| Different payload | Returns 409 error |
在重试失败请求时防止重复发送邮件。
| 关键信息 | 说明 |
|---|---|
| 单次发送格式 | |
| 批量发送格式 | |
| 有效期 | 24小时 |
| 最大长度 | 256个字符 |
| 重复请求相同 payload | 返回原始响应,不重新发送邮件 |
| 重复请求不同 payload | 返回409错误 |
Error Handling
错误处理
| 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 (by default, rate limit is 2 requests/second) |
| 500 | Server error - retry with exponential backoff |
| 状态码 | 处理方式 |
|---|---|
| 400、422 | 修正请求参数,不要重试 |
| 401、403 | 检查API密钥/验证域名,不要重试 |
| 409 | 幂等键冲突 - 使用新密钥或修正请求内容 |
| 429 | 速率限制 - 使用指数退避策略重试(默认速率限制为每秒2次请求) |
| 500 | 服务器错误 - 使用指数退避策略重试 |
Retry Strategy
重试策略
- Backoff: Exponential (1s, 2s, 4s...)
- Max retries: 3-5 for most use cases
- Only retry: 429 (rate limit) and 500 (server error)
- Always use: Idempotency keys when retrying
- 退避方式: 指数退避(1秒、2秒、4秒……)
- 最大重试次数: 大多数场景下3-5次
- 仅重试以下错误: 429(速率限制)和500(服务器错误)
- 必须使用: 重试时务必携带幂等键
Single Email
单次发送邮件
Endpoint: (prefer SDK over cURL)
POST /emails端点: (优先使用SDK而非cURL)
POST /emailsRequired Parameters
必填参数
| Parameter | Type | Description |
|---|---|---|
| string | Sender address. Format: |
| string[] | Recipient addresses (max 50) |
| string | Email subject line |
| string | Email body content |
| 参数 | 类型 | 说明 |
|---|---|---|
| string | 发件人地址。格式: |
| string[] | 收件人地址(最多50个) |
| string | 邮件主题 |
| string | 邮件正文内容 |
Optional Parameters
可选参数
| Parameter | Type | Description |
|---|---|---|
| string[] | CC recipients |
| string[] | BCC recipients |
| string[] | Reply-to addresses |
| string | Schedule send time (ISO 8601) |
| array | File attachments (max 40MB total) |
| array | Key/value pairs for tracking (see Tags) |
| object | Custom headers |
*Parameter naming varies by SDK (e.g., in Node.js, in Python).
replyToreply_to| 参数 | 类型 | 说明 |
|---|---|---|
| string[] | 抄送收件人 |
| string[] | 密送收件人 |
| string[] | 回复地址 |
| string | 定时发送时间(ISO 8601格式) |
| array | 文件附件(总大小不超过40MB) |
| array | 用于追踪的键值对(详见 标签) |
| object | 自定义请求头 |
*参数命名因SDK而异(例如:Node.js中为,Python中为)。
replyToreply_toMinimal Example (Node.js)
最简示例(Node.js)
typescript
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);See references/single-email-examples.md for all SDK implementations with error handling and retry logic.
typescript
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);所有包含错误处理和重试逻辑的SDK实现示例详见 references/single-email-examples.md。
Batch Email
批量发送邮件
Endpoint: (but prefer SDK over cURL)
POST /emails/batch端点: (优先使用SDK而非cURL)
POST /emails/batchLimitations
限制
- No attachments - Use single sends for emails with attachments
- No scheduling - Use single sends for scheduled emails
- Atomic - If one email fails validation, the entire batch fails
- Max 100 emails per request
- Max 50 recipients per individual email in the batch
- 不支持附件 - 带附件的邮件请使用单次发送
- 不支持定时发送 - 定时邮件请使用单次发送
- 原子性 - 若某封邮件验证失败,整个批量请求都会失败
- 每请求最多100封邮件
- 批量中单个邮件最多50个收件人
Pre-validation
预验证
Since the entire batch fails on any validation error, validate all emails before sending:
- Check required fields (from, to, subject, html/text)
- Validate email formats
- Ensure batch size <= 100
由于单个邮件验证失败会导致整个批量请求失败,发送前请验证所有邮件:
- 检查必填字段(from、to、subject、html/text)
- 验证邮箱格式
- 确保批量大小不超过100封
Minimal Example (Node.js)
最简示例(Node.js)
typescript
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.batch.send(
[
{
from: 'Acme <notifications@acme.com>',
to: ['delivered@resend.dev'],
subject: 'Order Shipped',
html: '<p>Your order has shipped!</p>',
},
{
from: 'Acme <notifications@acme.com>',
to: ['delivered@resend.dev'],
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));See references/batch-email-examples.md for all SDK implementations with validation, error handling, and retry logic.
typescript
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.batch.send(
[
{
from: 'Acme <notifications@acme.com>',
to: ['delivered@resend.dev'],
subject: 'Order Shipped',
html: '<p>Your order has shipped!</p>',
},
{
from: 'Acme <notifications@acme.com>',
to: ['delivered@resend.dev'],
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。
Large Batches (100+ Emails)
大批次邮件(100封以上)
For sends larger than 100 emails, chunk into multiple batch requests:
- Split into chunks of 100 emails each
- Use unique idempotency keys per chunk:
<batch-prefix>/chunk-<index> - Send chunks in parallel for better throughput
- Track results per chunk to handle partial failures
See references/batch-email-examples.md for complete chunking implementations.
对于超过100封的邮件发送,需拆分为多个批量请求:
- 拆分为多个批次,每批100封邮件
- 每个批次使用唯一的幂等键:
<批量前缀>/chunk-<序号> - 并行发送批次以提升吞吐量
- 追踪每个批次的结果以处理部分失败的情况
完整的拆分实现示例详见 references/batch-email-examples.md。
Deliverability
邮件送达率
Follow these practices to maximize inbox placement.
For more help with deliverability, install the email-best-practices skill with .
npx skills add resend/email-best-practices遵循以下实践以最大化邮件进入收件箱的概率。
如需更多送达率相关帮助,可通过安装邮件最佳实践技能。
npx skills add resend/email-best-practicesRequired
必备实践
| Practice | Why |
|---|---|
| Valid SPF, DKIM, DMARC record | authenticate the email and prevent spoofing |
| Links match sending domain | If sending from |
| Include plain text version | Use both |
| Avoid "no-reply" addresses | Use real addresses (e.g., |
| Keep body under 102KB | Gmail clips larger messages |
| 实践 | 原因 |
|---|---|
| 配置有效的SPF、DKIM、DMARC记录 | 验证邮件合法性,防止邮件伪造 |
| 链接与发件域名匹配 | 若发件域为 |
| 包含纯文本版本 | 同时使用 |
| 避免使用"no-reply"地址 | 使用真实地址(例如: |
| 邮件正文大小不超过102KB | Gmail会截断更大的邮件 |
Recommended
推荐实践
| Practice | Why |
|---|---|
| Use subdomains | Send transactional from |
| Disable tracking for transactional | Open/click tracking can trigger spam filters for password resets, receipts, etc. |
| 实践 | 原因 |
|---|---|
| 使用子域名 | 事务性邮件从 |
| 事务性邮件禁用追踪 | 打开/点击追踪会触发垃圾邮件过滤器,不适用于密码重置、收据等邮件 |
Tracking (Opens & Clicks)
追踪(打开与点击)
Tracking is configured at the domain level in the Resend dashboard, not per-email.
| Setting | How it works | Recommendation |
|---|---|---|
| Open tracking | Inserts 1x1 transparent pixel | Disable for transactional emails - can hurt deliverability |
| Click tracking | Rewrites links through redirect | Disable for sensitive emails (password resets, security alerts) |
When to enable tracking:
- Marketing emails where engagement metrics matter
- Newsletters and announcements
When to disable tracking:
- Transactional emails (receipts, confirmations, password resets)
- Security-sensitive emails
- When maximizing deliverability is priority
Configure via dashboard: Domain → Configuration → Click/Open Tracking
追踪功能在Resend控制台中按域名级别配置,而非单封邮件级别。
| 设置 | 工作原理 | 建议 |
|---|---|---|
| 打开追踪 | 插入1x1透明像素 | 事务性邮件禁用 - 可能影响送达率 |
| 点击追踪 | 通过重写链接实现跳转 | 敏感邮件(密码重置、安全警报)禁用 |
建议启用追踪的场景:
- 需要关注参与度指标的营销邮件
- 新闻通讯和公告邮件
建议禁用追踪的场景:
- 事务性邮件(收据、确认邮件、密码重置)
- 安全敏感邮件
- 优先保障送达率的场景
配置方式:控制台 → 域名 → 配置 → 点击/打开追踪
Webhooks (Event Notifications)
Webhook(事件通知)
Track email delivery status in real-time using webhooks. Resend sends HTTP POST requests to your endpoint when events occur.
| Event | When to use |
|---|---|
| Confirm successful delivery |
| Remove from mailing list, alert user |
| Unsubscribe user (spam complaint) |
| Track engagement (marketing only) |
CRITICAL: Always verify webhook signatures. Without verification, attackers can send fake events to your endpoint.
See references/webhooks.md for setup, signature verification code, and all event types.
使用Webhook实时追踪邮件送达状态。当事件发生时,Resend会向你的端点发送HTTP POST请求。
| 事件 | 使用场景 |
|---|---|
| 确认邮件成功送达 |
| 从邮件列表中移除收件人、提醒用户 |
| 取消用户订阅(垃圾邮件投诉) |
| 追踪用户参与度(仅营销邮件) |
重要提示:务必验证Webhook签名。 若不验证,攻击者可能向你的端点发送伪造事件。
Webhook设置、签名验证代码及所有事件类型详见 references/webhooks.md。
Tags
标签
Tags are key/value pairs that help you track and filter emails.
typescript
tags: [
{ name: 'user_id', value: 'usr_123' },
{ name: 'email_type', value: 'welcome' },
{ name: 'plan', value: 'enterprise' }
]Use cases:
- Associate emails with customers in your system
- Categorize by email type (welcome, receipt, password-reset)
- Filter emails in the Resend dashboard
- Correlate webhook events back to your application
Constraints: Tag names and values can only contain ASCII letters, numbers, underscores, or dashes. Max 256 characters each.
标签是用于追踪和筛选邮件的键值对。
typescript
tags: [
{ name: 'user_id', value: 'usr_123' },
{ name: 'email_type', value: 'welcome' },
{ name: 'plan', value: 'enterprise' }
]使用场景:
- 将邮件与系统中的客户关联
- 按邮件类型分类(欢迎邮件、收据、密码重置)
- 在Resend控制台中筛选邮件
- 将Webhook事件与应用程序关联
约束: 标签名称和值只能包含ASCII字母、数字、下划线或连字符。每个标签最大长度为256个字符。
Templates
邮件模板
Use pre-built templates instead of sending HTML with each request.
typescript
const { data, error } = await resend.emails.send({
from: 'Acme <hello@acme.com>',
to: ['delivered@resend.dev'],
subject: 'Welcome!',
template: {
id: 'tmpl_abc123',
variables: {
USER_NAME: 'John', // Case-sensitive!
ORDER_TOTAL: '$99.00'
}
}
});IMPORTANT: Variable names are case-sensitive and must match exactly as defined in the template editor. ≠ .
USER_NAMEuser_name| Fact | Detail |
|---|---|
| Max variables | 20 per template |
| Reserved names | |
| Fallback values | Optional - if not set and variable missing, send fails |
| Can't combine with | |
Templates must be published in the dashboard before use. Draft templates won't work.
使用预构建模板代替每次请求都发送HTML内容。
typescript
const { data, error } = await resend.emails.send({
from: 'Acme <hello@acme.com>',
to: ['delivered@resend.dev'],
subject: 'Welcome!',
template: {
id: 'tmpl_abc123',
variables: {
USER_NAME: 'John', // 区分大小写!
ORDER_TOTAL: '$99.00'
}
}
});重要提示: 变量名称区分大小写,必须与模板编辑器中定义的完全一致。 ≠ 。
USER_NAMEuser_name| 信息 | 详情 |
|---|---|
| 最大变量数 | 每个模板最多20个 |
| 保留名称 | |
| 回退值 | 可选 - 若未设置且变量缺失,发送会失败 |
| 不可与以下参数同时使用 | |
模板必须在控制台中发布后方可使用。草稿模板无法使用。
Testing
测试
WARNING: Never test with fake addresses at real email providers.
Using addresses like , , or will:
test@gmail.comexample@outlook.comfake@yahoo.com- Bounce - These addresses don't exist
- Destroy your sender reputation - High bounce rates trigger spam filters
- Get your domain blocklisted - Providers flag domains with high bounce rates
警告:切勿使用真实邮件服务商的虚假地址进行测试。
使用、或这类地址会导致:
test@gmail.comexample@outlook.comfake@yahoo.com- 邮件退回 - 这些地址不存在
- 破坏发件人声誉 - 高退信率会触发垃圾邮件过滤器
- 域名被列入黑名单 - 邮件服务商会标记高退信率的域名
Safe Testing Options
安全测试选项
| Method | Address | Result |
|---|---|---|
| Delivered | | Simulates successful delivery |
| Bounced | | Simulates hard bounce |
| Complained | | Simulates spam complaint |
| Your own email | Your actual address | Real delivery test |
For development: Use the test addresses to simulate different scenarios without affecting your reputation.
resend.devFor staging: Send to real addresses you control (team members, test accounts you own).
| 方式 | 地址 | 结果 |
|---|---|---|
| 模拟成功送达 | | 模拟邮件成功送达 |
| 模拟退回 | | 模拟硬退回 |
| 模拟垃圾邮件投诉 | | 模拟用户标记为垃圾邮件 |
| 个人真实邮箱 | 你自己的真实邮箱 | 真实送达测试 |
开发环境: 使用测试地址模拟不同场景,不会影响你的发件人声誉。
resend.dev** staging环境:** 发送到你控制的真实地址(团队成员邮箱、你拥有的测试账户)。
Domain Warm-up
域名预热
New domains must gradually increase sending volume to establish reputation.
Why it matters: Sudden high volume from a new domain triggers spam filters. ISPs expect gradual growth.
新域名需逐步提升发送量以建立良好声誉。
重要性: 新域名突然发送大量邮件会触发垃圾邮件过滤器。邮件服务商期望发送量逐步增长。
Recommended Schedule
推荐预热计划
Existing domain
| Day | Messages per day | Messages per hour |
|---|---|---|
| 1 | Up to 1,000 emails | 100 Maximum |
| 2 | Up to 2,500 emails | 300 Maximum |
| 3 | Up to 5,000 emails | 600 Maximum |
| 4 | Up to 5,000 emails | 800 Maximum |
| 5 | Up to 7,500 emails | 1,000 Maximum |
| 6 | Up to 7,500 emails | 1,500 Maximum |
| 7 | Up to 10,000 emails | 2,000 Maximum |
New domain
| Day | Messages per day | Messages per hour |
|---|---|---|
| 1 | Up to 150 emails | |
| 2 | Up to 250 emails | |
| 3 | Up to 400 emails | |
| 4 | Up to 700 emails | 50 Maximum |
| 5 | Up to 1,000 emails | 75 Maximum |
| 6 | Up to 1,500 emails | 100 Maximum |
| 7 | Up to 2,000 emails | 150 Maximum |
已有域名
| 天数 | 每日发送量 | 每小时发送量上限 |
|---|---|---|
| 1 | 最多1000封 | 最多100封 |
| 2 | 最多2500封 | 最多300封 |
| 3 | 最多5000封 | 最多600封 |
| 4 | 最多5000封 | 最多800封 |
| 5 | 最多7500封 | 最多1000封 |
| 6 | 最多7500封 | 最多1500封 |
| 7 | 最多10000封 | 最多2000封 |
新域名
| 天数 | 每日发送量 | 每小时发送量上限 |
|---|---|---|
| 1 | 最多150封 | 无 |
| 2 | 最多250封 | 无 |
| 3 | 最多400封 | 无 |
| 4 | 最多700封 | 最多50封 |
| 5 | 最多1000封 | 最多75封 |
| 6 | 最多1500封 | 最多100封 |
| 7 | 最多2000封 | 最多150封 |
Monitor These Metrics
监控指标
| Metric | Target | Action if exceeded |
|---|---|---|
| Bounce rate | < 4% | Slow down, clean list |
| Spam complaint rate | < 0.08% | Slow down, review content |
Don't use third-party warm-up services. Focus on sending relevant content to real, engaged recipients.
| 指标 | 目标值 | 超出后的操作 |
|---|---|---|
| 退信率 | < 4% | 降低发送速度,清理邮件列表 |
| 垃圾邮件投诉率 | < 0.08% | 降低发送速度,检查邮件内容 |
不要使用第三方预热服务。 专注于向真实、活跃的收件人发送相关内容。
Suppression List
抑制列表
Resend automatically manages a suppression list of addresses that should not receive emails.
Addresses are added when:
- Email hard bounces (address doesn't exist)
- Recipient marks email as spam
- You manually add them via dashboard
What happens: Resend won't attempt delivery to suppressed addresses. The webhook event fires instead.
email.suppressedWhy this matters: Continuing to send to bounced/complained addresses destroys your reputation. The suppression list protects you automatically.
Management: View and manage suppressed addresses in the Resend dashboard under Suppressions.
Resend会自动管理一个抑制列表,包含不应再接收邮件的地址。
地址被加入列表的场景:
- 邮件硬退回(地址不存在)
- 收件人将邮件标记为垃圾邮件
- 你通过控制台手动添加
处理方式: Resend不会尝试向抑制列表中的地址发送邮件。会触发 Webhook事件。
email.suppressed重要性: 继续向退回/投诉地址发送邮件会严重破坏你的发件人声誉。抑制列表会自动保护你。
管理方式: 在Resend控制台的"抑制列表"中查看和管理被抑制的地址。
Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
| Retrying without idempotency key | Always include idempotency key - prevents duplicate sends on retry |
| Using batch for emails with attachments | Batch doesn't support attachments - use single sends instead |
| Not validating batch before send | Validate all emails first - one invalid email fails the entire batch |
| Retrying 400/422 errors | These are validation errors - fix the request, don't retry |
| Same idempotency key, different payload | Returns 409 error - use unique key per unique email content |
| Tracking enabled for transactional emails | Disable open/click tracking for password resets, receipts - hurts deliverability |
| Using "no-reply" sender address | Use real address like |
| Not verifying webhook signatures | Always verify - attackers can send fake events to your endpoint |
| Testing with fake emails (test@gmail.com) | Use |
| Template variable name mismatch | Variable names are case-sensitive - |
| Sending high volume from new domain | Warm up gradually - sudden spikes trigger spam filters |
| 错误 | 修复方式 |
|---|---|
| 重试时未携带幂等键 | 始终包含幂等键 - 防止重试时重复发送邮件 |
| 使用批量发送带附件的邮件 | 批量发送不支持附件 - 改用单次发送 |
| 发送前未验证批量邮件 | 先验证所有邮件 - 单个无效邮件会导致整个批量请求失败 |
| 重试400/422错误 | 这些是验证错误 - 修正请求内容,不要重试 |
| 同一幂等键对应不同请求内容 | 返回409错误 - 每个不同的邮件内容使用唯一的幂等键 |
| 事务性邮件启用追踪 | 禁用打开/点击追踪 - 会影响送达率 |
| 使用"no-reply"发件地址 | 使用真实地址如 |
| 未验证Webhook签名 | 务必验证 - 攻击者可能发送伪造事件到你的端点 |
| 使用虚假邮箱测试(如test@gmail.com) | 使用 |
| 模板变量名称不匹配 | 变量名称区分大小写 - |
| 新域名突然发送大量邮件 | 逐步预热 - 发送量突增会触发垃圾邮件过滤器 |
Notes
注意事项
- The address must use a verified domain
from - If the sending address cannot receive replies, set the parameter to a valid address.
reply_to - Store API key in environment variable
RESEND_API_KEY - Node.js SDK supports parameter for React Email components
react - Resend returns ,
error,datain the response.headers - Data returns on success (single) or array of IDs (batch)
{ id: "email-id" } - For marketing campaigns to large lists, use Resend Broadcasts instead
- 地址必须使用已验证的域名
from - 若发件地址无法接收回复,请将参数设置为有效地址
reply_to - 将API密钥存储在环境变量中
RESEND_API_KEY - Node.js SDK支持参数以使用React Email组件
react - Resend响应包含,
error,dataheaders - 成功时,单次发送返回,批量发送返回ID数组
{ id: "email-id" } - 针对大型列表的营销活动,请使用Resend Broadcasts功能