| name | sendgrid-webhooks |
| description | Receive and verify SendGrid webhooks. Use when setting up SendGrid webhook handlers, debugging signature verification, or handling email delivery events.
|
| license | MIT |
| metadata | {"author":"hookdeck","version":"0.1.0","repository":"https://github.com/hookdeck/webhook-skills"} |
SendGrid Webhooks
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
Essential Code
Signature Verification (Manual)
SendGrid uses ECDSA (Elliptic Curve Digital Signature Algorithm) with public key verification.
const crypto = require('crypto');
function verifySignature(publicKey, payload, signature, timestamp) {
const decodedSignature = Buffer.from(signature, 'base64');
const signedContent = timestamp + payload;
const verifier = crypto.createVerify('sha256');
verifier.update(signedContent);
let pemKey = publicKey;
if (!pemKey.includes('BEGIN PUBLIC KEY')) {
pemKey = `-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`;
}
return verifier.verify(pemKey, decodedSignature);
}
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');
}
const events = JSON.parse(payload);
console.log(`Received ${events.length} events`);
res.sendStatus(200);
});
Using SendGrid SDK
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');
}
res.sendStatus(200);
});
Common Event Types
| Event | Description | Use Cases |
|---|
processed | Message has been received and is ready to be delivered | Track email processing |
delivered | Message successfully delivered to recipient | Delivery confirmation |
bounce | Message permanently rejected (includes type='blocked' for blocked messages) | Update contact lists, handle failures |
deferred | Temporary delivery failure | Monitor delays |
open | Recipient opened the email | Engagement tracking |
click | Recipient clicked a link | Link tracking, CTR analysis |
spam report | Email marked as spam | List hygiene, sender reputation |
unsubscribe | Recipient unsubscribed | Update subscription status |
group unsubscribe | Recipient unsubscribed from a group | Update group subscription preferences |
group resubscribe | Recipient resubscribed to a group | Update group subscription preferences |
Environment Variables
SENDGRID_WEBHOOK_VERIFICATION_KEY="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..."
Local Development
For local webhook testing, use Hookdeck CLI:
npx hookdeck-cli listen 3000 sendgrid --path /webhooks/sendgrid
No account required. Provides local tunnel + web UI for inspecting requests.
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
Related Skills
webhook-handler-patterns - Cross-cutting patterns (idempotency, retries, framework guides)
- hookdeck-event-gateway - Webhook infrastructure that replaces your queue — guaranteed delivery, automatic retries, replay, rate limiting, and observability for your webhook handlers