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.
// 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
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
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
Your SendGrid webhook verification key (public key)
SENDGRID_WEBHOOK_VERIFICATION_KEY
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE..." Local Development For local webhook testing, use Hookdeck CLI: brew install hookdeck/hookdeck/hookdeck hookdeck listen 3000 --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