Skip to content

CONCEPT Cited by 1 source

Address-based agent routing

Definition

Address-based agent routing is the pattern of encoding the target agent's class and instance identity in the email address itself — so the address is the DO-ID / instance selector and the inbound dispatcher ("the address-based resolver") parses it directly with no configuration table or routing DB to look up.

Canonical shape, from Cloudflare's Agents-SDK 2026-04-16 launch:

  • Local-part → agent class / default instance. support@domainSupportAgent class, instance "support".
  • RFC-5233 plus-sub segment → specific instance within that class. support+ticket-123@domainSupportAgent class, instance "ticket-123".

"Each agent gets its own identity from a single domain. The address-based resolver routes support@… to a 'support' agent instance, sales@… to a 'sales' instance, and so on. You don't need to provision separate inboxes — the routing is built into the address. You can even use sub-addressing (support+ticket-123@…) to route to different agent namespaces and instances" (Source: sources/2026-04-16-cloudflare-email-service-public-beta-ready-for-agents).

Why it's the canonical email-tier shape

The Agents SDK already uses per-HTTP-request / per-WebSocket-session DO lookup via routeAgentRequest. Address-based routing is the email-tier realisation of one-to-one agent instance — the email address is the DO-ID selector, same shape applied to a different channel. A single domain hosts an arbitrary number of distinct agent classes and instances:

domain: your-agents.example

  support@your-agents.example             → SupportAgent / "support"
  support+ticket-123@your-agents.example  → SupportAgent / "ticket-123"
  support+ticket-456@your-agents.example  → SupportAgent / "ticket-456"
  sales@your-agents.example               → SalesAgent  / "sales"
  billing+inv-789@your-agents.example     → BillingAgent / "inv-789"

No mailbox provisioning, no tenant DB, no lookup service — the address string is the routing decision.

Agents-SDK API

import { routeAgentEmail } from "agents";
import { createAddressBasedEmailResolver } from "agents/email";

export default {
  async email(message, env) {
    await routeAgentEmail(message, env, {
      resolver: createAddressBasedEmailResolver("SupportAgent"),
    });
  },
} satisfies ExportedHandler<Env>;

createAddressBasedEmailResolver(defaultClassName) returns a resolver that parses the To: address (local-part + optional plus-sub) and yields a { className, instanceName } pair the platform uses to bind the inbound message to a specific DO instance.

Combined with signed reply routing

On outbound, the agent calls this.sendEmail({ …, inReplyTo: messageId }) where messageId carries an HMAC-SHA256-signed token so inbound replies to that thread route back to the exact same DO instance that sent the original — even if the plus-sub-addressing looks different. See patterns/signed-reply-routing-header.

Trade-offs

Pro:

  • Zero provisioning — one domain hosts infinite agent classes and instances.
  • Human-legiblesupport+refund-abc123@ is a self-documenting address.
  • Works on every email client — RFC-5233 plus-sub is standard + widely interoperable.
  • Natural one-to-one shape — mirrors HTTP / WS Agent-SDK routing.

Con:

  • Public discoverability — address-as-routing-key is user-visible; a leaked address reveals some internal structure (agent-class names at minimum).
  • Plus-sub mangling — not all senders preserve plus-sub when replying; some mail servers strip or rewrite. Reply routing must handle the case where the sub-segment is missing on inbound.
  • Without signed headers, spoof-forwardable — anyone can put anything after the +. For writes/state mutation, patterns/signed-reply-routing-header is load-bearing, not optional.

Seen in

Last updated · 200 distilled / 1,178 read