Webhooks Guide

Real-time event notifications for your email infrastructure

Event Types

email.delivered

Triggered when an email successfully reaches the recipient's mail server.

{ "event": "email.delivered", "timestamp": 1716144000, "data": { "message_id": "msg_abc123xyz", "recipient": "recipient@example.com", "isp": "gmail" } }

email.bounced

Triggered when an email fails to deliver. Includes bounce type and code.

{ "event": "email.bounced", "timestamp": 1716144000, "data": { "message_id": "msg_abc123xyz", "recipient": "invalid@example.com", "bounce_type": "hard", "bounce_code": "5.1.1", "bounce_description": "Mailbox does not exist" } }

email.complained

Triggered when a recipient marks your email as spam. Critical to track.

{ "event": "email.complained", "timestamp": 1716144000, "data": { "message_id": "msg_abc123xyz", "recipient": "recipient@example.com", "isp": "gmail" } }

email.opened

Triggered when the recipient opens your email (via tracking pixel).

{ "event": "email.opened", "timestamp": 1716144000, "data": { "message_id": "msg_abc123xyz", "recipient": "recipient@example.com" } }

email.clicked

Triggered when the recipient clicks a link in your email.

{ "event": "email.clicked", "timestamp": 1716144000, "data": { "message_id": "msg_abc123xyz", "recipient": "recipient@example.com", "url": "https://yoursite.com/landing" } }

Setting Up Webhooks

1. Create a Webhook Endpoint

Your endpoint must:

  • Accept POST requests
  • Return 200 OK within 10 seconds
  • Accept JSON body
  • Verify webhook signature

2. Register Your Endpoint

POST /api/v1/webhooks { "url": "https://yourapp.com/webhooks/cloudmails", "events": ["email.delivered", "email.bounced", "email.complained"], "secret": "your_webhook_secret" }

3. Verify Webhook Signature

import hmac import hashlib def verify_signature(payload, signature, secret): expected = hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature)

Handling Webhooks

PHP Example

$secret = 'your_webhook_secret'; $payload = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_CLOUDMAILS_SIGNATURE']; $expected = hash_hmac('sha256', $payload, $secret); if (!hash_equals($expected, $signature)) { http_response_code(401); exit('Invalid signature'); } $data = json_decode($payload, true); switch ($data['event']) { case 'email.bounced': remove_from_list($data['data']['recipient']); break; case 'email.complained': remove_from_list($data['data']['recipient']); break; case 'email.delivered': log_delivery($data['data']); break; } http_response_code(200);

⚠️ Process Async

Don't process webhooks synchronously. Queue the webhook event and process from queue. If your processing takes too long, the webhook will timeout and retry.

Retry Behavior

If your endpoint returns non-200 or times out, CloudMails retries with exponential backoff:

  • 1st retry: 1 minute
  • 2nd retry: 5 minutes
  • 3rd retry: 30 minutes
  • 4th retry: 2 hours
  • 5th retry: 24 hours

✓ Idempotent Handling

Implement idempotent handlers. Webhooks may arrive multiple times. Use message_id to deduplicate.