BulkMail API 文档
BulkMail 提供基于 HTTP 的邮件发送 API。所有请求和响应都使用 JSON,任何语言都能直接调用。
快速开始
- 注册账户,并点击验证邮件里的链接完成邮箱验证。
- 在控制台的「域名」页面添加你的域名,把显示的 DNS 记录添加到域名服务商。DKIM 记录生效后,域名会自动变为「已验证」。
- 在「API Keys」页面创建一把 Key。Key 只显示一次,请妥善保存。
- 发送第一封邮件:
curl -X POST https://bulkmail.dev/emails \
-H "Authorization: Bearer mk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <hello@acme.com>",
"to": "user@example.com",
"subject": "你好",
"html": "<p>这是我的第一封邮件</p>"
}'
mail.acme.com),和公司日常办公邮箱分开,互不影响信誉。认证
所有 API 请求都需要在请求头中带上 API Key:
Authorization: Bearer mk_your_api_key
API Key 等同于账户密码,请只在服务端使用,不要放在网页或 App 的前端代码里。如果泄露,在控制台删除那一把并重新创建即可。
发送邮件
邮件会先进入发送队列,接口立即返回邮件 ID。投递结果可以通过查询接口或 Webhook 获取。
请求参数
| 参数 | 类型 | 说明 |
|---|---|---|
from | string | 必填。发件人,格式为 地址 或 名称 <地址>。域名必须已在你的账户中验证。 |
to | string | string[] | 必填。收件人。 |
cc | string | string[] | 抄送。 |
bcc | string | string[] | 密送。 |
reply_to | string | string[] | 回复地址。 |
subject | string | 必填。主题,不能包含换行,最长 998 个字符。 |
html | string | HTML 正文。 |
text | string | 纯文本正文。html 和 text 至少填一个,两者都填时收件人的邮箱客户端会自动选择。合计不超过 512 KB。 |
收件人、抄送和密送的总数不能超过账户等级的上限(见限额)。
响应
HTTP/1.1 202 Accepted
{
"id": "9db6562a-d026-4c68-ae7d-df08dd3af862",
"status": "queued",
"suppressed": []
}
suppressed 列出因在抑制名单中而被跳过的收件人。如果所有收件人都被抑制,status 为 suppressed,邮件不会发出。
邮件状态
| 状态 | 含义 |
|---|---|
queued | 已进入发送队列 |
sent | 已交给邮件服务器,正在投递 |
delivery_delayed | 对方暂时拒收,正在自动重试 |
delivered | 对方邮件服务器已接收 |
bounced | 硬退信(例如地址不存在),地址已加入抑制名单 |
complained | 收件人举报为垃圾邮件 |
failed | 发送失败,例如被对方拒收或重试超时,原因见 error 字段 |
suppressed | 所有收件人都在抑制名单中,没有发出 |
查询邮件
返回邮件内容、当前状态,以及每个收件人的投递事件。
{
"id": "9db6562a-d026-4c68-ae7d-df08dd3af862",
"from": "Acme <hello@acme.com>",
"to": ["user@example.com"],
"subject": "你好",
"status": "delivered",
"created_at": "2026-11-08T10:24:01.000Z",
"sent_at": "2026-11-08T10:24:02.000Z",
"events": [
{
"type": "delivered",
"recipient": "user@example.com",
"detail": "250 2.0.0 OK",
"created_at": "2026-11-08T10:24:03.000Z"
}
]
}
按时间倒序列出邮件。limit 最大 100。响应中的 next_before 不为空时,把它作为下一页的 before 参数。
域名
{ "name": "acme.com" }
返回域名信息和需要添加的 DNS 记录:
| 用途 | 类型 | 名称 | 说明 |
|---|---|---|---|
| DKIM | TXT | <selector>._domainkey.acme.com | 必需。邮件签名公钥,生效后域名即可发信。 |
| SPF | TXT | send.acme.com | 强烈建议。授权平台的 IP 代表该域名发信。 |
| 退信地址 | MX | send.acme.com | 强烈建议。用于接收退信。 |
| DMARC | TXT | _dmarc.acme.com | 建议。Gmail 等邮箱对批量发件人要求必须有。 |
立即检查 DNS 记录。系统也会每 10 分钟自动检查一次;添加后 72 小时内未验证的域名会失效,需要重新添加。
Webhook
{ "url": "https://your-app.com/webhooks/mail" }
第一次设置时,响应会包含签名密钥 secret,只显示这一次。之后邮件状态每次变化,我们都会向这个地址发送 POST 请求:
{
"type": "email.delivered",
"created_at": "2026-11-08T10:24:03.000Z",
"data": {
"email_id": "9db6562a-d026-4c68-ae7d-df08dd3af862",
"recipient": "user@example.com",
"detail": "250 2.0.0 OK"
}
}
事件类型
| 事件 | 触发时机 |
|---|---|
email.sent | 邮件已交给邮件服务器 |
email.delivered | 对方邮件服务器已接收 |
email.delivery_delayed | 暂时投递失败,稍后自动重试 |
email.bounced | 硬退信,地址已加入抑制名单 |
email.rejected | 被对方拒收(例如判为垃圾邮件),或重试超时 |
email.complained | 收件人举报为垃圾邮件 |
email.failed | 发送失败(例如账户被停用) |
你的服务器返回 2xx 即视为成功;否则会按指数退避重试,最多 8 次。
验证签名
每个请求都带有 X-Webhook-Timestamp(Unix 秒)和 X-Webhook-Signature 两个请求头。用签名密钥对 时间戳 + "." + 原始请求体 计算 HMAC-SHA256,与签名比对:
import crypto from "node:crypto";
export function verifyWebhook(headers, rawBody, secret) {
const ts = headers["x-webhook-timestamp"];
const sig = headers["x-webhook-signature"] ?? "";
const expected = "v1=" + crypto
.createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
// 拒绝 5 分钟以前的请求,防止重放
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh
&& sig.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
错误码
出错时响应体为 { "error": "错误说明" }。
| 状态码 | 含义 |
|---|---|
400 | 请求体不是合法的 JSON |
401 | 缺少 API Key,或 Key 无效 |
403 | 发件域名未验证、邮箱未验证,或账户已被停用 |
404 | 资源不存在 |
409 | 资源已存在,例如域名已被添加 |
413 | 邮件正文超过 512 KB |
422 | 参数不合法,例如地址格式错误、收件人过多 |
429 | 超过每日或每月发送额度 |
500 | 服务器内部错误,请稍后重试 |
限额
| 免费版 | 专业版 | 独立 IP | |
|---|---|---|---|
| 每日额度 | 100 封 | 10,000 封 | 不限 |
| 每月额度 | 3,000 封 | 100,000 封 | 不限 |
| 单封收件人 | 10 个 | 50 个 | 50 个 |
| 发信 IP | 免费共享池 | 优质共享池 | 专属 IP |
| 自动停用阈值 | 退信率 4% / 投诉率 0.08% | 退信率 5% / 投诉率 0.1% | 退信率 5% / 投诉率 0.1% |
额度按收件人数计算(一封邮件发给 3 个人算 3 封)。每日额度在 UTC 0 点重置。退信率和投诉率按近 7 天统计,超过阈值时账户会被自动停用,以保护平台上所有用户的送达率。