Cách SendGrid gửi webhook

SendGrid ký bằng ECDSA P-256, không phải HMAC, trong header x-twilio-email. Định dạng đã kiểm chứng và code xác minh bằng Web Crypto.

Hành vi gửi

Lấy từ tài liệu của chính hãng, kiểm tra lần cuối 2026-08-06. Hãng không nêu con số nào thì bảng này cũng không ghi.

Thời hạn phản hồihãng không công bố
Thử lạihãng không công bố
Ngừng gửihãng không công bố

Chữ ký

Kiểm chứng bằng một bộ xác minh chạy thật, có bộ test chứng minh, chứ không đọc từ tài liệu. Kiểm chứng lần cuối 2026-08-20.

Thuật toánECDSA P-256
Payload được ký{timestamp}{body}
Encodingbase64
Headerx-twilio-email-event-webhook-signature
Dung saikhông quy định

Xác minh

Dùng raw body của request, đúng từng byte, trước mọi bước parse JSON. Mọi cơ chế trên trang này đều hỏng ngay khi framework serialize lại 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),
);

Những chỗ dễ vấp

Header ghi x-twilio-email vì Twilio sở hữu SendGrid; cơ chế này là của riêng SendGrid và không dính dáng gì tới HMAC-SHA1 của Twilio. Bộ xác minh chỉ dựa vào tiền tố header sẽ chọn sai thuật toán.

Đọc thêm

AnyHook đứng trước các endpoint nhận webhook từ SendGrid: trả lời sau khoảng 1 giây, tự thử lại theo lịch riêng khi server của bạn ngừng hoạt động, và giữ mọi sự kiện để bạn phát lại được. Đổi một URL, giữ nguyên code.

Cách hoạt động →