Skip to main content

Worked email lifecycle samples

Copy a request as written, substitute your own ids, and compare the response envelope. Errors follow Devotel Orbit’s { error, meta } envelope and carry a request_id in meta you quote when reporting. The sender chain: register a sender → publish the domain’s DNS records → run a test-send → keep suppressions clean.

1. Register a sender

POST /api/v1/email/senders
Request
The domain is registered with the sending provider, which issues real SPF/DKIM records — publish them with your DNS provider, then verify with the DNS-status read below before the sender can send. Omit default_from_email to send as noreply@<domain>.

2. Update the sender’s defaults

PUT /api/v1/email/senders/{senderId}
Request
PUT replaces the From/Reply-To defaults — pass every field you want to keep. Promoting back to default uses the dedicated endpoint below (flipping isDefault: false here is a no-op).

3. Promote a sender to the org default

POST /api/v1/email/senders/{senderId}/set-default
The compose dropdown fills with this sender first; the previous default is demoted. Deleting a sender (DELETE /api/v1/email/senders/{senderId}) removes it from the dropdown and accepts no body.

4. Check the domain’s DNS records

GET /api/v1/email/domains/{domainId}/dns-status
Request
Each record renders a traffic light (valid / warning / invalid / unknown); overallStatus is the worst of them. Compare recordExpected against recordActual to see what your DNS provider is missing. Pass ?refresh=true to re-verify at the provider, not just at DNS. GET /dns-history?days=30 returns the same id with an entries array of dated record snapshots so you can trace propagation.

5. Run a test-send and poll the result

POST /api/v1/email/domains/{domainId}/test-send
Poll GET /api/v1/email/domains/{domainId}/test-send/{testId}/result with the returned testId:
Until the proof lands the result endpoint returns 404 (retry — it usually settles within a minute). estimated: true means the spamScore is a provisional estimate from the domain’s DNS grid, not the measured receiver verdict. GET /inbox-placement?days=30 aggregates delivered proofs into an inbox/spam/promotions breakdown with an inboxRate percentage.

6. Validate recipient addresses

POST /api/v1/email/validate
Request
Check addresses before a campaign or import. suggestion carries the corrected domain on mistyped common domains (e.g. gamil.com → gmail.com). For batch checks, POST /api/v1/email/validate/bulk: Request
Each address reports deliverable, mailbox_full / undeliverable, mailbox_disabled, spamtrap, potential, invalid_mx, no_mx, or syntax_failure. The bulk form returns a results map plus the invalidAddresses list so you don’t have to cross-check every entry.

7. Manage the suppression list

POST /api/v1/email/suppressions
Request
Suppressed addresses never receive sends — the send path rejects them before they reach the provider. Manual reason accepts manual, unsubscribe, complaint, or hard_bounce; bounce/automatic entries (collector handles them) carry the machine reasons. Repeat an add and it returns 200 with the existing entry rather than 201. Bulk-import (POST /api/v1/email/suppressions/bulk-import) accepts either CSV text (one address per line, optional email header row tolerated) or an emails array: Request
imported counts newly-added entries; skipped counts duplicates already on the list; invalid counts malformed addresses dropped. GET /api/v1/email/suppressions pages the list (?limit=&offset=&search=&reason=):
Remove an entry with DELETE /api/v1/email/suppressions/{id} (returns { "ok": true }). GET /api/v1/email/suppressions/reputation?days=30 reports a suppression-rate breakdown by reason over trailing send volume — the number a deliverability review quotes.

8. Poll readiness and DNS, then promote to default

Once the DNS records publish (step 4), poll until the records show valid and then promote the sender to the org default. The Node.js escape hatch — the SDK is generated from this same OpenAPI contract, so a typed client covers it; raw fetch is fine too:
refresh=true re-verifies at the provider, not just at DNS — pass it when you just published the records. The promote call accepts no body; steps 3–5 above show the shapes.

Warmup, dedicated IP, TLS reports, and inbound routing (advanced)

These complete the sender’s onboard checklist; most tenants never need them. POST /api/v1/email/inbound-routes registers an inbound subdomain→destination mapping (webhook): Request
GET /api/v1/email/warmup-plan returns the day-by-day ramp for your ?targetDailyVolume=:
GET /api/v1/email/warmup-status adds what you have actually sent (sent.totalSent, the live-day current.maxAllowed, and reputation). GET /api/v1/email/warmup-enforcement answers “which batches get sent when the pattern doesn’t match a plan day” for a requested batch.

Dedicated sending — eligibility, request, status

Check eligibility (GET /api/v1/email/dedicated-sending/eligibility) against your actual trailing-30-day volume, submit a free-text request, then read back the server-authoritative status (GET /api/v1/email/dedicated-sending):
Eligibility read (eligibility is also nested inside GET /dedicated-sending):
Status read after submitting POST /dedicated-sending/request with a justification note:
eligibility.monthlySendVolume comes from real send history, not a client estimate — the request is rejected 403 below the ~50k/month bar, and re-submitting a pending request returns the existing record.

TLS-report and Postmaster reputation reads

Two stateless analysis routes fold the aggregate reports mailbox providers mail (TLS-RPT) and the per-delivery reputation Google / feedback loops expose (Postmaster) into one tenant-side readout — no persistence, no quota to the provider. TLS-RPT — POST /api/v1/email/tls-rpt/reports/analyze (base64-encode the report body you receive, or publish the _smtp._tls.<domain> record providers attach as application/tlsrpt+gzip):
Postmaster — POST /api/v1/email/postmaster/reputation/analyze (POST the payloads a tenant’s scheduled connector fetches from Google Postmaster Tools and your configured feedback loops — we deliberately do not pull from Google directly, so the route stays read-through):
Malformed records are skipped and counted in skipped, never thrown — a corrupt attachment or a single bad snapshot never sinks the batch.

See also