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).
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.).
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).
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:
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).
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.
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):
{
"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