Tracking
Retrieve open/click tracking events and aggregate email statistics.
Tracking is automatically enabled for every outbound email. Sendy combines four signals to build a robust picture of email engagement.
Tracking signals
Each email collects up to five lifecycle timestamps. The unified status is derived from these.
- Open (pixel) — a 1×1 transparent image is injected before
</body>. Firesemail.openedand setsfirst_opened_at. Image-blocking clients (Apple Mail Privacy Protection, some Gmail proxies) may suppress this signal. - Click —
<a href>links are rewritten to go through a tracking redirect. Firesemail.clicked. The most reliable engagement signal. - Delivered (DSN) — Sendy requests a Delivery Status Notification (RFC 3461) and matches the report back via a
bounce+{email_id}@{domain}Return-Path. Firesemail.deliveredand setsdelivered_at. Coverage depends on the recipient MTA; Gmail honors success-DSN only partially. - Read (MDN) — Sendy adds the
Disposition-Notification-Toheader (RFC 8098). When the recipient client honors the read-receipt prompt, Sendy parses the returning MDN and setsread_at. Most webmail clients ignore MDN — expect <5% coverage in practice. - Replied — when a new inbound message contains
In-Reply-Tomatching a previously sent email, Sendy firesemail.repliedand setsfirst_replied_at. Requires a linked IMAP account.
Unified status
Every email exposes a derived unified_status field, computed with the following priority:bounced >replied >read >opened >delivered >sent >sending >queued >failed.
Endpoints
| Method | Path | Permission |
|---|---|---|
GET | tracking.read | |
GET | tracking.read |
Get Tracking Events
GET /api/v1/tracking/:emailId
Request
Response
Possible type values:open,click,delivered,read,replied.
{
"success": true,
"data": [
{
"id": "evt-uuid-1",
"emailId": "email-uuid",
"type": "delivered",
"createdAt": "2026-03-18T10:04:12Z"
},
{
"id": "evt-uuid-2",
"emailId": "email-uuid",
"type": "open",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"createdAt": "2026-03-18T10:05:00Z"
},
{
"id": "evt-uuid-3",
"emailId": "email-uuid",
"type": "click",
"url": "https://example.com/pricing",
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"createdAt": "2026-03-18T10:06:30Z"
},
{
"id": "evt-uuid-4",
"emailId": "email-uuid",
"type": "replied",
"createdAt": "2026-03-18T11:20:45Z"
}
]
}json
Get Global Stats
GET /api/v1/stats
Request
Response
All rates are percentages computed against total_sent. The query period defaults to the last 30 days; override with from and to (ISO 8601).
{
"success": true,
"data": {
"total_sent": 1250,
"total_opened": 654,
"total_clicked": 189,
"total_bounced": 15,
"total_failed": 5,
"total_queued": 0,
"total_sending": 0,
"total_delivered": 1130,
"total_read": 42,
"total_replied": 87,
"open_rate": 52.32,
"click_rate": 15.12,
"bounce_rate": 1.2,
"delivery_rate": 90.4,
"read_rate": 3.36,
"reply_rate": 6.96,
"period": {
"from": "2026-03-01T00:00:00Z",
"to": "2026-03-18T23:59:59Z"
}
}
}json