Deliverability and Bounces via API and MCP
Pull outbound deliverability rollups and per-recipient hard/soft bounce reasons through the REST API and MCP.
Article details
Type, difficulty, plans, and last updated info.
▼
Article details
Type, difficulty, plans, and last updated info.
- Type
- Reference
- Difficulty
- Intermediate
- Plans
- Starter · Pro · Agency
- Last updated
- Sep 10, 2026
TrekMail's dashboard surfaces two kinds of bounce data on every domain's Stats tab:
- A 30-day rollup: sent, delivered, soft-bounce, and hard-bounce counts, plus delivery and bounce rates.
- A per-recipient list: the last 50 outbound bounces with the receiver's SMTP status code and response, so you can see why a specific message failed.
Both are now available through the REST API and the MCP server. An agent can pull bounce reasons, summarise reputation health, and feed list-hygiene workflows without ever opening the dashboard.
What's exposed
| Surface | Endpoint | MCP tool | Returns |
|---|---|---|---|
| Domain rollup | GET /api/v1/domains/{domain}/deliverability |
get_domain_deliverability |
sent, delivered, soft_bounce, hard_bounce, forwarding_bounces_excluded, delivery_rate, bounce_rate, status ("good" / "warning" / "poor") for a configurable window (default 30 days, max 90). |
| Domain bounces | GET /api/v1/domains/{domain}/bounces |
list_domain_bounces |
Paginated list of hard/soft bounces with recipient_email, event_type, smtp_status_code, smtp_response, occurred_at, mailbox_id. |
| Mailbox bounces | GET /api/v1/mailboxes/{mailbox}/bounces |
list_mailbox_bounces |
Same shape, scoped to one mailbox for per-sender reputation triage. |
All three require domains:read (or mailboxes:read for the mailbox-scoped list). Read-only. No idempotency key needed.
The API uses the same deliverability data as the dashboard's stats cards, so the two views stay aligned.
REST API: quick examples
Domain rollup
curl -sS -H "Authorization: Bearer $TM_TOKEN" \
"https://trekmail.net/api/v1/domains/123/deliverability?days=30" | jq .
{
"data": {
"from": "2026-04-26T00:00:00+00:00",
"to": "2026-05-26T23:59:59+00:00",
"sent": 4180,
"delivered": 4112,
"soft_bounce": 22,
"hard_bounce": 46,
"forwarding_bounces_excluded": 7,
"delivery_rate": 0.9837,
"bounce_rate": 0.0163,
"status": "good"
}
}
status is the same three-state signal the dashboard renders:
- good: bounce rate below 2%.
- warning: bounce rate between 2% and 5%.
- poor: bounce rate at or above 5%. Review and clean the sending list.
forwarding_bounces_excluded reports how many forwarding-related bounces were dropped from the rate calculations (consistent with the dashboard, which treats those as routing artefacts, not sender-list problems).
Per-recipient bounce list
curl -sS -H "Authorization: Bearer $TM_TOKEN" \
"https://trekmail.net/api/v1/domains/123/bounces?days=7&type=hard&limit=50" | jq .
{
"data": [
{
"id": 994821,
"occurred_at": "2026-05-26T18:14:02+00:00",
"recipient_email": "lost@example.com",
"event_type": "hard_bounce",
"smtp_status_code": "550",
"smtp_response": "5.1.1 The email account that you tried to reach does not exist.",
"mailbox_id": 7741,
"domain_id": 123
}
],
"pagination": { "total": 17, "limit": 50, "offset": 0 }
}
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
days |
integer (1-90) | 30 | Look-back window from now. |
type |
hard / soft / all |
all |
Filter by bounce class. |
recipient |
string (max 255) | Empty | Case-insensitive partial match on recipient_email. |
limit |
integer (1-100) | 50 | Page size. |
offset |
integer (≥ 0) | 0 | Skip count for pagination. |
Mailbox-scoped list
For per-sender reputation triage, scope to one mailbox:
curl -sS -H "Authorization: Bearer $TM_TOKEN" \
"https://trekmail.net/api/v1/mailboxes/7741/bounces?days=14&type=soft" | jq .
Same response shape as the domain endpoint.
Privacy of SMTP responses
TrekMail removes internal diagnostic information before it returns an SMTP response. The remaining message is the same one shown to the account owner in the dashboard and is intended to help diagnose delivery, not to expose server internals.
MCP tools
All three tools accept the same parameters as the REST endpoints. They are read-only and do not change mail or account settings.
get_domain_deliverability
{
"name": "get_domain_deliverability",
"arguments": {
"domain_id": 123,
"days": 30
}
}
list_domain_bounces
{
"name": "list_domain_bounces",
"arguments": {
"domain_id": 123,
"type": "hard",
"days": 7,
"limit": 100
}
}
list_mailbox_bounces
{
"name": "list_mailbox_bounces",
"arguments": {
"mailbox_id": 7741,
"recipient": "@example.com",
"limit": 50
}
}
Bulk-sender deliverability headers
If you send marketing or subscribed bulk mail, major mailbox providers may require one-click unsubscribe headers. Google applies this rule to marketing and subscribed messages from senders that exceed its bulk-sender threshold; it does not apply the one-click rule to transactional messages. There are two ways to attach the headers:
Per-message (granular). Pass them through the headers field of POST /api/v1/messages/send:
{
"to": ["recipient@example.com"],
"subject": "...",
"body": {"text": "..."},
"headers": {
"List-Unsubscribe": "<mailto:bounces@mydomain.com?subject=unsubscribe>, <https://mydomain.com/u/abc123>",
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click"
}
}
The headers field accepts a small whitelist: List-Unsubscribe, List-Unsubscribe-Post, Reply-To, and any X-* custom tracking header. Header injection (CR/LF) and managed headers (From, Subject, Date, Message-Id, Authentication-Results, DKIM-Signature, etc.) are rejected with 422.
Account-wide (set once). If every outbound message from this account is automated, you can toggle auto_list_unsubscribe on the account. When enabled, the platform adds a mailto-only List-Unsubscribe header to every outbound message that does not already have one. It does not add List-Unsubscribe-Post, so this fallback is not RFC 8058 one-click unsubscribe. For provider-compliant one-click unsubscribe, supply both headers per message with your own HTTPS unsubscribe endpoint, as in the example above. Caller-supplied headers always win. The toggle defaults to OFF, and existing accounts are unchanged.
For one-to-one personal mail, leave the toggle off. Gmail may show an Unsubscribe button next to the sender when this header is present, which is usually not right for a conversation.
Patterns for AI agents
A few high-value flows that drop out of these endpoints:
- Weekly reputation digest. Each Monday, call
get_domain_deliverabilityfor every domain on the account and post a summary into Slack/Teams. Surface only domains wherestatusiswarningorpoor. - Bounce-driven list hygiene. Call
list_domain_bounces?type=hard&days=14, deduplicaterecipient_email, then suppress those addresses from your sending list. Hard bounces usually mean the recipient address no longer exists, and re-sending wastes deliverability budget. - Per-sender triage. When a single mailbox's
bounce_ratejumps, calllist_mailbox_bounceson it and group bysmtp_status_code. A burst of 550s can mean the address list went stale; a burst of 421s can mean the receiving mail server rate-limited you. - Customer-support investigation. When a user reports that email did not arrive, ask the agent to call
list_domain_bounces?recipient=<their-address>. The SMTP response may point to the next action, such as a full recipient mailbox, recipient block, or DMARC rejection.
Versioning
These endpoints follow the same versioning contract as the rest of the v1 API: additive changes only, no breaking field renames without a v2/ namespace.
Related
- Spam Metrics: inbound spam protection telemetry (
get_spam_metrics,get_spam_summary). - Email Verifier: pre-send list cleaning so bounces do not happen in the first place.
- API Overview: authentication, scopes, rate limits, and idempotency.
Related articles
Jump to nearby guides that continue the workflow.