新用户新用户即享 DNS 与 CDN 免费套餐。立即注册

SMTP 与 HTTP API

创建 API 密钥,通过 SMTP 或 HTTP API 发送邮件,包含请求字段、响应、错误码和示例。

7 分钟阅读 更新于 2026年10月20日

通过发信流发信有两种方式:从任意应用或邮件库走 SMTP,或者调用 HTTP API。两者共用同一套 API 密钥、额度、抑制名单和事件。开始之前,请先验证发信域名并创建 API 密钥。

API 密钥

  1. 打开发信流,进入 API 密钥 标签页。
  2. 点击 创建密钥,填写 名称(例如 production)并确认。
  3. 复制显示的密钥,然后点击 我已保存。密钥只显示这一次,之后列表中只显示它的 前缀,例如 ytm_aB3dE6gH…。

密钥都以 ytm_ 开头。每个发信流最多可有 20 个有效密钥。列表会显示每个密钥最近一次使用的时间。要停用某个密钥,点击 吊销:使用该密钥的程序会立即失效。密钥只能用于它所属的发信流。

警告

API 密钥只能放在你的服务器上,不要写进浏览器代码、移动应用或公开仓库。任何拿到密钥的人都能以你的域名发信。

SMTP

发信流的 概览 标签页会显示 SMTP 配置:

配置项值
主机该发信流显示的 SMTP 主机,通常为 smtp.tm.yeapcloud.net
端口587(STARTTLS)或 465(TLS)
用户名apikey(就是这个单词本身)
密码该发信流的任一 API 密钥
类别头X-Yeap-Category

请以控制台显示的主机为准。部分发信流通过其他服务器组发信,主机名也不同。

SMTP 发信规则:

  • From 邮件头必须使用该发信流已验证域名下的地址。
  • 每个收件人(To、Cc 和 Bcc)都会收到单独的一份副本,拥有独立的邮件 ID,并各计为一封邮件。
  • 要设置分类,可以添加 X-Yeap-Category: password-reset 这样的邮件头,它会在投递前被移除。允许的字符为字母、数字、.、_ 和 -,最长 64 个字符。
  • 单封邮件最大 25 MB,每个 SMTP 事务最多 1,000 个收件人。
  • 每封邮件都会带上 X-TM-ID 邮件头(即发送记录和事件中显示的邮件 ID),以及供邮箱服务商反馈环使用的 Feedback-ID 邮件头。
  • 在营销发信流上,你设置的 List-Unsubscribe 邮件头会被替换为 Yeap Cloud 的一键退订邮件头。SMTP 不会修改邮件正文,所以请自行在内容中加入通信地址和退订链接。详见抑制名单与退订。
  • 打开和点击跟踪仅在 HTTP API 中可用。

使用 Python 标准库的示例:

python
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Example <noreply@example.com>"
msg["To"] = "user@example.org"
msg["Subject"] = "Reset your password"
msg["X-Yeap-Category"] = "password-reset"
msg.set_content("Click the link to reset your password: https://example.com/reset/abc")

with smtplib.SMTP("smtp.tm.yeapcloud.net", 587) as s:
    s.starttls()
    s.login("apikey", "ytm_your_api_key")
    s.send_message(msg)

SMTP 响应码

服务器拒收邮件时,响应码会说明原因。4xx 为临时错误:稍后重试。5xx 为永久错误:先解决问题再重新发送。

响应码消息原因与处理
535 5.7.8Authentication failed / API key revoked用户名或密钥错误,或密钥已被吊销。用户名必须是 apikey。
454 4.7.0Temporary authentication failure / Too many authentication failures服务器暂未就绪,或你的 IP 登录失败次数过多。稍等后重试。
451 4.7.1Stream is paused发信流已被自动暂停。查看发信流上显示的原因并联系客服。
550 5.7.1Stream is banned / suspended / terminated发信流已被封禁、订阅已停用,或发信流已释放。
550 5.7.1From domain … is not verified for this stream验证该域名,或检查它是否已共用给或绑定到该发信流。
550 5.7.1Sandbox mode: recipient is not a verified address发信流处于沙箱中。请验证该收件人,或发往你自己的域名。
550 5.7.1Recipient is on a suppression list / All recipients are suppressed该地址在抑制名单中(退信、投诉、退订或手动添加)。
452 4.7.1Hourly sending limit reached, try later每小时上限(或沙箱每日上限)已用完。下一个小时再试。
550 5.7.1Monthly sending quota exhausted每月邮件量已用完且不允许超量:免费版,或已达到超量消费上限。
452 4.5.3Too many recipients单个事务的收件人超过 1,000 个。
553 5.1.3Invalid recipient address收件地址格式错误。
554 5.7.1Message rejected: virus detected邮件含有病毒。发信流会被立即封禁,所有 API 密钥均被吊销。
554 5.7.1Message rejected as spam内容被判定为垃圾邮件。多次被拒会导致发信流被暂停。
451 4.3.0Content scanner unavailable, try again later营销邮件必须通过扫描才会被接收,请稍后重试。其他 451 4.3.0 响应为服务器临时错误:重试即可。
554 5.6.0Malformed message headers修正邮件头。

HTTP API

项目值
基础 URLhttps://api.tm.yeapcloud.net/v1(也可使用 https://api.yeap.cloud/api/tm/v1)
认证Authorization: Bearer ytm_your_api_key
格式请求和响应体均为 JSON,Content-Type: application/json
频率限制每个 API 密钥每分钟 600 次请求

出错时返回 HTTP 状态码和如下响应体:

json
{"error": {"code": "invalid_request", "message": "subject is required (single line)"}}
HTTP 状态码error.code含义
400invalid_json、invalid_request请求体不是 JSON 对象,或批量请求为空或过大
401unauthorizedAPI 密钥缺失、格式错误、已吊销或不存在
403stream_paused、stream_banned、stream_suspended发信流无法发信
403from_domain_unverified、invalid_from发件人域名未对该发信流验证,或发件人地址无效
403postal_address_required营销发信流未填写通信地址。请在 营销设置 标签页填写。
403virus附件含有病毒,发信流已被封禁。
404not_found该发信流中不存在这封邮件
422invalid_request某个字段缺失或无效,message 会指明是哪一个。
429rate_limited一分钟内请求超过 600 次。请降低频率后重试。
503no_node当前没有可用的发信服务器。请稍后重试。

发送邮件:POST /v1/send

字段类型说明
fromstring必填。单个地址,例如 noreply@example.com 或 Example <noreply@example.com>。域名必须已对该发信流验证。
tostring 或 array必填。单个地址、逗号分隔的字符串或数组。数组元素也可以是对象 {"email": "...", "name": "..."}。
cc、bccstring 或 array可选。格式同 to。Bcc 地址不会出现在邮件头中。
reply_tostring 或 array可选。Reply-To 地址。
subjectstring必填。单行,最长 998 个字符。
html、textstring至少填写一个。同时提供两者效果最好。
headersobject可选的额外邮件头,例如 {"X-Campaign": "spring"}。标准邮件头(From、To、Subject、Reply-To、Message-ID、List-Unsubscribe 等)不能在这里设置。
attachmentsarray可选。元素格式为 {"filename": "invoice.pdf", "content_base64": "...", "type": "application/pdf"}。最多 10 个文件,总大小不超过 10 MB。
categorystring可选。字母、数字、.、_、-,最长 64 个字符。
tagsarray of strings可选。最多 10 个标签,供你自己筛选,每个最长 64 个字符。
track_opens、track_clicksboolean可选。为本封邮件开启或关闭打开跟踪(跟踪像素)和点击跟踪(链接改写为经由 t.tm.yeapcloud.net 跳转)。仅对 HTML 有效。不填则使用发信流的默认设置。两者默认均关闭。
variablesobject可选。替换 subject、html 和 text 中的 {{name}} 占位符。在 html 中,值会做 HTML 转义。未知的占位符保持原样。

单次调用中 to、cc 和 bcc 合计最多 50 个收件人。每个收件人都会收到单独的一份副本,拥有独立的邮件 ID。如需向大量收件人发送不同内容,请使用批量接口。

示例:

bash
curl -X POST https://api.tm.yeapcloud.net/v1/send \
  -H "Authorization: Bearer ytm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Example <noreply@example.com>",
    "to": ["alice@example.org"],
    "subject": "Your order {{order_id}} has shipped",
    "html": "<p>Hi {{name}}, your order is on its way.</p>",
    "text": "Hi {{name}}, your order is on its way.",
    "category": "shipping",
    "tags": ["order"],
    "variables": {"name": "Alice", "order_id": "A-1024"}
  }'

响应:

json
{
  "message_ids": ["01JAQ3Z9V8K4M2N6P7R5S1T0XW"],
  "rejected": []
}

message_ids 列出已接收的副本。rejected 列出未发送的收件人,每项包含 rcpt 和 reason。即使部分甚至全部收件人被拒,调用也可能返回成功,所以请务必检查 rejected:

reason含义
invalid_recipient地址无效
suppressed:<scope>:<reason>地址在抑制名单中,例如 suppressed:global:hard_bounce
sandbox_recipient_not_verified发信流处于沙箱中,且该收件人不在允许范围内
rate_limited_hourly、rate_limited_sandbox_or_hourly每小时上限(或沙箱每日上限)已用完
monthly_quota_exceeded每月邮件量已用完且不允许超量
enqueue_failed邮件未能入队,不计入额度。请重试。

使用 requests 的 Python 示例:

python
import requests

resp = requests.post(
    "https://api.tm.yeapcloud.net/v1/send",
    headers={"Authorization": "Bearer ytm_your_api_key"},
    json={
        "from": "Example <noreply@example.com>",
        "to": "alice@example.org",
        "subject": "Welcome",
        "html": "<p>Welcome aboard!</p>",
        "text": "Welcome aboard!",
        "category": "welcome",
    },
    timeout=30,
)
resp.raise_for_status()
result = resp.json()
print(result["message_ids"], result["rejected"])

批量发送:POST /v1/batch

一次请求最多发送 500 封邮件。每一项的字段与 /v1/send 相同。

json
{
  "messages": [
    {"from": "noreply@example.com", "to": "a@example.org", "subject": "Hi A", "text": "Hello A"},
    {"from": "noreply@example.com", "to": "b@example.org", "subject": "Hi B", "text": "Hello B"}
  ]
}

响应中每封邮件对应一个结果,顺序与请求一致:

json
{
  "results": [
    {"index": 0, "message_ids": ["01JAQ..."], "rejected": []},
    {"index": 1, "error": {"code": "invalid_request", "message": "subject is required (single line)"}, "rejected": []}
  ]
}

查询邮件:GET /v1/messages

查询参数说明
status按状态筛选:queued、delivered、deferred、bounced、complained、rejected 或 failed
to按收件地址筛选
since只返回在此时间及之后创建的邮件,例如 2026-10-01T00:00:00Z
limit每页条数,1–100(默认 50)
before获取下一页时,传入上一次响应中的 next_before 值

响应格式为 {"data": [...], "next_before": "..."}。最后一页的 next_before 为 null。邮件记录保留 30 天。

GET /v1/messages/{id} 返回单封邮件及其事件:

json
{
  "id": "01JAQ3Z9V8K4M2N6P7R5S1T0XW",
  "stream_id": 12,
  "source": "api",
  "to": "alice@example.org",
  "from": "Example <noreply@example.com>",
  "subject": "Welcome",
  "category": "welcome",
  "tags": [],
  "status": "delivered",
  "smtp_code": 250,
  "smtp_response": "250 2.0.0 OK",
  "opened_at": null,
  "clicked_at": null,
  "unsubscribed_at": null,
  "created_at": "2026-10-20 10:15:02",
  "updated_at": "2026-10-20 10:15:04",
  "events": [
    {"type": "delivered", "at": "2026-10-20 10:15:04", "rcpt": "alice@example.org", "smtp_code": 250, "mx": "mx.example.org"}
  ]
}

抑制名单:/v1/suppressions

这些接口用于管理 API 密钥所属发信流的抑制名单。

请求请求体或查询参数响应
GET /v1/suppressions查询参数 email(可选)、limit(1–500,默认 100)、offset{"data": [{"id", "scope", "email", "reason", "category", "note", "created_at"}]}
POST /v1/suppressions{"email": "..."} 或 {"emails": [...]}(最多 1,000 个),可选 category{"added": 2, "invalid": []}
DELETE /v1/suppressions{"email": "..."},可选 category(放在请求体或查询参数中){"removed": 1}

通过 API 添加的地址,原因为 manual。账号级和全局抑制无法通过 API 修改。详见抑制名单与退订。

相关文档

本页内容是否有帮助?