sendgrid-webhooks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSendGrid Webhooks
SendGrid Webhook
When to Use This Skill
适用场景
- Setting up SendGrid webhook handlers for email delivery tracking
- Debugging ECDSA signature verification failures
- Processing email events (bounce, delivered, open, click, spam report)
- Implementing email engagement analytics
- 搭建用于邮件投递追踪的SendGrid Webhook处理器
- 调试ECDSA签名验证失败问题
- 处理邮件事件(退信、投递成功、已打开、已点击、垃圾邮件举报)
- 实现邮件互动分析
Essential Code
核心代码示例
Signature Verification (Manual)
手动签名验证
SendGrid uses ECDSA (Elliptic Curve Digital Signature Algorithm) with public key verification.
javascript
// Node.js manual verification
const crypto = require('crypto');
function verifySignature(publicKey, payload, signature, timestamp) {
// Decode the base64 signature
const decodedSignature = Buffer.from(signature, 'base64');
// Create the signed content
const signedContent = timestamp + payload;
// Create verifier
const verifier = crypto.createVerify('sha256');
verifier.update(signedContent);
// Add PEM headers if not present
let pemKey = publicKey;
if (!pemKey.includes('BEGIN PUBLIC KEY')) {
pemKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;
}
// Verify the signature
return verifier.verify(pemKey, decodedSignature);
}
// Express middleware
app.post('/webhooks/sendgrid', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
if (!signature || !timestamp) {
return res.status(400).send('Missing signature headers');
}
const publicKey = process.env.SENDGRID_WEBHOOK_VERIFICATION_KEY;
const payload = req.body.toString();
if (!verifySignature(publicKey, payload, signature, timestamp)) {
return res.status(400).send('Invalid signature');
}
// Process events
const events = JSON.parse(payload);
console.log(`Received ${events.length} events`);
res.sendStatus(200);
});SendGrid 使用带公钥验证的ECDSA(椭圆曲线数字签名算法)。
javascript
// Node.js manual verification
const crypto = require('crypto');
function verifySignature(publicKey, payload, signature, timestamp) {
// Decode the base64 signature
const decodedSignature = Buffer.from(signature, 'base64');
// Create the signed content
const signedContent = timestamp + payload;
// Create verifier
const verifier = crypto.createVerify('sha256');
verifier.update(signedContent);
// Add PEM headers if not present
let pemKey = publicKey;
if (!pemKey.includes('BEGIN PUBLIC KEY')) {
pemKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;
}
// Verify the signature
return verifier.verify(pemKey, decodedSignature);
}
// Express middleware
app.post('/webhooks/sendgrid', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
if (!signature || !timestamp) {
return res.status(400).send('Missing signature headers');
}
const publicKey = process.env.SENDGRID_WEBHOOK_VERIFICATION_KEY;
const payload = req.body.toString();
if (!verifySignature(publicKey, payload, signature, timestamp)) {
return res.status(400).send('Invalid signature');
}
// Process events
const events = JSON.parse(payload);
console.log(`Received ${events.length} events`);
res.sendStatus(200);
});Using SendGrid SDK
使用SendGrid SDK
javascript
const { EventWebhook } = require('@sendgrid/eventwebhook');
const verifyWebhook = new EventWebhook();
const publicKey = process.env.SENDGRID_WEBHOOK_VERIFICATION_KEY;
app.post('/webhooks/sendgrid', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
const isValid = verifyWebhook.verifySignature(
publicKey,
req.body,
signature,
timestamp
);
if (!isValid) {
return res.status(400).send('Invalid signature');
}
// Process webhook
res.sendStatus(200);
});javascript
const { EventWebhook } = require('@sendgrid/eventwebhook');
const verifyWebhook = new EventWebhook();
const publicKey = process.env.SENDGRID_WEBHOOK_VERIFICATION_KEY;
app.post('/webhooks/sendgrid', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
const isValid = verifyWebhook.verifySignature(
publicKey,
req.body,
signature,
timestamp
);
if (!isValid) {
return res.status(400).send('Invalid signature');
}
// Process webhook
res.sendStatus(200);
});Common Event Types
常见事件类型
| Event | Description | Use Cases |
|---|---|---|
| Message has been received and is ready to be delivered | Track email processing |
| Message successfully delivered to recipient | Delivery confirmation |
| Message permanently rejected (includes type='blocked' for blocked messages) | Update contact lists, handle failures |
| Temporary delivery failure | Monitor delays |
| Recipient opened the email | Engagement tracking |
| Recipient clicked a link | Link tracking, CTR analysis |
| Email marked as spam | List hygiene, sender reputation |
| Recipient unsubscribed | Update subscription status |
| Recipient unsubscribed from a group | Update group subscription preferences |
| Recipient resubscribed to a group | Update group subscription preferences |
| 事件类型 | 描述 | 适用场景 |
|---|---|---|
| 邮件已被接收,等待投递 | 追踪邮件处理状态 |
| 邮件成功投递至收件人 | 投递确认 |
| 邮件被永久拒收(包含 | 更新联系人列表,处理投递失败 |
| 临时投递失败 | 监控投递延迟 |
| 收件人已打开邮件 | 互动追踪 |
| 收件人点击了链接 | 链接追踪,点击率分析 |
| 邮件被标记为垃圾邮件 | 列表清理,发件人信誉维护 |
| 收件人取消订阅 | 更新订阅状态 |
| 收件人取消群组订阅 | 更新群组订阅偏好 |
| 收件人重新订阅群组 | 更新群组订阅偏好 |
Environment Variables
环境变量
bash
undefinedbash
undefinedYour SendGrid webhook verification key (public key)
Your SendGrid webhook verification key (public key)
SENDGRID_WEBHOOK_VERIFICATION_KEY="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..."
undefinedSENDGRID_WEBHOOK_VERIFICATION_KEY="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..."
undefinedLocal Development
本地开发
For local webhook testing, use Hookdeck CLI:
bash
brew install hookdeck/hookdeck/hookdeck
hookdeck listen 3000 --path /webhooks/sendgridNo account required. Provides local tunnel + web UI for inspecting requests.
对于本地Webhook测试,使用Hookdeck CLI:
bash
brew install hookdeck/hookdeck/hookdeck
hookdeck listen 3000 --path /webhooks/sendgrid无需注册账号,提供本地隧道和Web界面用于查看请求详情。
Resources
参考资源
- overview.md - What SendGrid webhooks are, common event types
- setup.md - Configure webhooks in SendGrid dashboard, get verification key
- verification.md - ECDSA signature verification details and gotchas
- examples/ - Complete implementations for Express, Next.js, and FastAPI
- overview.md - 介绍SendGrid Webhook是什么、常见事件类型
- setup.md - 在SendGrid控制台配置Webhook,获取验证密钥
- verification.md - ECDSA签名验证的细节和注意事项
- examples/ - Express、Next.js和FastAPI的完整实现示例
Related Skills
相关技能
- - Cross-cutting patterns (idempotency, retries, framework guides)
webhook-handler-patterns - hookdeck-event-gateway - Webhook infrastructure that replaces your queue — guaranteed delivery, automatic retries, replay, rate limiting, and observability for your webhook handlers
- - 通用模式(幂等性、重试、框架指南)
webhook-handler-patterns - hookdeck-event-gateway - 替代队列的Webhook基础设施——为你的Webhook处理器提供可靠投递、自动重试、重放、速率限制和可观测性