> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Email channel lifecycle: from domain verification to deliverability

> Walk the full email path end to end — verify your domain on day one, plan the warm-up, build templates, send with tracking, manage suppression, and read the error catalog.

# Email channel lifecycle

The [Email channel reference](/channels/email) documents every part of the
email surface. This guide puts those parts in the order you actually use
them: a day-one-to-at-scale plan from DNS verification through template
design, sending patterns, suppression management, and error handling.

**You will:**

1. [Set up and verify your domain](#1-domain-setup-on-day-one)
2. [Plan deliverability before volume](#2-a-deliverability-plan-before-volume)
3. [Build templates](#3-build-templates)
4. [Send with a pattern that fits the traffic](#4-sending-patterns)
5. [Handle the inbound side](#5-inbound-side)
6. [Read the error catalog](#6-error-catalog-walkthrough)

<Tip>Assign an owner for DNS access and one for the suppression list. The two gates that block degraded email — domain verification and opt-out handling — each need a named responder.</Tip>

## 1. Domain setup on day one

Everything downstream — warm-up, tracking, reputation — hangs off a verified
sending domain. Do this before your first send.

1. Add the DNS records (DKIM, SPF, DMARC, and the Return-Path CNAME) under
   **Channels → Email → Domains**, as listed in
   [Domain Setup](/channels/email#domain-setup). The DKIM public key is
   bit-length-validated (minimum 1,024 bits per RFC 8301), so a placeholder
   TXT value never flips to verified.
2. Run **Verify DNS** (`POST /api/v1/settings/channels/email/verify-dns`)
   once the records propagate, and confirm the per-record traffic-light view
   on `GET /api/v1/email/domains/:domainId/dns-status` is green.
3. Treat verification as a regression watch, not a one-shot check. A daily
   health check re-validates your DNS, and a drifted record (TTL expiry,
   host edit, key rotation) lands in the domain's `dns-history` with a bell
   notification. If sends start returning a provider-side 403, check the
   DNS status first, then re-verify. If you migrate DNS providers or rotate
   keys, follow [Troubleshooting: email DNS drift](/troubleshooting/email-dns-drift).
4. Register every subdomain you send from (for example `mail.example.com`)
   as its own sender under **Email → Senders**, with its own records. The
   sender list (`GET|POST /api/v1/email/senders`) drives the compose
   dropdown, and the id `default` resolves to the platform
   `orbit.devotel.io` domain.

## 2. A deliverability plan before volume

A new domain has no sender reputation, even though the platform will accept
marketing volume immediately. Ramp deliberately.

* **Warm-up posture** — if you plan dedicated-IP volume, the warm-up
  endpoints (`GET /api/v1/email/warmup-plan` and
  `GET /api/v1/email/warmup-status`) return a recommended daily cap
  schedule and today's headroom. The eligibility check on
  `GET /api/v1/email/dedicated-sending/eligibility` tells you when a
  dedicated IP is on the table. Follow the schedule; the numbers behind it
  are in [Warm-up posture](/channels/email#warm-up-posture).
* **Suppression lifecycle** — hard bounces, exhausted soft bounces,
  complaints, and unsubscribes are held out of future sends automatically,
  and the served quota slot is refunded at the pre-send gate. The
  trigger-to-behavior mapping for each reason is in
  [Bounce and Complaint Handling](/channels/email#bounce-and-complaint-handling).
  You manage the list yourself under **Email → Suppressions**: search it,
  export a CSV, add manual entries, or bulk-import a list from a previous
  ESP. Treat removal as a deliberate, auditable action — a re-bounce or a
  re-complaint re-suppresses.
* **Monitoring** — watch the aggregate sent / delivered / bounced /
  complaint rates on `GET /api/v1/email/suppressions/reputation` while you
  ramp. For per-email delivery diagnosis, the
  [Delivery log](/guides/delivery-log) searches one message across every
  channel. For per-contact reachability verdicts gating a campaign or flow,
  use the
  [contact deliverability health score](/guides/contact-deliverability-health).

## 3. Build templates

The flow is two steps: render blocks to HTML, then send that HTML. The send
endpoint takes a finished `html` (or `text`) body — it does not accept a
`template_id`.

1. Render with `POST /api/v1/messages/email-builder/render`. The response
   carries static HTML, an AMP-for-Email alternative (ignored by non-AMP
   inboxes), and a `templateId` you can correlate with a later save.
2. Resolve every `{{...}}` merge tag before send time; an unresolved tag
   lands on the wire as the literal string. URL-bearing fields normalize to
   `https://` and neutralize unsafe schemes; a single merge tag passes
   through. The rules are in
   [Personalization with merge tags](/channels/email#personalization-with-merge-tags).
3. Save reusable definitions with
   `POST /api/v1/messages/email-builder/save` and rehydrate them from
   `GET /api/v1/messages/email-builder/list` — the same picker the dashboard
   "Load template" control uses. Save caps at 60 per minute per tenant.

Start with two templates: one transactional wrapper (single column, minimal
footer) and one marketing wrapper (preheader text, one-click unsubscribe
footer). Sending is roughly 200 per minute per tenant within the channel
rate pool, so template size, not throughput, is usually your constraint.

## 4. Sending patterns

Match the send pattern to the traffic class:

* **Transactional** (receipts, password resets, notifications) — send
  directly with an inline `html`/`text` body on `POST /api/v1/messages/email`.
* **Marketing to large recipient sets** — use the bulk endpoint
  (`POST /messages/bulk`, up to 10,000 recipients per call) with per-row
  outcomes, rather than one request per recipient.
* **Attachments** — when a send carries files, follow the size caps, the
  MIME allowlist, and the URL-vs-inline rules in
  [Email attachments](/guides/email-attachments). A violation fails with
  `422 VALIDATION_ERROR` before anything reaches the provider.
* **Tracking** — open and click tracking are configured per sending domain,
  not per send; the deprecated per-send flags are ignored. Orbit mints its
  own open pixel and rewrites click links at its edge regardless of the
  provider's per-domain toggle, and machine-open classification (Apple MPP,
  Gmail Image Proxy, bot prefetch) separates genuine engagement. The
  mechanics are in [Engagement Tracking](/channels/email#engagement-tracking).

Delivery arrives on `message.delivered` / `message.failed` events with
`channel: "email"`; engagement fires `email.opened` (first-open deduped)
and `email.clicked` (every distinct click). Subscribe once and filter on
the channel, as described in [Webhook Events](/channels/email#webhook-events).

## 5. Inbound side

If customers reply to your emails (or write to your domain), set up inbound
parsing — MX records plus a match-rule route. The
[inbound email and SMS routing guide](/guides/inbound-email-parse) walks
the normalized payload, SMS match rules, auto-replies, and how bounces and
unsubscribes are honored on the inbound path. When inbound mail stops
arriving, work through
[Troubleshooting: inbound email](/guides/inbound-email-troubleshooting).

## 6. Error catalog walkthrough

The full table with remediations is in
[Error Catalog](/channels/email#error-catalog). These are the rejections
you will actually see, in the order they appear over a lifecycle:

* `CHANNEL_NOT_CONFIGURED` (503) — the email provider was never set up.
  Finish the domain work in section 1.
* `NO_SENDER_CONFIGURED` (422) — no verified sender owns the `from`
  address. Register and verify under Email → Senders.
* `VALIDATION_ERROR` (422) — the payload itself: malformed addresses, an
  empty body, a disallowed attachment MIME type, or oversize attachments.
  This surfaces during template onboarding and never reaches the provider.
* `RECIPIENT_OPTED_OUT` (422) — the recipient is suppressed. This is the
  suppression lifecycle doing its job; the quota slot is refunded. Route
  the flow to an alternate channel instead of un-suppressing by reflex.
* `RATE_LIMITED` (429) — you crossed the per-tenant channel pool (200/min
  by default). Back off and retry; a provider-side 429 also passes through
  end-to-end as backpressure, not an outage.
* `QUOTA_EXCEEDED` (429) — the daily budget cap under Settings → Billing.
  Raise the cap or wait for the next cycle.
* `MESSAGE_SEND_FAILED` (502) — a provider-side failure after validation.
  Transient provider errors are retried in-band and are wire-safe (the
  send carries an idempotency key that de-duplicates for \~24 h); persistent
  failures carry the provider detail on `details.provider_message`.
* Provider 403, surfaced as `403 VALIDATION_ERROR` — most often a sending
  domain whose verification regressed. Go back to section 1 and re-run
  Verify DNS.

## Next steps

* [Channels → Email reference](/channels/email) — the full channel surface.
* [Troubleshooting: email bounces and spam complaints](/troubleshooting/email-bounces-complaints) — hard vs soft bounces, complaints, and spam-trap classification.
* [Go-live checklist](/guides/go-live-checklist) — gates to clear before you move from sandbox to live traffic.
