SendGrid 如何傳遞 Webhook

SendGrid 用 ECDSA P-256 簽章,不是 HMAC,簽章放在 x-twilio-email 標頭。附經驗證的格式與 Web Crypto 驗證程式。

傳遞行為

取自服務商自己的文件,最後檢查於 2026-08-06。服務商沒寫數字的地方,這張表也不填。

回應時限服務商未公開
重試服務商未公開
放棄服務商未公開

簽章

用一個經測試套件證明可運作的驗證程式核對過,不是照文件抄來的。最後驗證於 2026-08-20。

演算法ECDSA P-256
簽章內容{timestamp}{body}
編碼base64
標頭x-twilio-email-event-webhook-signature
容許時間差不強制

驗證簽章

要用原始請求主體(raw body),逐位元組原封不動,並在任何 JSON 解析之前取得。框架只要重新序列化 payload,這頁上的每一種機制就會立刻失效。

// ECDSA P-256 over "{timestamp}{body}", signature and key both base64.
const b64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));

const key = await crypto.subtle.importKey(
  "spki",
  b64(verificationKey), // Mail Settings → Signed Event Webhook
  { name: "ECDSA", namedCurve: "P-256" },
  false,
  ["verify"],
);
const ts = req.headers["x-twilio-email-event-webhook-timestamp"];
const valid = await crypto.subtle.verify(
  { name: "ECDSA", hash: "SHA-256" },
  key,
  b64(req.headers["x-twilio-email-event-webhook-signature"]),
  new TextEncoder().encode(ts + rawBody),
);

容易踩的坑

標頭寫的是 x-twilio-email,因為 SendGrid 屬於 Twilio;但這套機制是 SendGrid 自己的,和 Twilio 的 HMAC-SHA1 毫無共通之處。只看標頭前綴判斷的驗證程式會選錯演算法。

延伸閱讀

AnyHook 架在接收 SendGrid Webhook 的端點前面:大約 1 秒就回應,伺服器當機時依自己的排程重試,並讓每個事件都能重播。 換一個網址,程式碼不用動。

運作方式 →