resend

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Resend Email API Emulator

Resend 邮件API模拟器

Fully stateful Resend API emulation. Emails, domains, API keys, audiences, and contacts persist in memory. Sent emails are captured and viewable through the inbox UI or the REST API.
No real emails are sent. Every call to
POST /emails
stores the message locally so you can inspect it programmatically or in the browser.
具备完整状态的Resend API仿真工具,邮件、域名、API密钥、受众群组和联系人都会持久化存储在内存中。已发送的邮件会被捕获,可通过收件箱UI或REST API查看。
工具不会发送任何真实邮件,所有调用
POST /emails
的请求都会将消息存储在本地,你可以通过编程方式或在浏览器中查看消息内容。

Start

启动

bash
undefined
bash
undefined

Resend only

仅启动Resend模拟服务

npx emulate --service resend
npx emulate --service resend

Default port (when run alone)

单独运行时的默认端口


Or programmatically:

```typescript
import { createEmulator } from 'emulate'

const resend = await createEmulator({ service: 'resend', port: 4000 })
// resend.url === 'http://localhost:4000'

也可以通过编程方式启动:

```typescript
import { createEmulator } from 'emulate'

const resend = await createEmulator({ service: 'resend', port: 4000 })
// resend.url === 'http://localhost:4000'

Auth

认证

Pass tokens as
Authorization: Bearer <token>
. Any
re_
prefixed token is accepted.
bash
curl http://localhost:4000/emails \
  -H "Authorization: Bearer re_test_key"
When no token is provided, requests fall back to the default user.
通过
Authorization: Bearer <token>
传递令牌,所有以
re_
为前缀的令牌都会被接受。
bash
curl http://localhost:4000/emails \
  -H "Authorization: Bearer re_test_key"
如果没有提供令牌,请求会默认归属到默认用户。

Pointing Your App at the Emulator

将你的应用对接模拟器

Environment Variable (Resend SDK)

环境变量配置(Resend SDK)

The official Resend Node.js SDK reads
RESEND_BASE_URL
at module load time. Set it to the emulator URL and the SDK works without any code changes:
bash
RESEND_BASE_URL=http://localhost:4000
typescript
import { Resend } from 'resend'

// No baseUrl argument needed; the SDK reads RESEND_BASE_URL automatically.
const resend = new Resend('re_test_key')

await resend.emails.send({
  from: 'hello@example.com',
  to: 'user@example.com',
  subject: 'Hello',
  html: '<p>It works!</p>',
})
官方Resend Node.js SDK会在模块加载时读取
RESEND_BASE_URL
,将其设置为模拟器的URL,无需修改任何代码即可正常使用SDK:
bash
RESEND_BASE_URL=http://localhost:4000
typescript
import { Resend } from 'resend'

// 无需传入baseUrl参数;SDK会自动读取RESEND_BASE_URL环境变量
const resend = new Resend('re_test_key')

await resend.emails.send({
  from: 'hello@example.com',
  to: 'user@example.com',
  subject: 'Hello',
  html: '<p>It works!</p>',
})

Embedded in Next.js (adapter-next)

嵌入Next.js中使用(adapter-next)

When using
@emulators/adapter-next
, the emulator runs inside your Next.js app at
/emulate/resend
. Set
RESEND_BASE_URL
via
next.config.ts
:
typescript
// next.config.ts
import { withEmulate } from '@emulators/adapter-next'

export default withEmulate({
  env: {
    RESEND_BASE_URL: `http://localhost:${process.env.PORT ?? '3000'}/emulate/resend`,
  },
})
typescript
// app/emulate/[...path]/route.ts
import { createEmulateHandler } from '@emulators/adapter-next'
import * as resend from '@emulators/resend'

export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({
  services: {
    resend: {
      emulator: resend,
      seed: {
        domains: [{ name: 'example.com' }],
      },
    },
  },
})
当你使用
@emulators/adapter-next
时,模拟器会运行在你的Next.js应用的
/emulate/resend
路径下,通过
next.config.ts
设置
RESEND_BASE_URL
typescript
// next.config.ts
import { withEmulate } from '@emulators/adapter-next'

export default withEmulate({
  env: {
    RESEND_BASE_URL: `http://localhost:${process.env.PORT ?? '3000'}/emulate/resend`,
  },
})
typescript
// app/emulate/[...path]/route.ts
import { createEmulateHandler } from '@emulators/adapter-next'
import * as resend from '@emulators/resend'

export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({
  services: {
    resend: {
      emulator: resend,
      seed: {
        domains: [{ name: 'example.com' }],
      },
    },
  },
})

Direct fetch

直接调用fetch

If you cannot use the SDK or env var, call the emulator directly:
typescript
await fetch('http://localhost:4000/emails', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer re_test_key',
  },
  body: JSON.stringify({
    from: 'hello@example.com',
    to: 'user@example.com',
    subject: 'Hello',
    html: '<p>It works!</p>',
  }),
})
如果你无法使用SDK或环境变量,可以直接调用模拟器接口:
typescript
await fetch('http://localhost:4000/emails', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer re_test_key',
  },
  body: JSON.stringify({
    from: 'hello@example.com',
    to: 'user@example.com',
    subject: 'Hello',
    html: '<p>It works!</p>',
  }),
})

Seed Config

初始化配置(Seed Config)

yaml
resend:
  domains:
    - name: example.com
      region: us-east-1
  contacts:
    - email: test@example.com
      first_name: Test
      last_name: User
      audience: Default
yaml
resend:
  domains:
    - name: example.com
      region: us-east-1
  contacts:
    - email: test@example.com
      first_name: Test
      last_name: User
      audience: Default

Retrieving Sent Emails

获取已发送邮件

This is the key differentiator of the emulator: every email sent via
POST /emails
is stored and queryable.
这是本模拟器的核心优势:所有通过
POST /emails
发送的邮件都会被存储,支持查询。

Inbox UI

收件箱UI

Browse sent emails in the browser:
http://localhost:4000/inbox
在浏览器中浏览已发送的邮件:
http://localhost:4000/inbox

REST API

REST API

bash
undefined
bash
undefined

List all sent emails

列出所有已发送邮件

curl http://localhost:4000/emails
-H "Authorization: Bearer re_test_key"
curl http://localhost:4000/emails
-H "Authorization: Bearer re_test_key"

Get a single email by ID

根据ID获取单封邮件

curl http://localhost:4000/emails/<id>
-H "Authorization: Bearer re_test_key"
undefined
curl http://localhost:4000/emails/<id>
-H "Authorization: Bearer re_test_key"
undefined

Extracting Data from Emails (tests, agents)

从邮件中提取数据(测试、Agent场景)

Useful for completing magic link, verification code, or password reset flows programmatically:
bash
undefined
非常适合通过编程方式完成魔法链接、验证码或密码重置流程:
bash
undefined

Get the latest email ID

获取最新一封邮件的ID

EMAIL_ID=$(curl -s http://localhost:4000/emails
-H "Authorization: Bearer re_test_key" | jq -r '.data[0].id')
EMAIL_ID=$(curl -s http://localhost:4000/emails
-H "Authorization: Bearer re_test_key" | jq -r '.data[0].id')

Extract a 6-digit code from the HTML body

从HTML正文中提取6位验证码

CODE=$(curl -s http://localhost:4000/emails/$EMAIL_ID
-H "Authorization: Bearer re_test_key" | jq -r '.html' | grep -oE '[0-9]{6}')
echo "Verification code: $CODE"
undefined
CODE=$(curl -s http://localhost:4000/emails/$EMAIL_ID
-H "Authorization: Bearer re_test_key" | jq -r '.html' | grep -oE '[0-9]{6}')
echo "Verification code: $CODE"
undefined

API Endpoints

API端点

Emails

邮件相关

bash
undefined
bash
undefined

Send an email

发送邮件

curl -X POST http://localhost:4000/emails
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"from": "hello@example.com", "to": "user@example.com", "subject": "Hello", "html": "<p>Hi</p>"}'
curl -X POST http://localhost:4000/emails
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"from": "hello@example.com", "to": "user@example.com", "subject": "Hello", "html": "<p>Hi</p>"}'

Send batch (up to 100)

批量发送(最多100封)

curl -X POST http://localhost:4000/emails/batch
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '[{"from": "a@example.com", "to": "b@example.com", "subject": "One", "html": "<p>1</p>"}]'
curl -X POST http://localhost:4000/emails/batch
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '[{"from": "a@example.com", "to": "b@example.com", "subject": "One", "html": "<p>1</p>"}]'

List all emails

列出所有邮件

curl http://localhost:4000/emails
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/emails
-H "Authorization: Bearer $TOKEN"

Get email by ID

根据ID获取邮件

curl http://localhost:4000/emails/<id>
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/emails/<id>
-H "Authorization: Bearer $TOKEN"

Cancel a scheduled email

取消定时发送的邮件

curl -X POST http://localhost:4000/emails/<id>/cancel
-H "Authorization: Bearer $TOKEN"

Supported fields: `from`, `to`, `subject`, `html`, `text`, `cc`, `bcc`, `reply_to`, `headers`, `tags`, `scheduled_at`.
curl -X POST http://localhost:4000/emails/<id>/cancel
-H "Authorization: Bearer $TOKEN"

支持的字段:`from`、`to`、`subject`、`html`、`text`、`cc`、`bcc`、`reply_to`、`headers`、`tags`、`scheduled_at`。

Domains

域名相关

bash
undefined
bash
undefined

Create domain

创建域名

curl -X POST http://localhost:4000/domains
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name": "example.com", "region": "us-east-1"}'
curl -X POST http://localhost:4000/domains
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name": "example.com", "region": "us-east-1"}'

List domains

列出所有域名

curl http://localhost:4000/domains
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/domains
-H "Authorization: Bearer $TOKEN"

Get domain

获取域名信息

curl http://localhost:4000/domains/<id>
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/domains/<id>
-H "Authorization: Bearer $TOKEN"

Verify domain (instantly marks all records as verified)

验证域名(会立即标记所有记录为已验证)

curl -X POST http://localhost:4000/domains/<id>/verify
-H "Authorization: Bearer $TOKEN"
curl -X POST http://localhost:4000/domains/<id>/verify
-H "Authorization: Bearer $TOKEN"

Delete domain

删除域名

curl -X DELETE http://localhost:4000/domains/<id>
-H "Authorization: Bearer $TOKEN"
undefined
curl -X DELETE http://localhost:4000/domains/<id>
-H "Authorization: Bearer $TOKEN"
undefined

API Keys

API密钥相关

bash
undefined
bash
undefined

Create API key

创建API密钥

curl -X POST http://localhost:4000/api-keys
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name": "Production"}'
curl -X POST http://localhost:4000/api-keys
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name": "Production"}'

List API keys

列出所有API密钥

curl http://localhost:4000/api-keys
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/api-keys
-H "Authorization: Bearer $TOKEN"

Delete API key

删除API密钥

curl -X DELETE http://localhost:4000/api-keys/<id>
-H "Authorization: Bearer $TOKEN"
undefined
curl -X DELETE http://localhost:4000/api-keys/<id>
-H "Authorization: Bearer $TOKEN"
undefined

Audiences

受众群组相关

bash
undefined
bash
undefined

Create audience

创建受众群组

curl -X POST http://localhost:4000/audiences
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name": "Newsletter"}'
curl -X POST http://localhost:4000/audiences
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name": "Newsletter"}'

List audiences

列出所有受众群组

curl http://localhost:4000/audiences
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/audiences
-H "Authorization: Bearer $TOKEN"

Delete audience

删除受众群组

curl -X DELETE http://localhost:4000/audiences/<id>
-H "Authorization: Bearer $TOKEN"
undefined
curl -X DELETE http://localhost:4000/audiences/<id>
-H "Authorization: Bearer $TOKEN"
undefined

Contacts

联系人相关

bash
undefined
bash
undefined

Create contact in an audience

在指定受众群组中创建联系人

curl -X POST http://localhost:4000/audiences/<audience_id>/contacts
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"email": "user@example.com", "first_name": "Jane", "last_name": "Doe"}'
curl -X POST http://localhost:4000/audiences/<audience_id>/contacts
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"email": "user@example.com", "first_name": "Jane", "last_name": "Doe"}'

List contacts in an audience

列出指定受众群组中的所有联系人

curl http://localhost:4000/audiences/<audience_id>/contacts
-H "Authorization: Bearer $TOKEN"
curl http://localhost:4000/audiences/<audience_id>/contacts
-H "Authorization: Bearer $TOKEN"

Delete contact

删除联系人

curl -X DELETE http://localhost:4000/audiences/<audience_id>/contacts/<id>
-H "Authorization: Bearer $TOKEN"
undefined
curl -X DELETE http://localhost:4000/audiences/<audience_id>/contacts/<id>
-H "Authorization: Bearer $TOKEN"
undefined

Webhooks

Webhooks

The emulator dispatches webhook events when state changes:
  • email.sent
    and
    email.delivered
    on
    POST /emails
  • domain.created
    and
    domain.deleted
    on domain operations
  • contact.created
    and
    contact.deleted
    on contact operations
当状态发生变化时,模拟器会触发对应的webhook事件:
  • email.sent
    email.delivered
    在调用
    POST /emails
    时触发
  • domain.created
    domain.deleted
    在域名操作时触发
  • contact.created
    contact.deleted
    在联系人操作时触发

Common Patterns

常见使用场景

Magic Link / Verification Code Flow

魔法链接 / 验证码流程

bash
TOKEN="re_test_key"
BASE="http://localhost:4000"
bash
TOKEN="re_test_key"
BASE="http://localhost:4000"

1. Send verification email

1. 发送验证邮件

curl -X POST $BASE/emails
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"from": "auth@example.com", "to": "user@example.com", "subject": "Your code", "html": "<p>Code: <strong>482910</strong></p>"}'
curl -X POST $BASE/emails
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"from": "auth@example.com", "to": "user@example.com", "subject": "Your code", "html": "<p>Code: <strong>482910</strong></p>"}'

2. Retrieve the email

2. 获取邮件

EMAIL_ID=$(curl -s $BASE/emails -H "Authorization: Bearer $TOKEN" | jq -r '.data[0].id')
EMAIL_ID=$(curl -s $BASE/emails -H "Authorization: Bearer $TOKEN" | jq -r '.data[0].id')

3. Read the HTML body

3. 读取HTML正文

curl -s $BASE/emails/$EMAIL_ID -H "Authorization: Bearer $TOKEN" | jq -r '.html'
undefined
curl -s $BASE/emails/$EMAIL_ID -H "Authorization: Bearer $TOKEN" | jq -r '.html'
undefined

Send and Verify in a Test

测试场景下的邮件发送与验证

typescript
import { createEmulator } from 'emulate'
import { Resend } from 'resend'

const emu = await createEmulator({ service: 'resend', port: 4000 })

process.env.RESEND_BASE_URL = emu.url
const resend = new Resend('re_test_key')

// Send
await resend.emails.send({
  from: 'auth@example.com',
  to: 'user@test.com',
  subject: 'Verify',
  html: '<p>Code: <strong>123456</strong></p>',
})

// Retrieve
const res = await fetch(`${emu.url}/emails`, {
  headers: { Authorization: 'Bearer re_test_key' },
})
const { data: emails } = await res.json()
console.log(emails[0].html) // contains "123456"
typescript
import { createEmulator } from 'emulate'
import { Resend } from 'resend'

const emu = await createEmulator({ service: 'resend', port: 4000 })

process.env.RESEND_BASE_URL = emu.url
const resend = new Resend('re_test_key')

// 发送邮件
await resend.emails.send({
  from: 'auth@example.com',
  to: 'user@test.com',
  subject: 'Verify',
  html: '<p>Code: <strong>123456</strong></p>',
})

// 获取邮件
const res = await fetch(`${emu.url}/emails`, {
  headers: { Authorization: 'Bearer re_test_key' },
})
const { data: emails } = await res.json()
console.log(emails[0].html) // 包含"123456"