Bounces
Understand bounce types, categories, automatic suppression, and retry behavior
When an email cannot be delivered, the receiving server sends a bounce. MailLand classifies bounces, automatically suppresses addresses that will never accept mail, and retries transient failures.
Bounce Types
| Type | Description | Auto-Suppression |
|---|---|---|
| Hard | Permanent failure: the mailbox does not exist or the domain is invalid. | Global scope (immediate) |
| Soft | Temporary failure: the mailbox is full or the server is busy. | Marketing scope, 30-day expiry (on the first soft bounce) |
| Blocked | The recipient's mailbox is fine: the refusal was about our sending: a provider's spam filtering, a sender-authentication/reputation problem such as SPF, DKIM, DMARC or IP reputation, a receiver's policy verdict, a refusal of the envelope sender, or an operator bouncing the message out of MailLand's own queue. | Not auto-suppressed: this is a signal about our sending, not the recipient |
Bounce Categories
The bounce-breakdown API (GET /v1/deliverability/bounce-breakdown) groups every bounce by the
classification the mail transfer agent itself assigns to the SMTP rejection, then maps that
classification to hard, soft or blocked. The table below is the complete, pinned production
vocabulary: anything the host emits that isn't in it is counted as unknown rather than guessed at:
| Host classification | Type |
|---|---|
InvalidRecipient | Hard |
BadDomain | Hard |
AdminBounce | Blocked |
InactiveMailbox | Hard |
SpamBlock | Blocked |
SpamContent | Blocked |
AuthenticationFailed | Blocked |
QuotaIssues | Soft |
NoAnswerFromHost | Soft |
DNSFailure | Soft |
RoutingErrors | Soft |
MessageExpired | Soft |
TransientFailure | Soft |
PolicyRelated | Blocked |
InvalidSender | Blocked |
TooManyRecipients | Soft |
ProtocolErrors | Soft |
BadConnection | Soft |
Uncategorized, or anything unrecognized | Unknown: Hard when the reply's enhanced status code names the recipient address as permanently unusable (such as 5.1.1) |
Two endpoints further down this page report bounces in a vocabulary of their own.
/v1/transactional/bounces/statistics counts hardBounces and softBounces from the same decision
that suppresses (or does not suppress) the address, so a blocked bounce is never counted as hard or
soft; its byCategory groups the host classification above into a coarser set (invalid_recipient,
bad_mailbox, bad_domain, mailbox_full, content_rejected, policy_reason, general_bounce).
/v1/transactional/bounces/recent returns each message's host classification itself as
bounceCategory.
Automatic Handling
Hard bounces
- The recipient email is immediately added to the global suppression list
- All future emails (transactional and marketing) to this address are blocked
- A
message.bouncedwebhook event is fired withbounce_type: "hard"(no separatesuppression.addedevent is emitted)
Soft bounces
- The message status becomes
Bounced - The address is suppressed for Marketing mail for 30 days (transactional mail is still delivered): on the first soft bounce, not after retries. Exception: an address's first
MessageExpiredbounce, or its first message-too-large bounce (QuotaIssueswith the enhanced code5.3.4or5.2.3), suppresses nothing; another one within 30 days suppresses as usual. - A
message.bouncedwebhook event is fired withbounce_type: "soft". (Temporary failures are retried by the MTA itself before a bounce is reported to MailLand.) - After 30 days, the suppression expires automatically
Blocked bounces
- The message status changes to
Bounced(Failedfor anAdminBounce), but the recipient's address is not added to any suppression list: a blocked bounce is a statement about our sending, not about the recipient's mailbox - A
message.bouncedwebhook event is fired withbounce_type: "blocked"(for anAdminBounce, amessage.failedevent withreason: "admin_bounce"instead) - A sustained rate of blocked bounces raises an internal alert for manual review; there is no automatic pause of sending
Escalation to a hard bounce isn't simply "after 3 soft bounces." It requires at least 3 recorded bounces spread across at least 7 days, and only certain bounce reasons are eligible: bounces caused by mailbox quota, DNS or host lookup issues, transient failures, connection problems, routing errors, protocol errors, or message expiry do not escalate. When an address does escalate, the suppression upgrades from Marketing scope to a hard bounce (Global scope) and expires automatically after 90 days.
A blocked bounce (SpamBlock, SpamContent, AuthenticationFailed, PolicyRelated, InvalidSender, AdminBounce) is never folded into hard or
soft: doing so would either suppress a perfectly reachable recipient forever, or hide a real
sender-reputation problem behind a label the account owner cannot act on. It also never escalates
to a permanent suppression through repetition, unlike an eligible soft bounce: the repeated signal
is about the sending domain's reputation, not the recipient.
Bounce Statistics
Get aggregate bounce statistics for a time period:
GET https://api.mail.land/v1/transactional/bounces/statisticsAuthenticate with Authorization: Bearer <token> or X-API-Key: <api key>.
curl https://api.mail.land/v1/transactional/bounces/statistics \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."| Parameter | Type | Default | Description |
|---|---|---|---|
from | datetime | 30 days ago | Start date |
to | datetime | Now | End date |
{
"totalBounces": 1125,
"hardBounces": 450,
"softBounces": 385,
"generalBounces": 290,
"byCategory": {
"invalid_recipient": 380,
"mailbox_full": 345,
"content_rejected": 185,
"policy_reason": 95,
"bad_domain": 70,
"general_bounce": 50
}
}Recent Bounces
Get the most recent bounced messages:
GET https://api.mail.land/v1/transactional/bounces/recent?limit=50curl "https://api.mail.land/v1/transactional/bounces/recent?limit=50" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Number of recent bounces to return |
[
{
"messageId": "t_a1b2c3d4e5f6",
"recipientEmail": "[email protected]",
"subject": "Your order has shipped",
"bounceCategory": "InvalidRecipient",
"bounceReason": "550 5.1.1 The email account does not exist",
"bouncedAt": "2026-02-17T12:34:56Z",
"retryCount": 0
},
{
"messageId": "t_d4e5f6a1b2c3",
"recipientEmail": "[email protected]",
"subject": "Invoice #1234",
"bounceCategory": "QuotaIssues",
"bounceReason": "552 5.2.2 Mailbox full",
"bouncedAt": "2026-02-17T11:00:00Z",
"retryCount": 2
}
]Results are ordered by bouncedAt descending, limited to the last 90 days. bouncedAt is the message's creation time, not a separately tracked bounce timestamp.
Retry a Bounced Message
Manually retry delivery of a bounced message:
POST https://api.mail.land/v1/transactional/bounces/{messageId}/retrycurl -X POST https://api.mail.land/v1/transactional/bounces/t_a1b2c3d4e5f6/retry \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."The retry re-sends the original content through MailLand's outbox. Open and click tracking are OFF on retried copies: the original send's tracking choice isn't recoverable from the message row.
| Status | Code | Description |
|---|---|---|
200 | - | Retry accepted (or Retry already accepted for this attempt on a duplicate request) |
400 | INVALID_REQUEST | Message is not bounced |
400 | RECIPIENT_SUPPRESSED | Recipient is suppressed |
422 | DOMAIN_NOT_VERIFIED | The sending domain is no longer verified |
429 | MARKETING_PAUSED | Marketing sending is paused for this tenant |
404 | RESOURCE_NOT_FOUND | Message not found |
You cannot retry a message if the recipient is suppressed. Remove the suppression first (see Suppressions), then retry.
Bounce Rate Thresholds
Thresholds are plan defaults, evaluated once at least the minimum sample size of sends has occurred in the evaluation window:
| Plan | Hard bounce warn | Sending paused (429) at | Complaint warn | Complaint pause | Min. sample size | Window |
|---|---|---|---|---|---|---|
| Free / Pro | ≥ 2% | ≥ 5% | ≥ 0.05% | ≥ 0.1% | 100 sends | 60 min |
| Max | ≥ 2% | ≥ 6% | ≥ 0.1% | ≥ 0.2% | 500 sends | 120 min |
Sending is paused (API 429) when the pause threshold is reached; this lowers your sender score as well.
Deliverability Holds
A pause-threshold breach also places a durable deliverability hold on the workspace, separate
from the transient 429 pause above. While a hold is active, every send, transactional and
marketing alike, is refused: 403 ACTION_REQUIRED from the API, a temporary 451 4.7.0 over SMTP relay, so your mail server keeps the message queued and retries.
- The hold is placed once per breach episode, not repeated on every send.
- It persists until MailLand support reviews and lifts it; a recovering bounce or complaint rate does not lift it automatically, there is no auto-lift.
- The workspace's Owners and Admins receive an email as soon as the hold is placed.
Best Practices
- Clean your lists: validate email addresses before sending with Email Validation. Remove addresses that consistently bounce.
- Monitor bounce categories: a spike in
content_rejectedbounces may indicate a content issue, not a list quality problem. - Don't retry hard bounces: hard bounces are permanent. Retrying wastes quota and damages reputation.
- Watch soft bounce patterns: repeated
mailbox_fullbounces from the same domain may indicate a provider-level issue. - Use the deliverability dashboard: track bounce rates by provider to catch domain-specific problems early.
Next Steps
- Suppressions: manage the suppression list
- Deliverability Overview: monitor sender score and trends
- Webhooks Events: receive
message.bouncedevents