Email Logs
Search, filter, and inspect detailed delivery logs for every email sent through Mail.Land
This page lists transactional messages only: campaign and automation mail (sys_* system messages included) are excluded. Use the campaign recipients endpoint (see Campaigns) for marketing/automation send history.
List Emails
GET https://api.mail.land/v1/transactional/logscurl "https://api.mail.land/v1/transactional/logs?limit=20" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | - | Opaque cursor from the previous page's nextCursor. Omit for the first page. A malformed or tampered cursor returns 400 INVALID_CURSOR. |
limit | int | 20 | Items per page |
status | string | - | Filter by status (see below) |
search | string | - | Search recipient, subject, or message ID |
from | datetime | 30 days ago | Start date |
to | datetime | Now | End date |
refresh | bool | false | Avoid a stale page: there is no longer a count cache to bypass |
Status Filters
| Value | Matches |
|---|---|
queued | Waiting in queue |
sent | Accepted by MTA |
deferred or retrying | Temporarily delayed |
delivered | Successfully delivered |
bounced | Hard bounce |
failed | System error or admin bounce |
opened | Recipient opened the email |
clicked | Recipient clicked a link |
complained | Recipient filed spam complaint |
{
"items": [
{
"messageId": "t_a1b2c3d4e5f6",
"recipient": "[email protected]",
"subject": "Your order has shipped",
"status": "delivered",
"sentAt": "2026-02-17T12:34:56Z",
"deliveredAt": "2026-02-17T12:34:58Z",
"openedAt": "2026-02-17T13:15:00Z",
"clickedAt": null,
"bounceReason": null,
"openCount": 2,
"clickCount": 0
},
{
"messageId": "t_d4e5f6a1b2c3",
"recipient": "[email protected]",
"subject": "Invoice #1234",
"status": "bounced",
"sentAt": "2026-02-17T12:30:00Z",
"deliveredAt": null,
"openedAt": null,
"clickedAt": null,
"bounceReason": "550 5.1.1 Mailbox not found",
"openCount": 0,
"clickCount": 0
}
],
"nextCursor": "eyJ2IjoxLCJzIjoiY3JlYXRlZGF0OmRlc2MiLCJrIjoi...",
"hasMore": true
}Status Priority
The status field reflects the highest-priority event for each email:
complained(highest)clickedopened- Delivery status:
queued→sent→deferred→delivered→bounced→failed
For example, if an email was delivered and then opened, the status shows opened.
A default 30-day date range is applied for performance. The search parameter filters by recipient email, subject line, or message ID (case-insensitive).
Log Stats
Get aggregate statistics for your email logs:
GET https://api.mail.land/v1/transactional/logs/statscurl "https://api.mail.land/v1/transactional/logs/stats" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."| Parameter | Type | Default | Description |
|---|---|---|---|
from | datetime | 7 days ago | Start date |
to | datetime | Now | End date |
emailType | int | - | 0 = Transactional, 1 = Marketing. Omit to cover all email types: unlike List Emails above, which is transactional-only. |
refresh | bool | false | Bypass cache |
{
"total": 4750,
"accepted": 4750,
"sent": 4700,
"delivered": 4680,
"opened": 1498,
"clicked": 195,
"bounced": 38,
"complained": 1,
"failed": 12,
"queued": 20,
"deliveryRate": 99.57,
"openRate": 32.01,
"clickRate": 13.02,
"bounceRate": 0.81,
"complaintRate": 0.021,
"source": "clickhouse",
"queryTimeMs": 32
}Rate calculations:
| Rate | Formula |
|---|---|
deliveryRate | delivered / sent * 100 |
openRate | opened / delivered * 100 |
clickRate | clicked / delivered * 100 |
bounceRate | bounced / sent * 100 |
complaintRate | complained / sent * 100 (3 decimal places) |
Response headers indicate cache status:
| Header | Values |
|---|---|
X-Cache | HIT, MISS, or FRESH |
X-Stats-Source | cache or clickhouse |
Cache-Control | Always no-store, no-cache, must-revalidate |
Email Detail
Get full details for a specific email, including the event timeline:
GET https://api.mail.land/v1/transactional/logs/{messageId}curl https://api.mail.land/v1/transactional/logs/t_a1b2c3d4e5f6 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"messageId": "t_a1b2c3d4e5f6",
"recipient": "[email protected]",
"fromEmail": "[email protected]",
"subject": "Your order has shipped",
"status": "opened",
"sentAt": "2026-02-17T12:34:56Z",
"deliveredAt": "2026-02-17T12:34:58Z",
"openedAt": "2026-02-17T13:15:00Z",
"clickedAt": null,
"createdAt": "2026-02-17T12:34:55Z",
"bounceReason": null,
"bounceCategory": null,
"ipAddress": null,
"retryCount": 0,
"smtpResponse": "250 2.0.0 OK",
"openCount": 2,
"clickCount": 0,
"htmlContent": "<html>...</html>",
"textContent": "Your order has shipped...",
"events": [
{
"eventType": "delivered",
"timestamp": "2026-02-17T12:34:58Z",
"ipAddress": null,
"userAgent": null,
"linkUrl": null,
"bounceType": null,
"bounceReason": null,
"smtpResponse": "250 2.0.0 OK",
"deviceType": null,
"browser": null,
"country": null,
"city": null
},
{
"eventType": "opened",
"timestamp": "2026-02-17T13:15:00Z",
"ipAddress": "203.0.113.45",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"linkUrl": null,
"bounceType": null,
"bounceReason": null,
"smtpResponse": null,
"deviceType": "desktop",
"browser": "Chrome",
"country": "US",
"city": "San Francisco"
},
{
"eventType": "opened",
"timestamp": "2026-02-17T14:30:00Z",
"ipAddress": "203.0.113.45",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0)",
"linkUrl": null,
"bounceType": null,
"bounceReason": null,
"smtpResponse": null,
"deviceType": "mobile",
"browser": "Safari",
"country": "US",
"city": "San Francisco"
}
]
}The events array is sourced from ClickHouse and ordered by timestamp. If ClickHouse is temporarily unavailable, the email detail is still returned from PostgreSQL but events will be an empty array.
Event Fields
| Field | Description |
|---|---|
eventType | delivered, opened, clicked, bounced, complained, and also accepted, sent, deferred, admin_bounce, oob_bounce, expired |
timestamp | When the event occurred (UTC) |
ipAddress | Client IP (for opens/clicks) |
userAgent | Client user agent string |
linkUrl | Clicked URL (for clicked events) |
bounceType | hard, soft, or unknown (for bounced events) |
bounceReason | SMTP response (for bounced events) |
smtpResponse | Remote server response (for delivered events) |
deviceType | desktop, mobile, or tablet |
browser | Browser name (Chrome, Safari, Firefox, etc.) |
country | ISO country code |
city | City name |
Retry a Failed Email
Retry delivery of a bounced or failed email:
POST https://api.mail.land/v1/transactional/logs/{messageId}/retrycurl -X POST https://api.mail.land/v1/transactional/logs/t_a1b2c3d4e5f6/retry \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."The message must be in Bounced or Failed status, and the recipient must not be suppressed.
| Status | Code | Description |
|---|---|---|
200 | - | Retry accepted |
400 | INVALID_REQUEST | Email is not bounced or failed |
400 | RECIPIENT_SUPPRESSED | Recipient is on the suppression list |
404 | RESOURCE_NOT_FOUND | Message not found: not EMAIL_NOT_FOUND |
422 | DOMAIN_NOT_VERIFIED | The sending domain is no longer verified |
429 | MARKETING_PAUSED | Marketing sending is currently paused for this workspace |
422 | RETRY_ATTACHMENTS_UNAVAILABLE | The message had attachments that can no longer be recovered; send it again with its attachments instead |
422 | RETRY_ATTACHMENTS_UNKNOWN | The message was sent before attachments were recorded, so a retry cannot guarantee them; send it again instead |
429 | PLATFORM_CAPACITY_PROTECTION | New sending is briefly paused to protect platform capacity; nothing was changed, retry shortly |
503 | RETRY_ATTACHMENT_STORAGE_UNAVAILABLE | The attachments could not be read right now; nothing was changed, retry shortly |
The retry creates a new email job with the original content and queues it for delivery. Retried copies are sent without open/click tracking.
Next Steps
- Analytics Overview: aggregate event summaries and rates
- Advanced Analytics: geographic, device, and time-of-day breakdowns
- Bounces: understand bounce handling and retries