# Detect and handle bounced email

Source: https://developer.nylas.com/docs/cookbook/use-cases/build/handle-bounced-email/

You send an email through a user's mailbox and it bounces. Without bounce handling, you never find out: the message just never arrives, and your app keeps emailing an address that will never accept mail. That quietly damages the sender's reputation and your delivery rates.

Nylas surfaces bounces as a webhook. When a provider returns a Non-Delivery Report, the `message.bounce_detected` trigger fires with the failed address, the reason, and the SMTP code, so your app can react the moment a send fails instead of discovering it in a support ticket.

## How do I get notified when an email bounces?

Subscribe a webhook to the `message.bounce_detected` trigger. Nylas fires it when it detects a Non-Delivery Report (NDR) in the sender's mailbox for a message sent through the grant. The trigger is available on 4 providers (Google, Microsoft, iCloud, and Yahoo) because it depends on the provider generating an NDR in the first place.

Create the subscription the same way as any other webhook, adding `message.bounce_detected` to your `trigger_types`. The [webhooks recipe](/docs/cookbook/use-cases/build/realtime-webhooks/) covers the full setup, verification, and signature checks.

## What's in a bounce notification?

The notification arrives in the standard webhook envelope with the bounce details under `data.object`. The 5 fields that matter are `bounced_addresses` (the address that failed), `bounce_reason` (a human-readable explanation), `type` (a category such as `mailbox_unavailable`), `code` (the SMTP status code as a string, like `"550"`), and `bounce_date`. The payload also includes `origin`, the original message.

The example below shows the shape your handler parses. Note that `code` is a string, not an integer, so compare it as `"550"`.

```json
{
  "type": "message.bounce_detected",
  "data": {
    "grant_id": "<NYLAS_GRANT_ID>",
    "object": {
      "bounced_addresses": "no-such-user@example.com",
      "bounce_reason": "The email account that you tried to reach does not exist.",
      "type": "mailbox_unavailable",
      "code": "550",
      "bounce_date": "Mon, 08 Jun 2026 14:21:00 +0000"
    }
  }
}
```

## How do I handle hard versus soft bounces?

The `code` and `type` fields tell you whether a failure is permanent. SMTP codes in the 500 range are hard bounces: the address is invalid or the mailbox is gone, signaled by a `type` like `mailbox_unavailable`. Codes in the 400 range are soft bounces, temporary problems like a full mailbox or a throttled server that are safe to retry later.

Add permanently failed addresses to a suppression list and stop sending to them. Retrying a hard bounce wastes effort and erodes the shared sending reputation across all 4 providers, which lowers inbox placement for your other mail. Treat soft bounces with a capped retry instead.

## Things to know about bounce detection

Bounce detection depends on the provider, so a few constraints are worth planning for. The trigger fires on the same 4 providers (Google, Microsoft, iCloud, Yahoo) and only when the provider issues an NDR that Nylas finds in the sender's mailbox, so standard IMAP and Exchange (EWS) accounts don't produce `message.bounce_detected` events. Detection is also asynchronous: the NDR can arrive minutes after the original send.

If you send through the Nylas transactional Email API rather than a connected mailbox, watch the `message.transactional.bounced` trigger instead; it's one of 4 `message.transactional.*` deliverability events (bounced, complaint, delivered, rejected). See [sending errors](/docs/v3/email/sending-errors/) for provider error codes returned at send time.

## What's next

- [Get real-time updates with webhooks](/docs/cookbook/use-cases/build/realtime-webhooks/) to set up the subscription
- [Sending errors](/docs/v3/email/sending-errors/) for errors returned synchronously at send time
- [message.bounce_detected reference](/docs/reference/notifications/messages/message-bounce_detected/) for the full payload schema
- [Track email opens and replies](/docs/v3/email/message-tracking/) for the other engagement webhooks