Email Status Event Webhook Configuration
This section explains how users can configure webhooks in the application and verify signatures using the provided signature verification secret for enhanced security.
Adding a Webhook URL
Users can specify a webhook URL in the application where events will be sent. The webhook URL should be a publicly accessible endpoint capable of handling HTTP POST requests.
Steps to Add a Webhook:
- Go to Settings -> API Settings -> Email -> Status Update.
Webhook Event Structure:
When an event is triggered, the application will send a POST request to the configured webhook URL with the following headers and body:
Headers
- X-Easify-Signature: A Base64-encoded signature of the payload, generated using the verification secret.
- X-Easify-Timestamp: The UNIX timestamp of the request.
Payload
The POST body contains the event data. Example:
[
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "processed",
"category": ["cat facts"],
"sg_event_id": "4mA9l_cHKMlUEEkEuZc3****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "deferred",
"category": ["cat facts"],
"sg_event_id": "eKRNAYmTi2jlSdymGKZs****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"response": "400 try again later",
"attempt": "5"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "delivered",
"category": ["cat facts"],
"sg_event_id": "GuGhSahRjAq7Ci2m_FF****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"response": "250 OK"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "open",
"category": ["cat facts"],
"sg_event_id": "ABygEH8H1JfhmJQnDEtz****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"ip": "255.255.255.***"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "click",
"category": ["cat facts"],
"sg_event_id": "RlVuHd4e6J1KX1c3UXtu****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"ip": "255.255.255.***",
"url": "http://www.sendgrid.com/"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "bounce",
"category": ["cat facts"],
"sg_event_id": "SMrxoGPPPugXFS_tLM0b****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"reason": "500 unknown recipient",
"status": "5.0.*"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "dropped",
"category": ["cat facts"],
"sg_event_id": "00udEyCl5KqOB8aviHUI****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"reason": "Bounced Address",
"status": "5.0.*"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "spamreport",
"category": ["cat facts"],
"sg_event_id": "cxwA33aN6INAhHxR4eEl****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "unsubscribe",
"category": ["cat facts"],
"sg_event_id": "6KQ3MWWC3jY5Fm9PgYxE****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****"
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "group_unsubscribe",
"category": ["cat facts"],
"sg_event_id": "E9VM-8dxczn2XE1nstn4****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"ip": "255.255.255.***",
"url": "http://www.sendgrid.com/",
"asm_group_id": 1*
},
{
"additional_data" : "{'name':'John','id':'232'}",
"email": "example@test.com",
"email_id": "675",
"timestamp": 1734081***,
"smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
"event": "group_resubscribe",
"category": ["cat facts"],
"sg_event_id": "Q3zFzf5hk2ec_Ck5330R****",
"sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
"useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"ip": "255.255.255.***",
"url": "http://www.sendgrid.com/",
"asm_group_id": 1*
}
]
* You can use the status in the response by checking both the email and email_id values
Steps for Validating the Signature
Extract Header and Payload Information
X-Easify-Timestamp from the request headers.
X-Easify-Signature from the request headers.
Raw JSON payload from the request body.
Recreate the Signature
To validate the signature, recreate it using the following process:
Use the raw JSON payload as the input:
$payloadString = json_encode($payload);
Generate an HMAC signature using the shared webhook_secret:
$computedSignature = hash_hmac('sha256', $payloadString, $webhook_secret);
Encode the generated signature in Base64
$computedSignatureBase64 = base64_encode($computedSignature);
Compare the Signatures
Compare the computed signature with the one received in the X-Easify-Signature header:
if (hash_equals($computedSignatureBase64, $receivedSignature)) {
// Signature is valid
} else {
// Signature is invalid
}
Validate the Timestamp
To prevent replay attacks, ensure that the timestamp in X-Easify-Timestamp is within an acceptable range (e.g., ±5 minutes):
$currentTime = time();
if (abs($currentTime - $receivedTimestamp) > 300) {
// 5 minutes
// Reject the request as expired
}