Skip to main content

Email channel lifecycle

The Email channel reference 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
  2. Plan deliverability before volume
  3. Build templates
  4. Send with a pattern that fits the traffic
  5. Handle the inbound side
  6. Read the error catalog
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.

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. 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.
  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.
  • 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. 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 searches one message across every channel. For per-contact reachability verdicts gating a campaign or flow, use the contact deliverability health score.

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.
  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. 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.
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.

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 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.

6. Error catalog walkthrough

The full table with remediations is in 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