# Proof that a message was sent

**Sent** means the provider acknowledged the message and that acknowledgement is stored against it. Where the acknowledgement never arrived — a timeout, a broken connection, an answer Connect cannot interpret — the state is *uncertain*, and it stays that way on screen. Guessing in either direction produces a worse outcome than admitting the doubt.

- **Status:** Available
- **Audience:** both
- **Channels:** email
- **In the app:** #/inbox, #/activity
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/email/send-evidence/

## The claim being made

"Sent" is not a description of intent. It is a statement to a colleague, to a customer and sometimes to a regulator that a specific message left at a specific time. A status that means "the API was called and presumably it worked" cannot carry that weight, and every system that pretends otherwise discovers it during the one week it matters.

So the rule in `outbound.py` is narrow and dull: no acknowledgement, no `sent`. The evidence is recorded with the outcome, so the answer to "prove it went" is a stored fact rather than a reconstruction.

## The state in the middle

| Situation | State | Safe to retry? |
|---|---|---|
| The provider answered with an acknowledgement | Sent | No — it already went |
| The provider refused, with a reason | Failed | Depends on the reason |
| No answer came back before the timeout | Uncertain | Not automatically |
| The connection dropped mid-request | Uncertain | Not automatically |
| An answer arrived and cannot be interpreted | Uncertain | Not automatically |

The right-hand column is the whole reason the middle state exists. A message whose fate is unknown has a real chance of having been delivered, and an automatic retry on that chance is how a customer receives the same reply twice — from a business that has just told them it is careful. Duplicate contact is not a cosmetic fault; on an outreach path it is a compliance one.

> **Note** The inverse mistake is quieter and worse. Marking an unconfirmed send as `sent` closes the item, empties the queue and leaves a customer waiting for a reply that a screen says they already had.

## Resolving one

1. Look at the mailbox's sent items at the provider.
   - Result: This is the authoritative answer and it usually takes seconds. The provider either has the message or does not.
2. If it is there, treat it as handed over and do not send again. Note it on the thread so the next person is not asking the same question.
   - Result: The record keeps the doubt visible, which is honest: what changed is your knowledge, not what happened.
3. If it is not there, send again — deliberately, as a person.
   - Result: The new send is a separate action with its own evidence, and the earlier attempt stays in the record rather than being overwritten.
4. If it keeps happening on one mailbox, treat it as a health signal.
   - Result: Repeated unconfirmed sends point at the connection rather than at any message — [Mailbox health](/docs/email/mailbox-health/) is the screen for that.

## What the evidence is not

- **Not a delivery confirmation.** The provider accepted it. The recipient's server may still reject it later, which arrives as a bounce.
- **Not a read receipt.** Connect proxies remote images on the way in and does not attach tracking on the way out; nothing tells you the message was opened.
- **Not proof of the content.** It proves this message, as stored, was handed over and accepted. The audit trail is what ties it to who released it.
- **Not a promise about the inbox.** Whether it lands in front of somebody depends on authentication and reputation, and no honest system promises that.

Holding those apart is what makes the status worth anything. A single green tick that quietly means five different things is a tick nobody can rely on.

## Questions

### How long before an unanswered send is called uncertain?

The timeout belongs to the send path in `outbound.py` rather than being a number this page can state without inventing one. What matters operationally is that the wait ends in a state you can see, rather than in an item that silently disappears.

### Can Connect retry automatically?

Not on the middle state, and that is deliberate — retrying a message that may have arrived is the one failure this design exists to prevent. Failures with a clear provider reason are a different matter, handled on [A send that failed](/docs/email/failed-send/).

### Where do I see the evidence for a message that did go?

With the message itself and in the activity record. The same trail answers which mailbox it left from and who released it, which is usually the second question somebody asks.

## Related

- [Sending email](https://connectbyjbrh.com/docs/email/sending/)
- [A send that failed](https://connectbyjbrh.com/docs/email/failed-send/)
- [Bounces](https://connectbyjbrh.com/docs/email/bounces/)
- [Mailbox health](https://connectbyjbrh.com/docs/email/mailbox-health/)
- [Why 'sent' must require provider evidence](https://connectbyjbrh.com/research/provider-evidence-for-sent/)

## What this page is based on

- CHANNELS.md §1 — sending and the third state
- `backend/app/outbound.py` — the send boundary and its evidence
- Connect capability registry (docs-source/facts.py) — `send_evidence`
