Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Bounce Handling

A bounce is a delivery failure. ScaiSend classifies bounces, records them on the message timeline, fans out bounce events to webhooks, and adds the recipient to the suppression list so you don't repeat the failure. This page explains how.

Two paths to a bounce#

Bounces arrive two ways:

  1. Synchronous SMTP response. The recipient MX returns a 5xx at the end of the SMTP conversation. ScaiSend sees it immediately.
  2. Asynchronous DSN. The recipient MX accepts the message (returns 2xx), but later — after internal routing — can't deliver. It sends a Delivery Status Notification (RFC 3464) back to the envelope sender. ScaiSend's inbound SMTP server receives and parses this.

Both paths end up the same: a bounce event on the message, the address added to the bounce suppression list.

Synchronous bounces#

At the end of RCPT TO: or DATA, the recipient can reply with:

Response Classification Action
250 OK Delivered Record delivered event, update message status
4xx Temporary failure (deferred) Retry with exponential backoff; record deferred event
5xx Permanent failure (bounce) Record bounce event; add to bounce suppression list

ScaiSend parses the response string to classify further. A 550 5.1.1 User unknown is a hard bounce (recipient doesn't exist). A 552 5.2.2 Mailbox full is a soft bounce (might succeed later if retried). A 550 5.7.1 Message rejected due to content is a block (policy decision; not necessarily permanent).

Bounce types recorded#

bounce_type Trigger
hard Permanent failure: invalid recipient, non-existent mailbox, account closed
soft Temporary failure that exhausted retries: mailbox full, message too large
block Sender reputation issue: IP blocklisted, content rejected

Asynchronous bounces (DSNs)#

Sometimes the recipient MX accepts a message, queues it internally, and only later discovers it can't deliver (e.g., forward loop, downstream server unreachable, virus-scan rejection). The convention is to send a DSN back to the envelope sender.

ScaiSend's inbound SMTP server (port 25) accepts these DSNs. The parser:

  1. Reads the multi-part message body.
  2. Extracts the message/delivery-status part, which contains machine-readable reporting.
  3. Finds the Original-Recipient, Action (e.g., "failed"), Status (SMTP enhanced status code), and Diagnostic-Code fields.
  4. Matches the DSN to the original message via the Message-ID or the X-ScaiSend-Message-Id header that ScaiSend injected.
  5. Records a bounce event with parsed fields and adds the recipient to the suppression list.

What the inbound server accepts#

The inbound server is narrowly scoped: it accepts DSN messages, ARF feedback-loop reports, and refuses everything else. It's not a general-purpose MTA. Arbitrary inbound mail from the internet is rejected at the SMTP conversation level.

For the inbound server to work, port 25 must be reachable and an A/AAAA record pointing to it. See Deployment.

Retry policy for deferrals#

A 4xx response doesn't give up immediately. ScaiSend retries with exponential backoff:

Attempt Delay after previous attempt
1 (initial send)
2 ~60 seconds
3 ~5 minutes
4 ~15 minutes
5 ~1 hour
6 (last) ~4 hours

Actual delays have jitter to avoid thundering herds, and are bounded by SMTP_MAX_RETRIES (default 5 retries = 6 attempts total) and SMTP_RETRY_BASE_DELAY (default 60 seconds).

After the final retry, if still deferred, ScaiSend classifies as a soft bounce and marks the message BOUNCED.

Greylisting#

Some recipient MXs greylist — they return 4xx on first attempt from an unknown sender, expecting a real MTA to retry. ScaiSend detects the common greylisting responses (e.g., 4.7.1 with specific wording like "greylisted") and retries more aggressively (shorter initial delay), which satisfies the greylist check.

You typically see one deferred event, then a delivered event seconds later. Nothing to do; this is working as intended.

Suppression#

Every hard bounce automatically adds the recipient to the tenant's bounce suppression list. Future sends to that address are dropped (status FAILED, event dropped, reason suppressed_bounce) unless you bypass with mail_settings.bypass_bounce_management: {enable: true}.

Soft bounces also add to the list by default. If you'd rather let soft-bounced addresses be retried on future sends, delete them from the list after they resolve:

bash
1
2
curl -X DELETE https://scaisend.scailabs.ai/v3/suppression/bounces/user@example.com \
  -H "Authorization: Bearer $SCAISEND_API_KEY"

See Suppressions for the full suppression model.

Event payload#

A bounce event:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "event_id": "evt_01HXYZ",
  "event_type": "bounce",
  "timestamp": 1713888000,
  "message_id": "msg_01ABC",
  "recipient_email": "invalid@example.com",
  "tenant_id": "tnt_acme",
  "bounce_type": "hard",
  "bounce_reason": "User unknown",
  "smtp_response": "550 5.1.1 User unknown",
  "metadata": {
    "diagnostic_code": "smtp; 550 5.1.1 <invalid@example.com> User unknown in virtual mailbox table",
    "reporting_mta": "dns; mx1.example.com"
  }
}

metadata.diagnostic_code is what the recipient MX actually said (for synchronous bounces, it's the raw SMTP response; for async DSNs, it's the Diagnostic-Code field from the DSN). Log this for support triage.

Interpreting bounce reasons#

Common bounce reasons and their meaning:

SMTP class Typical cause What to do
5.1.1 Recipient doesn't exist Remove from your list; the address is dead
5.1.10 Recipient address null-routed Same as above
5.2.1 Mailbox disabled User left the company or was deactivated
5.2.2 Mailbox full Soft bounce; retry later possibly
5.4.4 Unable to route DNS issue at recipient; usually transient
5.5.0 Syntax error in message Check your message structure; template bug
5.7.1 Message rejected for policy Spam filter, IP reputation, content block
5.7.26 DMARC failure Your DKIM/SPF/DMARC isn't aligned — fix DNS

Reputation management#

Hard bounce rate is the single most important deliverability metric. Over 2% and you'll start getting rate-limited by major providers. Over 5% and you'll be outright blocked by some.

Monitor:

bash
1
2
curl "https://scaisend.scailabs.ai/v3/stats?start_date=2026-04-01&end_date=2026-04-23" \
  -H "Authorization: Bearer $SCAISEND_API_KEY"

Calculate bounces / requests. If it's trending up:

  • Audit your list sources. Did you import addresses from a suspect list?
  • Audit your signup flow. Are you validating emails at registration?
  • Check a random sample of bounced addresses. If they're all 5.1.1, your list has invalid addresses. If they're 5.7.*, your reputation is the problem.
Updated 2026-05-17 01:33:27 View source (.md) rev 1