Skip to content
Skip to main content

Round-robin email routing to a team

Last updated:

Shared inboxes like sales@ or support@ collapse the moment two people grab the same lead and a third gets ignored. Round-robin routing fixes that by handing each new message to the next person in a fixed rotation, so a 5-person team splits 100 inbound leads into roughly 20 each instead of a free-for-all. This recipe shows how to receive inbound mail through a webhook, pick the next assignee in code, and send an automatic acknowledgment, all on top of the Nylas Email API.

Nylas has no assignment endpoint, and that’s the key design point: the rotation lives entirely in your application. The API tells you when mail arrives and lets you reply or notify; your code owns who gets what. For the one-time webhook subscription and challenge handshake, follow the new email webhook recipe first, then come back here for the routing logic.

How does round-robin email assignment work?

Section titled “How does round-robin email assignment work?”

Round-robin assignment keeps a counter that advances by 1 with every new message. You hold a list of team members and compute index = counter % team.length, so a 4-person list cycles 0, 1, 2, 3, then wraps back to 0. The message goes to that person, and the counter increments for the next one.

The counter is application state, not something the Email API stores. A message.created webhook fires when mail lands in the shared mailbox, your handler reads the current counter, picks the assignee, and persists the new value. Keeping the rotation server-side means you control fairness completely: weight it, skip absent members, or reset it nightly. A typical handler runs this whole decision in under 50 ms before it acknowledges the webhook. The math is trivial; the discipline is making the state durable and concurrency-safe, which the later sections cover.

How do I receive inbound email for routing?

Section titled “How do I receive inbound email for routing?”

Inbound mail reaches your app through the message.created trigger. Nylas POSTs a JSON notification when a message arrives on the connected mailbox, with the message nested under data.object carrying its id and grant_id. Your handler has 10 seconds to return a 200 OK, so acknowledge first and do the routing afterward to avoid a timeout.

The payload only includes IDs and a partial body, so fetch the full message with GET /v3/grants/{grant_id}/messages/{message_id} when you need the sender or subject for assignment rules. Verify the X-Nylas-Signature header before you trust a payload, as covered in verify webhook signatures. The handler below acknowledges within the window, then reads the IDs it needs to route.

How do I pick the next assignee in rotation?

Section titled “How do I pick the next assignee in rotation?”

Picking the assignee is a single modulo operation against a counter you own. Read the counter, compute counter % team.length, select that member, then store counter + 1. With a 6-person team and 600 leads per month, each person lands close to 100, give or take the wrap point. The exact spread depends on when your billing window starts and stops.

Concurrency is the one trap worth naming. Webhooks deliver in parallel, so two notifications arriving 5 milliseconds apart can both read counter 7 and both assign the same person. Use an atomic increment instead: Redis INCR, a SQL UPDATE ... RETURNING, or a row lock returns a unique value to each caller. The snippet below uses an atomic increment so every message gets a distinct slot, then derives the assignee from the returned value.

How do I notify the assignee or auto-reply?

Section titled “How do I notify the assignee or auto-reply?”

Once you have an assignee, you can act in two ways: send an internal heads-up to the team member or send an acknowledgment back to the sender. Both use POST /v3/grants/{grant_id}/messages/send, the same endpoint covered in send email without SMTP. A short auto-reply that confirms receipt within 1 minute measurably lifts reply rates on cold inbound leads.

To reply on the original thread, fetch the inbound message first and pass its reply_to_message_id so the acknowledgment threads cleanly. The snippet below sends an internal notification to the chosen assignee with the lead’s address in the body. Swap the recipient and content to auto-reply to the sender instead.

How do I keep routing fair and avoid duplicates?

Section titled “How do I keep routing fair and avoid duplicates?”

Two delivery properties shape a correct router. Nylas guarantees at-least-once delivery, so the same message.created can arrive twice and would otherwise advance the counter twice and double-assign 1 message. Dedupe on the message id before you route: store processed IDs in a set with a 24-hour expiry and skip any repeat. This single check prevents the most common fairness bug in production routers.

Fairness also breaks when the rotation ignores reality. If someone is on leave, a blind modulo still feeds them about 25% of a 4-person queue while they’re out. Maintain an availability flag per member and filter the list before the modulo, or weight a senior rep at 0.5 so they receive half the volume. Reset or rebalance the counter on a schedule that matches your shifts. For retry timing, ordering, and signature verification, read Using webhooks with Nylas, since out-of-order notifications can otherwise skew your counts.