Multi-agent systems fail in ways that are hard to debug. Unlike a single-agent failure where the cause is usually obvious, multi-agent failures are often silent and intermittent. One of the most common sources of silent failure is shared email infrastructure. When two agents share an inbox, they will eventually pick up each other's OTPs. The failure rate is probabilistic, depends on timing, and leaves no obvious error trace.

The Race Condition

Imagine an orchestrator that spawns ten agents in parallel. Each agent signs up for the same service with a different username. All ten use the same shared inbox address. The service sends ten OTPs within seconds of each other.

Now each agent is polling the inbox looking for its OTP. They filter by recency, keeping only OTPs that arrived after the agent started. But all ten agents started at roughly the same time. All ten OTPs arrived within the same window. Agent 1 grabs the first OTP it sees, which might be Agent 7's code. Agent 7's verification fails. Agent 1's verification also fails because it used the wrong code. Eight agents succeed. Two fail. The failure rate is 20%, the cause is completely non-obvious, and it is irreproducible on demand.

Time-windowed filtering, sender-based filtering, and subject-line filtering all have edge cases that produce the same class of failure. The only correct fix is inbox isolation.

Inbox Per Task: The Pattern

Each agent task that involves email must have its own inbox, never shared or pooled, created at task start and deleted at task completion. OTP routing is then correct by construction, because each inbox receives exactly the emails destined for that agent's session.

import Lumbox from "lumbox";

const client = new Lumbox({ apiKey: process.env.AGENTMAILR_API_KEY });

async function runAgentTask(taskId: string) {
  // Each task gets its own inbox
  const inbox = await client.inboxes.create({ username: `task-${taskId}` });

  try {
    // Pass inbox address to the agent's browser context
    const result = await runSignupFlow(inbox.address);

    // OTP is guaranteed to be for THIS agent's session
    const { otp } = await client.messages.waitForOTP({
      inboxId: inbox.id,
      timeout: 30_000,
    });

    await completeVerification(otp);
    return result;
  } finally {
    // Always clean up, even on failure
    await client.inboxes.delete(inbox.id);
  }
}

// 10 agents in parallel, each with its own isolated inbox
const results = await Promise.all(
  Array.from({ length: 10 }, (_, i) => runAgentTask(`agent-${i}`))
);

// Zero OTP collisions. Guaranteed.

Inbox Lifecycle Rules

Following these rules eliminates the entire class of email-related multi-agent failures:

  • Create at task start: provision the inbox before any email-related action in the task
  • Scoped to that task: an inbox ID passed to another task or agent puts two readers on the same inbox
  • Delete on completion: clean up in a finally block so deletion happens even on failure
  • One task per inbox ID: when two concurrent tasks reference the same inbox, each can pick up the other's OTP
  • One inbox per verification flow: a task that signs up for multiple services creates a separate inbox for each service

Following these rules consistently removes the intermittent, hard-to-debug OTP routing failures from a multi-agent system.

Start Free

Lumbox makes inbox isolation trivial. Create unlimited isolated inboxes via API. Free to start, no credit card required.