> ## Documentation Index
> Fetch the complete documentation index at: /docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Receive Email Delivery and Engagement Webhooks

> Configure turboSMTP event callbacks, read delivery and engagement payloads, secure unsigned requests, and handle retries and duplicate events.

Use turboSMTP webhooks to receive email events at your application's HTTP endpoint. Configure the callback URL and selected events in the dashboard. You do not register webhooks through the public v2 API.

## Configure a callback

**1. Open webhook settings**

In the [dashboard](https://dashboard.serversmtp.com), go to **Settings → Notifications → Webhooks → Edit**.

**2. Enter your callback URL**

Enter the URL of your receiver. Use HTTPS to protect callback data and credentials in transit. The dashboard also accepts HTTP URLs, so configure HTTPS explicitly.

**3. Choose events**

Select the delivery and engagement events you need. Some options can be disabled for your plan. Free and Basic include a 30-day webhook demo; check the current [plan comparison](https://serversmtp.com/pricing/) and your dashboard for availability.

**4. Save and allow settings to propagate**

Changes can take up to one hour to take effect. There is no **Send Test** button. After that interval, send a message from your application and inspect the resulting callback and dashboard record.

## Event types

The dashboard labels and payload values differ. Use the uppercase `status` field when processing events.

| Dashboard event | Payload `status` | Meaning |
| - | - | - |
| Processed | `PROCESSED` | Message received and queued |
| Dropped | `DROPPED` | Message not sent, for example because the recipient is suppressed |
| Delivered | `DELIVERED` | Recipient mail server accepted the message |
| Deferred | `DEFERRED` | Delivery temporarily deferred |
| Bounced | `BOUNCED` | Delivery failed with a permanent rejection |
| Open | `OPENED` | A mail client or proxy loaded the tracking pixel |
| Click | `CLICKED` | A tracked link was requested |
| Unsubscribe | `UNSUBSCRIBED` | Recipient unsubscribed |
| Spam report | `REPORT` | Spam complaint received |

Open and click events depend on tracking being enabled. Automated mail scanners and privacy proxies can trigger them; an event does not prove that a person read the message.

## Payload format

Each callback body is a flat JSON object. Production callbacks use capitalized `Timestamp`. The [public webhook reference](https://serversmtp.com/event-webhook-reference/) shows lowercase `timestamp`, so a defensive receiver can accept both.

```json Delivery event theme={"system"}
{
  "id": "5943788912",
  "mid": "1475205839938715648",
  "status": "DELIVERED",
  "email": "recipient@example.com",
  "subject": "Your account is ready",
  "Timestamp": 1793095200
}
```

| Field | Meaning |
| - | - |
| `status` | Uppercase event type |
| `mid` | Original message identifier; shared across events for that message |
| `email` | Recipient address |
| `Timestamp` | Unix timestamp in seconds |
| `id` | Event identifier when present |
| `subject` | Message subject; can be `null` |
| `reason` | Failure or status details as a string |
| `useragent`, `ip` | Client information on an engagement event |
| `url` | Clicked destination on a click event |
| `Reference-ID`, `X-Campaign-ID` | Your message reference and campaign ID, when the message carried them and your account's webhook worker supports them |

Treat message identifiers as opaque identifiers. Snowflake IDs can exceed JavaScript's safe-integer range. Preserve string IDs as strings and use a lossless JSON parser if your callback encodes a large ID as a JSON number.

```json Click event theme={"system"}
{
  "id": "5943788913",
  "mid": "1475205839938715648",
  "status": "CLICKED",
  "email": "recipient@example.com",
  "Timestamp": 1793095260,
  "url": "https://example.com/account",
  "ip": "192.0.2.10",
  "useragent": "Example mail client"
}
```

Validate at least `status`, `mid`, `email`, and `Timestamp` (falling back to `timestamp`). Accept optional fields without depending on a fixed set of extra properties. Read the complete request body before parsing JSON: callbacks can use chunked HTTP transfer encoding.

## Secure the endpoint

> [!WARNING]
>
> turboSMTP does not sign webhook requests and does not provide an HMAC signature header to verify. A valid-looking payload is not proof of its sender.

Use HTTPS and authenticate the receiver. You can include HTTP Basic credentials in the configured callback URL:

```text Callback URL pattern theme={"system"}
https://WEBHOOK_USER:WEBHOOK_PASSWORD@hooks.example.com/turbosmtp
```

Percent-encode special characters in the username and password. Check the resulting `Authorization: Basic ...` header on your server before accepting the payload. Keep callback credentials separate from your SMTP/API credentials and redact them from logs. Alternatively, use a secret URL path. Only apply an IP allow-list if turboSMTP support has confirmed the callback source ranges for your account; the payload's `ip` field describes the recipient client and is not the callback source address.

## Acknowledgements and retries

Return an HTTP `2xx` response after validating and durably accepting an event. Process longer work asynchronously so the callback can finish promptly. If delivery receives a non-`2xx` response, turboSMTP retries twice before dropping the event. Webhooks are therefore not a permanent replay log.

Expect duplicate delivery. Deduplicate using the event ID when present, or an application key that includes the message ID, recipient, status, and timestamp. Do not deduplicate on `mid` alone: one message can produce multiple distinct events. Use [analytics](/docs/api-reference/analytics.md) when you need to reconcile delivery records.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.