Last updated: 2026-03-03•6 min read

Email Bounce and Rejection Reasons

When an email cannot be delivered, the receiving mail server returns an SMTP error. Different providers surface these in different ways. Truncus passes on the bounce type that AWS SES reports and classifies each email, so your system can act on it.

Where a failure shows up

WhereWhat you get
POST /api/v1/emails/send_syncThe terminal state in the same request: bounced or complained (or delivered). blocked when the send was refused before any attempt.
POST /api/v1/emails/sendOnly what happened to the request: blocked or failed before or at hand-off. A bounce arrives later as an event.
Webhook / event bouncedata.bounce_type (Permanent, Transient or Undetermined), data.bounce_subtype, data.recipients
GET /api/v1/emails/{id}intelligence.failure_reason, failure_category, is_retryable and recommended_action

Failure reasons on the email record

failure_reasonWhenrecommended_action
mailbox_not_foundPermanent bounceremove_from_list
mailbox_fullTransient or undetermined bounce (mailbox full, server busy)retry_later
spam_complaintRecipient marked the message as spamsuppress_permanently
suppressedAddress is on your suppression listreview_suppression_list
blockedRefused before sendingnone
send_failedThe email could not be sentcheck_configuration
cancelledCancelled before sendingnone

Permanent bounces and complaints add the address to your suppression list automatically. A later send to that address returns blocked with code ALL_RECIPIENTS_SUPPRESSED.

Common SMTP failures

FailureTypical SMTP codeRecommended action
Mailbox full552Retry later
Address does not exist550Remove address
Domain does not resolveNXDOMAINRemove address
Rejected by spam filter554Check domain reputation
Domain policy rejection550Review sender config
Transient delivery issue451Retry later

Which of these counts as a permanent or a transient bounce is decided by SES and reported in bounce_type and bounce_subtype. Act on those fields, not on the SMTP text.

Mailbox full

The recipient mailbox has exceeded its storage quota.

Typical SMTP response:

552 5.2.2 Mailbox full

This is a soft bounce — a temporary condition. SES reports it as a Transient bounce, and the email's failure_reason is mailbox_full. Retry after a delay. If it persists after several retries, treat the address as unreachable.

Address does not exist

The email address does not exist on the recipient server.

Typical SMTP response:

550 5.1.1 The email account that you tried to reach does not exist

This is a hard bounce: a Permanent bounce, failure_reason mailbox_not_found. Truncus adds the address to your suppression list. Remove it from your system as well. Continuing to send to non-existent addresses damages your domain reputation.

Domain does not resolve

The recipient domain has no valid MX record or is not resolvable in DNS.

Common causes: typo in the domain part of the email address, domain expired, domain deleted.

Treat as a hard bounce. Remove the address.

Rejected by spam filter

The message was rejected by the recipient server's spam filter.

Typical SMTP response:

554 5.7.1 Message rejected due to policy

Investigate your sending domain's reputation. Check your DKIM/SPF/DMARC configuration. Review message content for spam triggers.

Suppressed address

The address is on your suppression list — meaning it previously generated a hard bounce or spam complaint.

Truncus blocks sending to suppressed addresses to protect your domain reputation. Both send endpoints return:

{ "status": "blocked", "code": "ALL_RECIPIENTS_SUPPRESSED", "message_id": "msg_a2f7e8d1" }

Do not retry. Contact your recipient to verify their address if needed.

Transient delivery issue

The receiving server returned a transient error.

Typical SMTP response:

451 4.7.1 Try again later

This is a soft bounce. Retry after a delay.

Handling failures programmatically

With /emails/send, the send response only tells you whether the request was accepted. Bounces and complaints reach you as webhook events:

app.post('/truncus/webhook', async (req, res) => {
  const event = req.body

  if (event.event_type === 'bounce') {
    if (event.data.bounce_type === 'Permanent') {
      // hard bounce — Truncus has suppressed the address; remove it on your side too
      await removeEmailAddress(event.email.to)
    } else {
      // soft bounce — schedule your own retry with a limit
      await scheduleRetry(event.email.to)
    }
  }

  if (event.event_type === 'complaint') {
    await markAddressSuppressed(event.email.to)
  }

  res.status(200).send('ok')
})

A blocked send response means the address is suppressed or the domain cannot send this message: do not retry it. To get the bounce in the same request instead, call /emails/send_sync, which returns bounced or complained as the terminal state.

Bounce types

Hard bounce: permanent delivery failure. The address is invalid or permanently unreachable. Remove from your list immediately. Continuing to send to hard-bounced addresses degrades your sender reputation.

Soft bounce: temporary failure. The address is valid but temporarily unreachable. Retry after a delay, but set a retry limit.

bounce_typeTypefailure_reason
PermanentHardmailbox_not_found
TransientSoftmailbox_full
UndeterminedSoftmailbox_full

→ Start the Quickstart to see delivery state in practice

Email Bounce and Rejection Reasons | Truncus Manual