{"schema_version":"1.0","publisher":"Primitive SDKs","canonical_url":"https://test.abhinandan.one/functions-and-routing-concepts","markdown_url":"https://test.abhinandan.one/functions-and-routing-concepts.md","article":{"id":"a0ae7ada-c1bc-4010-8d01-da5c5415c77c","article_slug":"functions-and-routing-concepts","parent_article_slug":null,"parent_article_title":null,"kind":"concept","published_at":"2026-08-11T18:54:58.066005+00:00","keywords":["Primitive Functions","recipient routing","primitive functions deploy","primitive routes add","RoutingDecision","route-target endpoint"],"meta_description":"Primitive Functions run JavaScript handlers on inbound mail, and recipient routing rules bind an address pattern to the function or endpoint that handles it.","og_image_url":null,"source_file_paths":["cli-node/src/oclif/commands/functions-deploy.ts"],"recording_id":null,"replayable":false,"task_name":"Primitive Functions and Recipient Routing","category":"Product Surfaces","summary":null,"description":"Primitive Functions are serverless email handlers deployable from the CLI, and recipient routing decides which endpoint or function processes each inbound address, the two platform primitives every SDK and the CLI build on.","content_kind":"repo_page","content_markdown":"## What a Primitive Function is\n\nA Primitive Function is a single ESM module, deployed to Primitive's edge runtime, whose default export is an object with an async `fetch(request, env)` method, the same shape as a Cloudflare Workers-style handler. Primitive invokes it on inbound mail: it signs the delivery, forwards the `Primitive-Signature` header to the handler, and expects the handler to verify the raw request body against `PRIMITIVE_WEBHOOK_SECRET` before trusting the parsed payload. There is no infrastructure to provision; secrets you configure land in `env` as encrypted bindings, refreshed on every redeploy.\n\nThe payload's `event` field is `email.received` for ordinary inbound mail, or a machine-mail type (`email.bounced`, `email.tls_report`, `email.dmarc_report`, `email.dmarc_failure`) for bounces and reports; the payload shape is otherwise identical. For the normalized email object and the full webhook event catalog, see [Inbound and Outbound Email Model](email-model) and [Webhook Events Overview](webhook-events).\n\n## What recipient routing decides\n\nRecipient routing is a rule set that binds a recipient address (exact match or wildcard) to exactly one destination: either an existing webhook endpoint, or a Primitive Function. The webhook payload carries a `RoutingDecision` field describing how the inbound email was routed.\n\nBinding an address to a function mints that function's route-target endpoint in the same call, so you don't create the endpoint yourself first. Recipient routing is gated by an organization entitlement; rules are inert until that entitlement is enabled for your org.\n\n```mermaid\nflowchart LR\n    A[Inbound email] --> B{Recipient routing rule matches?}\n    B -- \"exact or wildcard match\" --> C[Bound destination]\n    C --> D[Function route-target endpoint]\n    C --> E[Existing webhook endpoint]\n    B -- \"no match\" --> F[Default / catch-all endpoint]\n```\n\n## Deploying a Function from the CLI\n\nThe CLI's `primitive functions` command group scaffolds, builds, and ships Functions; see [Primitive Functions: Deploy, Route, and Manage](cli-functions) for the full deploy workflow, secret-source flags, and `--wait` behavior.\n\n### Deployed doesn't mean reachable\n\nA successful deploy means the Function's code is live, not that inbound mail reaches it. Mail only flows to a Function once a route points at it. After every deploy the CLI checks routing status and prints one of:\n\n```text\nRoute bound. Function will receive inbound mail.\n```\n\nor\n\n```text\nDeployed but no route is bound. Inbound mail will not reach this function until\nyou bind one: primitive functions route-set --id <function-id> --domain <domain-id>  (or --fallback)\n```\n\nThat is the common first-deploy trap: testing an inbound flow against a Function with no route bound yet, and getting silence instead of an error.\n\n## Binding recipient routing rules\n\nBind an address to a destination with the CLI's `primitive routes` command group, which also lists, tests, reprioritizes, and removes rules:\n\n```bash\nprimitive routes add alice@example.com --function <function-id>\nprimitive routes add 'support+*@example.com' --match wildcard --endpoint <endpoint-id>\nprimitive routes list\nprimitive routes test alice@example.com\nprimitive routes update <route-id> --priority 5\nprimitive routes reorder --set <route-id>=10 --set <other-id>=20\nprimitive routes remove <route-id>\n```\n\n| Flag | Destination | Effect |\n|---|---|---|\n| `--function <function-id>` | A Primitive Function | Mints the function's route-target endpoint and binds the address to it in one call |\n| `--endpoint <endpoint-id>` | An existing webhook endpoint | Binds the address to that endpoint directly |\n\n`--match wildcard` accepts a pattern like `support+*@example.com` for plus-addressing or catch-all-style matches; the default match mode is exact. `primitive routes test <address>` previews where an address resolves and prints the rule trace, so you can confirm a routing change without waiting for real inbound mail. `primitive routes reorder` sets explicit priorities across multiple rules in one call when several patterns could match the same address.\n\n<Note>\n\nRecipient routing rules do nothing until your org's routing entitlement is enabled. If `routes add` succeeds but mail still lands on the default endpoint, confirm the entitlement is on before debugging the rule itself.\n\n</Note>\n\n## Next steps\n\n<CardGroup cols={2}>\n\n<Card title=\"Primitive Functions: Deploy, Route, and Manage\" href=\"cli-functions\">\n\nFull flag reference for functions-* commands: templates, redeploy, test runs, secrets, and logs.\n\n</Card>\n\n<Card title=\"Managing Domains and Recipient Routes\" href=\"cli-domains-and-routes\">\n\nThe full primitive routes command group plus inbound domain DNS configuration.\n\n</Card>\n\n<Card title=\"Webhook Events Overview\" href=\"webhook-events\">\n\nThe shared webhook contract every Function payload follows: signature verification and event catalog.\n\n</Card>\n\n<Card title=\"Inbox Setup and Status\" href=\"cli-inbox\">\n\nCheck whether an inbox is actively processed or stored-only, and diagnose missing routes.\n\n</Card>\n\n</CardGroup>","canonical_base_url":"https://test.abhinandan.one","seo_indexing_enabled":true,"last_modified":"2026-08-21T18:22:43.359885+00:00","video_url":null,"voiceover_url":null,"tools_used":[],"demonstrated_by":[],"steps":[],"related_links":[],"intro":null,"prerequisites":[],"verification":[],"troubleshooting":[],"suggest_edit_url":"https://github.com/abhi-browzer/primitive-sdks/edit/main/cli-node/src/oclif/commands/functions-deploy.ts","raise_issue_url":"https://github.com/abhi-browzer/primitive-sdks/issues/new?title=Docs+feedback%3A+Primitive+Functions+and+Recipient+Routing&body=Page%3A+https%3A%2F%2Ftest.abhinandan.one%2Ffunctions-and-routing-concepts","page_feedback_enabled":true,"verified_ref":null,"verified_at":"2026-08-11T18:38:45.205849+00:00"}}