开发者 → 指南

在您的应用中接收邮件

支持工单、通知回复、发送给机器人的文档:发往您域名下某个地址的邮件,会以一个签名的 JSON POST 请求送达您的 HTTPS 端点,包含纯文本、HTML 及所有附件。无需轮询邮箱,也无需 IMAP。

准备工作

  • 一个在 NameOcean 注册的域名:此类域名可免费使用邮件转发和邮件转 webhook 功能。
  • 一个位于公网地址、可在 20 秒内响应的 HTTPS 端点。
  • nameocean CLI,或一个具有 email:write 权限的 API 密钥。

1. 为域名开启邮件转发

nameocean
$ nameocean email forwards on example.com

此操作会将域名的 MX 记录指向 NameOcean 的邮件转发服务器。如果该域名已有指向其他邮箱服务的 MX 记录,命令将停止并列出这些记录,因为发往该域名的所有邮件都将转到这里。仅在您确实需要时才添加 --replace-mx。

2. 申请邮件转 webhook 功能

为防止被用作垃圾邮件中继,将邮件发布到 URL 的功能需按账户经过简短审核后开通。请在 控制台 → 邮件转发 下的域名页面中提交申请,并简要说明用途。在此之前,API 将返回 403 not_approved。

3. 将地址发送到您的端点

nameocean
$ nameocean email inbound add example.com support https://app.example.com/hooks/mail
curl
$ curl -X POST https://nameocean.net/api/v1/email/forwarding/example.com/webhooks \
    -H "Authorization: Bearer $NAMEOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d '{"localpart": "support", "url": "https://app.example.com/hooks/mail"}'

响应中包含签名密钥(whsec_…),请将其保存在您应用的配置中。localpart 设为 * 时,会转发该域名下所有未单独设置别名的地址。每个域名最多可设置三个此类 webhook。

4. 接收邮件

先基于原始请求体验证签名,再读取 JSON。一个简单的 Flask 接收端示例:

app.py
import base64, hashlib, hmac, json, os, time

from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["NAMEOCEAN_WEBHOOK_SECRET"]  # whsec_...


def verified(header, body, tolerance=300):
    fields = dict(part.split("=", 1) for part in header.split(",") if "=" in part)
    ts = int(fields.get("t", "0"))
    if abs(time.time() - ts) > tolerance:
        return False
    expected = hmac.new(SECRET.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, fields.get("v1", ""))


@app.post("/hooks/mail")
def mail():
    body = request.get_data()
    if not verified(request.headers.get("X-NameOcean-Signature", ""), body):
        abort(401)
    mail = json.loads(body)
    print(mail["envelope"]["from"], "→", mail["envelope"]["to"], mail["subject"])
    for a in mail["attachments"]:
        data = base64.b64decode(a["content_base64"])
        print("  attachment", a["filename"], a["content_type"], len(data), "bytes")
    return "", 204  # any 2xx: delivered

接收内容

POST https://app.example.com/hooks/mail
X-NameOcean-Event: email.received
X-NameOcean-Delivery: 6f1c2a4e-8b3d-4f5a-9c7e-1d2b3a4c5e6f
X-NameOcean-Signature: t=1794300000,v1=5f2b…

{
  "id": "6f1c2a4e-8b3d-4f5a-9c7e-1d2b3a4c5e6f",
  "event": "email.received",
  "received_at": "2026-11-11T09:30:12+00:00",
  "envelope": {"from": "alice@example.org", "to": "support@example.com"},
  "from": "Alice <alice@example.org>",
  "to": "support@example.com",
  "cc": null,
  "reply_to": null,
  "subject": "Order 1042",
  "date": "Wed, 11 Nov 2026 09:30:05 +0000",
  "message_id": "<…@example.org>",
  "in_reply_to": null,
  "references": null,
  "text": "Hi…",
  "html": "<p>Hi…</p>",
  "headers": [["From", "Alice <alice@example.org>"], …],
  "attachments": [{"filename": "invoice.pdf", "content_type": "application/pdf", "content_id": null,
                   "size": 48211, "content_base64": "JVBERi0…"}],
  "spam_score": 0.4,
  "size": 66120
}

同一封邮件重新发布时 id 保持不变,可用它来跳过重复邮件。in_reply_to 和 references 可告诉您对方回复的是您发出的哪封邮件。

当您的端点不可用时

  • 返回 2xx 即表示投递成功。遇到 408、429、5xx、超时(20 秒)或无法连接时,将在 6 小时内持续重试。
  • 其他任何 4xx 均视为最终结果:该邮件不会自动重新发布。
  • 无法发布的邮件将保留 30 天。可通过 nameocean email forwards log example.com(或 GET /email/forwarding/example.com/messages)找到并释放它:邮件将以相同的 id 再次发布一次。
  • 每个域名每天最多有 500 封邮件发送到 webhook,超出部分将以同样方式暂存。