Skip to main content

Reading the email message status ladder

The Status column on the Channels → Email page is the one number operators read day to day: one word per message, telling you how far that message got. This guide explains the order of the ladder, when a message moves from one rung to the next, and which rungs you can actually make decisions on.

1. The ladder

Every email message moves up a four-rung ladder, and the column always shows the furthest rung the message has genuinely reached: The rule is furthest real engagement wins. A message that was opened and then clicked shows Clicked, never Opened; a clicked message that is opened again later still shows Clicked. The column only ever moves forward, and it moves once per rung. On the page you see one row per message: recipient, subject, send time, and the status column. A freshly sent message reads Sent for the seconds to minutes until the recipient server acknowledges it, then flips to Delivered. Messages that bounce or draw a spam complaint leave the ladder entirely and show their terminal status instead (see section 4).

2. What “Opened” really means

An open is recorded when the recipient’s mail client loads the 1×1 tracking pixel Orbit injects into the HTML body. Two things keep that signal honest:
  • First-open dedupe. Proxy services (Gmail’s image proxy, corporate prefetch gateways) often load the pixel several times within seconds of delivery. Orbit keeps the first event only, so opened_at and the Opened status reflect one open, not a proxy fan-out.
  • Machine-open classification. Apple Mail Privacy Protection pre-loads every pixel for every message; Gmail’s proxy and security scanners do the same. Each open is therefore classified, and machine opens are stamped with is_machine_open so you can separate them from human reads.
In practice this means a bare Opened count overstates real readership. When you want the human number, filter on it:
  • The by-channel analytics rollup (GET /api/v1/analytics/messages/by-channel) returns total_opened_genuine alongside total_opened — the genuine count excludes machine-classified opens.
  • The dashboard’s email analytics tiles roll the same genuine count up per campaign, so human open rates and inflated open rates never silently mix.
If total_opened_genuine is meaningfully lower than total_opened for a send, that gap is privacy tooling doing its job, not lost engagement.

3. Clicked semantics

Clicks are the strongest signal on the ladder and the least spoofable: a click means a person (or at least a person’s browser) followed a link to its destination. Tracked links are rewritten to an Orbit redirect endpoint at send time; the original URL rides inside the rewritten link as an HMAC-signed payload bound to your tenant and the message, so a click cannot be forged or re-pointed at a different destination. When the redirect is hit, Orbit verifies the signature, records the click (with link, userAgent, and the click’s own timestamp), and forwards the recipient to the original URL. If a link cannot safely be rewritten, it ships untracked rather than failing the send. Keep two granularities straight:
  • Events — email.clicked fans out on every distinct click. Three clicks from one recipient produce three events (distinct click identity, not three identical receipts of one click).
  • Status — the column upgrades to Clicked once, on the first verified click, and stays there. The ladder records the furthest rung reached, not a click count.

4. Terminal statuses

Two outcomes remove a message from the ladder instead of advancing it:
  • Bounced — the recipient server refused the message. The DSN code decides what happens next: 5.x.x hard bounces are terminal immediately; 4.x.x soft bounces are retried across the provider’s window and only become terminal when they persist past the exhaustion threshold.
  • Complaint — the recipient marked the message as spam. This arrives on the same delivery-receipt path as bounces and is terminal the moment it lands.
Both statuses write the address into your suppression list automatically, and a send to a suppressed address is refused before it reaches the provider (the quota slot is refunded). For decoding a specific 5.x.x vs 4.x.x vs complaint, work the diagnostic tree in Troubleshooting: email bounces and spam complaints.

5. Reading engagement honestly

Open tracking was designed in a world where a pixel load meant a human looked at the message. That world is gone: Apple Mail Privacy Protection pre-fetches every pixel, Gmail proxies images through its own servers, and security gateways prefetch links. Open rates across all providers are therefore inflated by design, and the inflation varies per recipient client, so open counts are not comparable across audiences either. Base decisions on the rungs that stay honest:
  • Delivered and bounced — server-side facts, dependable everywhere. Watch them through GET /api/v1/email/suppressions/reputation for aggregate bounce and complaint rates.
  • Clicked — requires a real follow-through, survives privacy tooling, and is bot-filtered before it ships.
This is the same posture the SMS channel takes: email’s bot-filtered Clicked metric is the number verified SMS click-through is designed to compare against, so cross-channel engagement comparisons line up. See Reading the SMS click-through parity panel for the parity semantics. Use opens as a soft, directional signal; do not size campaigns, segments, or send windows to them.

6. Events vs. the column

If you integrate against webhooks, expect your event counts and the status column to disagree, by design:
  • email.opened fires once per message (first-open deduped) — a cumulative event.
  • email.clicked fires on every distinct click — a recipient who clicks four links produces four events while the column shows a single Clicked.
  • Delivery outcomes arrive on the channel-agnostic message.delivered and message.failed events (each carrying channel: "email"), not on email-specific types.
The events are a running log of everything that happened to a message; the column is the current state derived from that log. An integration that counts email.clicked rows will therefore always see more rows than the column implies, and a message whose events read opened-then-clicked shows exactly one status: Clicked. When reconciling, fold events into the furthest-rung-wins rule from section 1 and the two views agree.