**Infrastructure → Inbound → Messages** lists every message received at your domains, newest first, with one row per **message and receiving domain**. A message addressed to two of your receiving domains is two rows, because it is two deliveries.

The row shows when it was received, the sender, the recipient, the subject, any **failing** SES verdicts, the outcome, and the HTTP status and time of the last delivery attempt. Above the table a strip counts the window's messages, deliveries, parked messages, spam and virus failures, and replies.


  The log holds addresses, subject lines and verdicts — what it needs to say what arrived and what happened. It never holds a body or an attachment. Those exist only in your own bucket, which is why the raw message is a link into **your AWS console** rather than a download.


## Finding a message

Search matches the sender, the recipient and the subject. Filters narrow by receiving domain, by outcome, by a failed verdict (spam, virus, SPF, DKIM, DMARC), and by window: the last 24 hours, 7 days or 30 days. Filters are in the page URL, so a filtered view can be shared.

## Outcomes

| Outcome | Meaning | Recoverable? |
|---|---|---|
| **Delivered** | Your endpoint answered `2xx`. | — |
| **Rejected** | Your endpoint answered a `4xx` other than `429`. That is read as "I will never accept this message", and nothing retries. | Only by **Redeliver**, once the endpoint is fixed. |
| **Dropped** | A verdict posture on the domain discarded it — a virus with **Deliver nothing**, for instance. | Not while the posture stands. |
| **No route** | The domain is known, but the recipient matched nothing in its [allow list](/inbound/delivery-webhooks#the-allow-list). | Fix the allow list, then **Redeliver**. |
| **Parked** | Not delivered, and needs a person. The reason says why. | Yes — see below. |

Only **Parked** is a state something can still be done about. The raw message is in your bucket regardless of outcome.

### Why a message parks

| Reason shown | What it means | What to do |
|---|---|---|
| No receiving domain matched | The message arrived at a domain that is not in the published routing — deleted, not yet verified, or with no webhook. | Add or verify the domain and set its webhook, then Redeliver. |
| No published configuration for this domain | The intake function found no routing object in the bucket at all — normally only in the minutes after the stack was created. | Wait for the stack to reach **active**; SendOps publishes on its own. |
| The published configuration was too old to use | The routing object's version is one the deployed function does not understand. | Apply the pending stack update. |
| The message was larger than the intake function accepts | Over the 30 MB message ceiling. | The message is stored; it cannot be delivered by this pipeline. |
| The message had more MIME parts than the parser accepts | Over 64 parts. Parked deliberately rather than delivered without some of its attachments. | As above. |
| The message could not be parsed | Malformed beyond what the parser tolerates. Lesser defects are delivered and noted as a **MIME defect** on the message. | Open the raw message in your console. |
| The webhook delivery did not succeed | Your endpoint answered `429` or `5xx`, refused the connection, or did not answer within ten seconds. | See [When delivery fails](#when-delivery-fails). |

## Opening a message

Expanding a row shows every SES verdict including the passes, the receiving domain and every envelope recipient, the outcome with its reason, the webhook status and attempt count, the processing time, the module version that handled it, and a **history** of every state the message passed through — the log is append-only, so a message that parked and was later redelivered shows both, and the row reads the latest.

A message SendOps matched to something it sent shows a banner naming the broadcast or workflow; see [Reply Intelligence](/inbound/reply-intelligence).

## When delivery fails

What happens after a failed delivery depends on whether your endpoint said it did not take the message:

- **It answered `429` or `5xx`, or nothing accepted the connection.** The function retries three times over about ten seconds, then fails the invocation so Lambda's own retries try again with a fresh claim; after those, the notification is in your dead-letter queue. The message parks with the detail **endpoint error**, and it comes back on its own once the queue is redriven.
- **The request timed out.** Your endpoint may have processed it. The delivery claim is kept and nothing retries, because a duplicate ticket is worse than a parked message. The message parks with the detail **ambiguous transport**, and recovering it needs a deliberate **Redeliver**.


  Answering `4xx` for a transient problem — a full disk, a database that is down — records the message as **Rejected** and stops every retry. Answer `5xx` and it comes back. The [contract](https://developers.sendops.dev/api-reference/inbound-webhook) covers this for whoever writes the endpoint.


## Redeliver

**Redeliver**, on an expanded message, invokes your intake function again for that message. Any delivery claim is cleared first, so the message is **genuinely delivered again** — your endpoint sees it a second time, and its own deduplication on message id and domain is what should recognise that. It needs the manage permission.

Two things to know:

- **A redelivered message carries no verdicts.** SES's scan results live only in the original notification. The payload states each verdict as unknown, and the log row shows none.
- **The result appears as a new history entry** a moment later. The button's own reply says only whether the function ran: a raw message no longer in your bucket means nothing was replayed.

### What needs SendOps

Two recoveries are not on the page, and support performs them on request:

- **Redriving the dead-letter queue** — delivering every message parked with **endpoint error** in one go, once your endpoint is healthy.
- **Replaying a window of time** — every message stored between two timestamps, for instance after a webhook was misconfigured for an afternoon.

Neither reads your mail: both invoke your own intake function, exactly as Redeliver does. Neither can recover a message that never reached SES, one older than 400 days, or one to an endpoint that is still failing.

## Retention

| What | Where | Kept for |
|---|---|---|
| The log rows | SendOps | 400 days from when the outcome was recorded |
| Raw messages (`raw/`) | Your bucket | 400 days; moved to Glacier Instant Retrieval after 30 |
| Parsed parts served to your endpoint (`parts/`) | Your bucket | 30 days |
| Delivery claims (`claims/`) | Your bucket | 400 days |

The lifecycle rules on the bucket are set by the stack. Shortening them is yours to do in AWS; a message whose raw copy has expired can no longer be redelivered.

## Related pages

- [Delivery Webhooks](/inbound/delivery-webhooks) — allow lists and postures, which decide most outcomes
- [Reply Intelligence](/inbound/reply-intelligence) — the banner on a matched reply
- [Webhook payload and signature](https://developers.sendops.dev/api-reference/inbound-webhook) — what to answer, and why