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

# Event Reporting Agent

> Install and configure the SendPost event reporting agent to report delivered, bounced, and deferred events from your MTA logs.

The **event reporting agent** is a small program you install on the server where your MTA (e.g., Postfix) runs. It tails the MTA mail log, parses delivery status entries, correlates them to SendPost messages via `X-Sendpost-Message-UUID`, and batches events to SendPost's event ingestion API. This gives you **CSDelivered** and **CSHardBounced** / **CSSoftBounced** (from agent `delivered`, `bounced`, `soft_bounced`) in addition to synchronous **CSSent** and SendPost tracking events. The agent may also send `deferred`; SendPost accepts it but **does not store** deferred events (they do not appear in the UI).

<Info>
  Agent failures do not cause message loss. If the agent is down, you still get CSSent (from SMTP 2xx) and open/click/unsubscribe tracking. The agent adds final delivery outcome (CSDelivered, etc.).
</Info>

***

## Supported MTAs

| MTA                      | Status                      |
| ------------------------ | --------------------------- |
| Postfix                  | Supported (initial release) |
| PowerMTA, Haraka, others | Future releases             |

***

## Installation

### One-Liner (Postfix)

Run on the server where Postfix runs. Replace `<EVENT_INGESTION_KEY>` with the key from your Custom SMTP TPSP (shown once at creation).

```bash theme={null}
curl -sSL https://sendpost-agent.s3.us-east-1.amazonaws.com/agent | sudo bash -s -- \
  --api-key <EVENT_INGESTION_KEY> \
  --mta postfix \
  --endpoint https://events.sendpost.io/api/v1/tpsp/custom-smtp/events
```

The agent is distributed as a single statically-linked binary (\~10MB) and is installed as a systemd service with automatic restart on failure.

### Package Installation

The agent is also available as:

* `.deb` package (Debian/Ubuntu)
* `.rpm` package (RHEL/CentOS)
* Raw binary with shell installer

Use the same `--api-key`, `--mta`, and `--endpoint` (or config file) as in the one-liner.

***

## Configuration

Configuration can be provided via:

* **Command-line flags** (as in the install command)
* **Config file**: `/etc/sendpost-agent/config.yaml`

| Option     | Description                                               | Default                                                     |
| ---------- | --------------------------------------------------------- | ----------------------------------------------------------- |
| `api-key`  | Event Ingestion API Key (scoped to your Custom SMTP TPSP) | Required                                                    |
| `mta`      | MTA type                                                  | `postfix`                                                   |
| `endpoint` | SendPost event ingestion URL                              | `https://events.sendpost.io/api/v1/tpsp/custom-smtp/events` |
| `log-path` | Path to MTA mail log                                      | `/var/log/mail.log`                                         |

Example `config.yaml`:

```yaml theme={null}
api-key: "your-event-ingestion-api-key"
mta: postfix
endpoint: "https://events.sendpost.io/api/v1/tpsp/custom-smtp/events"
log-path: "/var/log/mail.log"
```

***

## What the Agent Reports (Postfix)

The agent parses Postfix mail log entries and sends events with `event_type` one of: **delivered**, **bounced**, **deferred**, **soft\_bounced**.

| Postfix status    | Agent `event_type`          | SendPost result                                                          |
| ----------------- | --------------------------- | ------------------------------------------------------------------------ |
| `status=sent`     | `delivered`                 | CSDelivered (stored)                                                     |
| `status=bounced`  | `bounced` or `soft_bounced` | CSHardBounced or CSSoftBounced (SendPost classifies by SMTP description) |
| `status=deferred` | `deferred`                  | Accepted but **not stored** (by design)                                  |

Each event can include SMTP response code and description. SendPost uses the SMTP description (keyword-based) to classify bounces as hard vs soft. Correlation to SendPost messages is done via **message\_id** (SendPost UUID) that Postfix logs when it receives the message. The agent maintains a mapping of Postfix queue ID → SendPost message UUID (with a 24-hour TTL for deferred retries).

<Warning>
  **Header preservation**: Your Postfix must preserve the `X-Sendpost-Message-UUID` header (or the header used for message-id correlation). Most default configurations do; if you use content\_filter or custom pipelines, ensure custom headers are not stripped.
</Warning>

***

## Batching and Resilience

* **Batching**: Up to 100 events or 5 seconds, whichever comes first, then POST to the ingestion endpoint.
* **Transient failures**: Exponential backoff (1s, 2s, 4s, 8s, up to 60s).
* **Durability**: Unsent events are written to a local WAL file (max 100MB) at `/var/lib/sendpost-agent/pending.wal`. A cursor file at `/var/lib/sendpost-agent/cursor` tracks the last-read position in the mail log so the agent can resume after restart.

***

## Health and Monitoring

| Endpoint                        | Purpose            |
| ------------------------------- | ------------------ |
| `http://localhost:9113/health`  | Health check       |
| `http://localhost:9113/metrics` | Prometheus metrics |

Use these to monitor the agent from your existing monitoring stack.

***

## Request Payload (Event Ingestion API)

**Endpoint**: `POST /api/v1/tpsp/custom-smtp/events`\
**Auth**: Header `X-SP-Event-ApiKey` (your Event Ingestion API Key). Missing or invalid → 401.\
**Rate limit**: 10,000 requests/minute per API key (when implemented).

**Body** (JSON):

```json theme={null}
{
  "events": [
    {
      "message_id": "<sendpost-message-uuid>",
      "event_type": "delivered",
      "timestamp": "2026-02-19T12:00:00Z",
      "smtp_code": 250,
      "smtp_description": "OK",
      "recipient": "user@example.com"
    }
  ]
}
```

* **message\_id** (required): SendPost message UUID.
* **event\_type** (required): One of `delivered`, `bounced`, `deferred`, `soft_bounced`.
* **timestamp** (optional): ISO 8601 (RFC3339).
* **smtp\_code**, **smtp\_description**, **recipient** (optional).

Validation: each event must have `message_id`; `event_type` must be in the allowed set; if present, `timestamp` must be RFC3339. Empty body or no events → 400. On success the API returns **200 OK** immediately; events are processed asynchronously.

***

## SendPost Side

* The event ingestion endpoint authenticates requests with the **X-SP-Event-ApiKey** header (your Event Ingestion API Key).
* On successful ingestion, SendPost updates the TPSP's **agent\_last\_seen\_at** timestamp. The dashboard shows ✓ when the agent has reported recently, or ⚠️ if it has not been seen or is stale.

***

## Next Steps

* [Event types](/guides/custom-smtp/event-types) for CSDelivered, CSDeferred, CSHardBounced
* [Troubleshooting](/guides/custom-smtp/troubleshooting) agent and event ingestion
