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:
- Set up and verify your domain
- Plan deliverability before volume
- Build templates
- Send with a pattern that fits the traffic
- Handle the inbound side
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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