MailLandDocs

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

TypeDescriptionAuto-Suppression
HardPermanent failure: the mailbox does not exist or the domain is invalid.Global scope (immediate)
SoftTemporary failure: the mailbox is full or the server is busy.Marketing scope, 30-day expiry (on the first soft bounce)
BlockedThe 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 classificationType
InvalidRecipientHard
BadDomainHard
AdminBounceBlocked
InactiveMailboxHard
SpamBlockBlocked
SpamContentBlocked
AuthenticationFailedBlocked
QuotaIssuesSoft
NoAnswerFromHostSoft
DNSFailureSoft
RoutingErrorsSoft
MessageExpiredSoft
TransientFailureSoft
PolicyRelatedBlocked
InvalidSenderBlocked
TooManyRecipientsSoft
ProtocolErrorsSoft
BadConnectionSoft
Uncategorized, or anything unrecognizedUnknown: 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

  1. The recipient email is immediately added to the global suppression list
  2. All future emails (transactional and marketing) to this address are blocked
  3. A message.bounced webhook event is fired with bounce_type: "hard" (no separate suppression.added event is emitted)

Soft bounces

  1. The message status becomes Bounced
  2. 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 MessageExpired bounce, or its first message-too-large bounce (QuotaIssues with the enhanced code 5.3.4 or 5.2.3), suppresses nothing; another one within 30 days suppresses as usual.
  3. A message.bounced webhook event is fired with bounce_type: "soft". (Temporary failures are retried by the MTA itself before a bounce is reported to MailLand.)
  4. After 30 days, the suppression expires automatically

Blocked bounces

  1. The message status changes to Bounced (Failed for an AdminBounce), 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
  2. A message.bounced webhook event is fired with bounce_type: "blocked" (for an AdminBounce, a message.failed event with reason: "admin_bounce" instead)
  3. 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/statistics

Authenticate with Authorization: Bearer <token> or X-API-Key: <api key>.

Get bounce statistics
curl https://api.mail.land/v1/transactional/bounces/statistics \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
ParameterTypeDefaultDescription
fromdatetime30 days agoStart date
todatetimeNowEnd date
Bounce statistics response
{
  "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=50
Get recent bounces
curl "https://api.mail.land/v1/transactional/bounces/recent?limit=50" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
ParameterTypeDefaultDescription
limitint50Number of recent bounces to return
Recent bounces response
[
  {
    "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}/retry
Retry a bounced message
curl -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.

StatusCodeDescription
200-Retry accepted (or Retry already accepted for this attempt on a duplicate request)
400INVALID_REQUESTMessage is not bounced
400RECIPIENT_SUPPRESSEDRecipient is suppressed
422DOMAIN_NOT_VERIFIEDThe sending domain is no longer verified
429MARKETING_PAUSEDMarketing sending is paused for this tenant
404RESOURCE_NOT_FOUNDMessage 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:

PlanHard bounce warnSending paused (429) atComplaint warnComplaint pauseMin. sample sizeWindow
Free / Pro≥ 2%≥ 5%≥ 0.05%≥ 0.1%100 sends60 min
Max≥ 2%≥ 6%≥ 0.1%≥ 0.2%500 sends120 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_rejected bounces 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_full bounces 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

On this page