AI agent 可以註冊一個服務、啟動一項工作,或開一張客服單,然後流程就停了,因為回覆送到了一個 agent 不存在的地方:Email 收件匣。驗證碼、收據、「你的匯出檔已經準備好」通知、密碼重設。Email 是網路上最古老的 callback 機制,而 agent 沒有地址。
這篇展示我們能做出的最小解法。一次 API 呼叫,不需要註冊,就會回傳一個可用的 Email 地址;寄到這個地址的信會變成結構化的事件,agent 透過 HTTP 讀回,和它的 Webhook 落在同一份事件紀錄裡。
重點摘要
POST https://anyhook.net/api/v1/quickstart(不需驗證)會回傳一個像q-cd3fe0f8.quickstart@anyhook.net這樣的inbox_address,外加一個 Webhook 的inbound_url和一把 API 金鑰。- 寄到這個地址的信會變成一個
email.received事件:from、to、subject、message_id,以及完整的原始 MIME 訊息。 - agent 用
GET /api/v1/events列出事件,用GET /api/v1/events/{id}讀取單一事件,或透過 MCP 使用anyhook_inbox/anyhook_events/anyhook_inspect(Registry:net.anyhook/anyhook,遠端端點https://anyhook.net/mcp)。 - 它只收不寄。它不能寄信也不能回信,這是刻意劃下的界線,不是路線圖上的缺口。
- 免費端點若未認領,7 天後到期;免費方案的上限是每天 1,000 個事件。
就這一個呼叫
curl -X POST https://anyhook.net/api/v1/quickstart
{
"inbound_url": "https://in.anyhook.net/q-cd3fe0f8/quickstart",
"inbox_address": "q-cd3fe0f8.quickstart@anyhook.net",
"api_key": "ahk_live_…",
"claim_url": "https://anyhook.net/claim/…",
"expires_at": "2026-08-06T…"
}
你不用建立帳號、不用解驗證碼,也不用一路點過 OAuth 同意畫面。這很重要,因為這裡的呼叫者往往不是人,而是任務進行到一半的 agent,流程中的每一張註冊表單,都是任務可能死掉的地方。在有人透過 claim_url 認領之前,這個端點都是暫時的(7 天),這同時也是濫用的上限:任何匿名的東西都活不過它的 TTL。
同一個 App(一個接收網址,對應一個 Webhook 來源)現在可以透過兩種管道接收:
| 管道 | 地址 |
|---|---|
| HTTP Webhook | https://in.anyhook.net/q-cd3fe0f8/quickstart |
q-cd3fe0f8.quickstart@anyhook.net |
兩者都匯入同一份事件紀錄,所以從 agent 的角度來看,「等 Stripe 的 Webhook」和「等確認信」是同一個操作:輪詢事件 API,檢視 payload。
一封信會變成什麼
隨便寄一封信到這個地址。幾秒內,它就會以事件的形式出現:
{
"type": "email.received",
"from": "noreply@github.com",
"to": "q-cd3fe0f8.quickstart@anyhook.net",
"subject": "Your verification code is 481920",
"message_id": "<abc123@mail.example.com>",
"date": "Thu, 30 Jul 2026 11:42:31 +0700",
"size": 7026,
"raw": "Received: from …"
}
raw 是完整、未經修改的 MIME 訊息:每個標頭、每個部分、每個附件,都和抵達時一模一樣。中繼資料欄位只是方便用的;原始訊息才是事實依據。agent 最常見的用途是從驗證信裡取出驗證碼,通常光看主旨就夠了。更複雜的需求,就用你所用語言的標準函式庫解析 MIME,那正是它的用途。
讀回來:
curl https://anyhook.net/api/v1/events \
-H "Authorization: Bearer ahk_live_…"
# the list carries no payloads; this returns one event with its body
curl https://anyhook.net/api/v1/events/<id> \
-H "Authorization: Bearer ahk_live_…"
透過 MCP
如果 agent 會講 MCP,它完全不用碰 curl。這個伺服器以 net.anyhook/anyhook 列在官方 MCP Registry 上,形式是 anyhook-mcp npm 套件,以及位於 https://anyhook.net/mcp 的遠端 streamable HTTP 端點:
anyhook_quickstart會直接回傳inbox_address(在 npm 套件裡不需要金鑰就能執行;遠端端點則需要先有 API 金鑰或先登入)。anyhook_inbox會回傳既有 App 的地址,以及它的 Webhook 網址。anyhook_events/anyhook_inspect讀取收到的內容。
快速入門工具就是整個上手流程。在 Registry 裡發現這個伺服器的 agent,可以替自己開一個收件匣,在沒有人類參與的情況下開始接收。人類之後才會出現(如果會的話),負責認領帳號。
運作方式(以及地址為什麼長這樣)
在底層,我們刻意不做第二條管線:
- Cloudflare Email Routing 的 catch-all 規則,會把寄到這個網域的每一封信,交給接收 Webhook 的同一個邊緣 Worker。
- Worker 以最後一個點,切開地址中 @ 前面的部分:
{user-slug}.{app-slug}@anyhook.net。slug 在建立時就被清理成只含[a-z0-9-],所以永遠不會包含點,這讓切分在結構上就不會有歧義。 - 這封信會被重新包裝成它原本會是的那個 HTTP 請求,之後的一切(配額、payload 上限、排入佇列、重試、傳遞到你的目的地、事件紀錄)走的都是和 Webhook 完全相同的程式路徑。
無法對應到真實 App 的信,會在 SMTP 階段就被拒收,而不是被悄悄吞掉。寄件者沒收到錯誤,就會以為已經送達。過大的信也會以同樣方式退回。
有兩個特性直接從 Webhook 那一側沿用過來。郵件主體在寫入資料庫之前,就以 AES-256-GCM 加密。每個事件的雜湊都會折入每個 App 各自的鏈,鏈每天封緘一次,每天的根雜湊都會提交到一個 AnyHook 沒有任何憑證的公開 git 儲存庫。如果我們在某封已儲存郵件的當天封緘之後修改它,已公開的錨點就會驗證不過。
它不是什麼
它不寄信。不回信、沒有外寄郵件、沒有 SMTP 憑證。寄信牽涉到送達率、SPF/DKIM 對齊、IP 信譽和垃圾郵件責任,那是另一門學問,失敗的方式也不一樣。如果你的 agent 需要一個完整雙向往來的 Email 產品,這個類別已經存在(AgentMail 就是以這個論點募到資金的)。加裝在 Webhook 中繼服務(webhook relay)上的只收信收件匣,是比較窄的東西:所有進來的東西,都在同一份事件紀錄裡。
它不是拋棄式信箱服務。預期的用途是你自己的系統產生的信:agent 正當操作的帳號收到的確認信、你整合的服務寄來的通知、你自己流程產生的收據。免費端點有速率限制、有上限,也會到期,濫用的模式會被擋下。如果某個服務的條款禁止自動註冊,有了收件匣也不會改變這一點。
它是輪詢,不是推送。agent 要自己問「收到了什麼?」,沒有東西會叫醒它。需要更低的延遲時,設定一個 destination_url,事件一抵達就會轉送到你自己的伺服器。這封信就變成了 Webhook。
試試看
# 1. mint an inbox (no signup)
curl -X POST https://anyhook.net/api/v1/quickstart
# 2. send any email to the inbox_address you got back
# 3. find it, then read it
curl https://anyhook.net/api/v1/events -H "Authorization: Bearer <api_key>"
curl https://anyhook.net/api/v1/events/<id> -H "Authorization: Bearer <api_key>"
整個設定花的時間,就是第 2 步那封信抵達所需的時間。