Troubleshooting: inbound email never routes
Inbound email to your parse domain runs three surfaces in parallel — a webhook forward to your endpoint, an inbox conversation, and (optionally) an email Flow. When you see none of them, work this page top to bottom. It isolates DNS, route matching, normalization, and trigger issues one at a time, so the escalation you open carries exactly the inputs Support needs. The full setup walkthrough lives in inbound email and SMS routing. This page assumes that setup exists and something is misbehaving.1. The inbound parse pipeline, in order
Every inbound email passes through these stages, and each stage is a place the pipeline can stop:- DNS → MX records. The receiving domain’s MX records point at Orbit’s ingress hostname (shown in Email → Inbound routes → Add route). Until MX resolves, no mail arrives at all.
- Route match. The SMTP envelope recipient is matched against your
registered inbound routes — exact address, catch-all
(
*@domain), or local-part — then theToandCcheaders. No match, no parse. - Normalization. The message is parsed into the normalized payload
(
from,toAddress,matchedRecipient,subject,text,html,attachmentsmetadata,headersincludingmessage-id). - Fan-out. The normalized message is forwarded to your
destinationUrlas a signedPOSTand simultaneously opens (or threads onto) an inbox conversation. Signature verification and a 2xx response are required for the forward to count as delivered. - (Optional) Flow trigger. An email-channel Flow can react to the inbound event — compose a reply through email, or fan out to another channel. Inbound email routes themselves have no built-in reply path.
2. Symptom → where to look
3. Diagnostic checklist
Work each item in order — collect the output as you go; it becomes your escalation payload.- DNS.
dig MX inbound.your-domain.com(or your DNS provider’s record viewer) — confirm the MX record points at the ingress hostname the dashboard displayed when you created the route. - Route shape.
GET /email/inbound-routes— confirm a route exists and itsrecipientPatterncovers the exact address being written to, in whichever syntax (exact, catch-all, local-part) you registered. Checkactive: trueandfailureCount: 0. - Normalized payload. From an earlier working message (or the
guide’s example): does the payload
carry
textorhtml, and aheaders.message-id? A body-less message is valid but can break downstream matchers. Attachment bytes never appear here — only metadata — unless you setincludeRawMime: trueon the route. - Signature. Your endpoint must verify the
X-Orbit-Signatureheader (sha256=<hex>, HMAC over the raw body, keyed by the route’ssigningSecret) and return 2xx. Only 2xx counts; redirects are not followed. - Flow trigger. If you expected a Flow: open it, confirm it triggers on the inbound email event, and confirm the trigger is enabled and published. The flow executions page covers trigger-side failure in more depth.
Inspect inbound routes over the API
The route state checks below (recipientPattern coverage, active,
failureCount / lastFailureAt) all read the same listing endpoint.
List every registered inbound email route:
{ data, meta } envelope, with the routes
under data.routes:
active: true,
recipientPattern covering the failing address, and
failureCount: 0. A rising failureCount with a recent
lastFailureAt means the webhook endpoint is rejecting the forwards —
check its response codes and signature verification, not the route.
Signing secrets never appear in this listing; the plaintext secret is
returned only once, at route creation.
Every route the list call returns carries recipientPattern,
destinationUrl, active, failureCount, and lastFailureAt, so one
call is enough for the full check — there is no separate single-route
read you need here. To re-check between fix attempts, poll the same
list call before sending the next test message:
Escalate with these
Open a ticket when every item above is clean and inbound mail still never lands. Include all four:- The parse domain (for example
inbound.your-domain.com). - The route id from
GET /email/inbound-routes(theeinr_…id). - One sample
headers.message-idfrom a message that should have routed (the RFC 5322 Message-ID header). - Your tenant ID — in the dashboard under Settings → Organization,
and returned by the
GET /api/v1/meresponse asorganizationId.
See also
- Inbound email and SMS routing — full setup walkthrough, payload shape, match-rule reference
- Flows overview — auto-reply and richer orchestration
- Flow executions failed — trigger-side failures in depth
- Email operational notes — attachment and MIME handling on the outbound side
- Webhook events reference — event types, payload fields, endpoint scoping