Skip to main content
openmail sends webhooks to your configured URL when inbound email is received. Use webhooks to power real-time features like live chat, ticket creation, or AI assistants.

Events

EventDescription
message.receivedA new inbound email was delivered to an inbox

Payload structure

{
  "event": "message.received",
  "event_id": "evt_abc123",
  "occurred_at": "2024-03-21T10:05:00.000Z",
  "delivered_at": "2024-03-21T10:05:01.000Z",
  "attempt": 1,
  "inbox_id": "inb_92ma...",
  "external_id": "user_abc123",
  "thread_id": "thr_xyz...",
  "message": {
    "id": "msg_...",
    "rfc_message_id": "<original@message.id>",
    "from": "sender@example.com",
    "to": "inbox@yourdomain.openmail.sh",
    "cc": [],
    "subject": "Email subject",
    "body_text": "Plain text body",
    "attachments": [
      {
        "filename": "document.pdf",
        "contentType": "application/pdf",
        "sizeBytes": 12345,
        "url": "https://api.openmail.sh/v1/attachments/msg_.../document.pdf"
      }
    ],
    "received_at": "2024-03-21T10:05:00.000Z"
  }
}

Headers

HeaderDescription
Content-Typeapplication/json
X-TimestampUnix timestamp (seconds) used in signature
X-SignatureHMAC-SHA256 signature (see below)
X-Event-IdUnique event ID for deduplication

Signature verification

The signature is computed as:
HMAC-SHA256(webhook_secret, "{timestamp}.{raw_json_payload}")
Verify before processing:
  1. Read the raw request body as a string (do not parse JSON first).
  2. Get X-Timestamp and X-Signature from headers.
  3. Compute HMAC-SHA256(secret, timestamp + "." + body).
  4. Compare with X-Signature using a constant-time comparison.
Use constant-time comparison (e.g. crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python) to prevent timing attacks.

Best practices

  • Respond quickly — Return 200 within 15 seconds. Process asynchronously if needed.
  • Idempotency — Use event_id to deduplicate. We may retry; your handler should be idempotent.
  • Attachment URLs — Fetch promptly; signed URLs expire.
  • Verify signatures — Never process webhooks without verifying the signature.

Retries

Failed deliveries (non-2xx or timeout) are retried up to 5 times with exponential backoff (~30s, 60s, 120s, 240s, 480s).