# Inboxes are the wrong primitive for platforms

Inbox-centric email APIs suit one agent with one owner. Platforms serving customers need addresses that work without being created and a bill per email.

[Pau Kraft](https://paukraft.com)

Founder, AI Inbx · [@paukraft on X](https://x.com/paukraft)

5 November 2026 · 11 min read Updated 6 November 2026

TL;DR

I think the inbox model fits one agent with one owner, and gets in the way of a product that gives its own customers email.

-   **For a platform**, an address should work as a filter on mail that is already arriving, and the bill should follow the mail. An inbox entity makes it keep a second copy of its tenant model and register every address before it can receive. More
-   **AI Inbx is built that way.** Every address on a verified domain sends and receives with nothing to create, and the price follows email volume. More
-   **For one personal agent**, an inbox scope is the right tool, and AI Inbx has one. More
-   **For up to three agents**, the free plans of inbox-first APIs cost less than AI Inbx. More

*I'm Pau, and I founded AI Inbx, so I'm not neutral. Before AI Inbx I built email agents that run in production for enterprises in the sourcing industry, thousands of emails a month, and this post comes from that work. The other providers' prices quoted here are from their public pricing pages as of November 2026, linked where they're used. If something is wrong or out of date, email me and I'll fix it.*

Some email APIs make the inbox the central entity. You create an inbox to get an address, mail is stored and read per inbox, and plans are priced partly by how many inboxes you hold.

## Where is the inbox the right model?

The inbox fits one agent, one owner and no backend in between. Picture a personal agent, such as Claude Code on a developer's laptop, connected straight to an email provider so it can write to a vendor's support team and read the answer a day later. In my view this is the case AgentMail is built around: it is the [official email plugin for OpenClaw](https://www.agentmail.to/build/openclaw), a personal agent.

The inbox does two useful things there. It gives the agent an address with no domain setup, and its credential limits the agent to its own mail. With no app between the agent and the provider, nobody else can enforce that limit, so the provider has to.

The trouble starts when the inbox stops being an option and becomes the object everything else hangs off.

## Why does the inbox get in the way of a platform?

A platform already has a backend that decides who sees what, and an inbox makes it keep a second copy of that decision at the provider. Two products I see often:

-   A **support desk** that gives every ticket its own reply address, `reply+t123@acme.com`, so the customer's answer lands on the right ticket whatever their mail client does with the headers.
-   An **agent platform** where each customer's agents get addresses on that customer's subdomain: `sales@acme.agents.app`, `billing@acme.agents.app`, and next week ten more.

In both, the platform's servers hold one email API credential, and the platform's own auth decides which customer and which agent may read which mail. It works like an app connecting to a database with one credential and filtering rows per user, rather than a database login per user.

Put an inbox entity under that and it adds three things.

### A second copy of the tenant model

The platform already knows which address belongs to which customer or agent. That mapping is a table in its own database. With inboxes, the same mapping has to exist again at the provider.

Every new agent becomes a create call and every removed agent a delete call, and the two copies have to agree. When a create times out or a delete is retried, the platform now runs a sync job between its tenant table and someone else's.

AgentMail and OpenMail add a pod per customer above the inbox ([AgentMail](https://docs.agentmail.to/documentation/core-concepts/pods), [OpenMail](https://docs.openmail.sh/concepts/pods)), and Nuntly a [namespace](https://nuntly.com/docs/guides/receiving-namespaces). That separates customers at the provider, which a platform does need, but each agent still needs its inbox inside the pod. The copy gains a level: pods that mirror the platform's customers and inboxes that mirror its agents. A record per customer changes when a customer signs up or leaves. A record per address changes every time an agent, a ticket or a conversation starts, and that is the copy that costs.

### Pre-registration before receiving

At AgentMail and OpenMail, an address with no inbox receives nothing. AgentMail [states it doesn't offer catch-all](https://www.agentmail.to/blog/catch-all-vs-inbox-per-agent), and at OpenMail such mail ["is dropped after SMTP, so the sender gets no bounce"](https://docs.openmail.sh/api-reference/policy/list-correspondent-policy-audit-events). The support desk makes an address per ticket, on the fly, often thousands a day. Each one then needs an API call before the ticket's first email goes out, and another when the ticket closes, or the address keeps counting against the plan. OpenMail's [rate limits](https://docs.openmail.sh/concepts/rate-limits) also cap inbox creation at 100 a day per account, so a desk opening thousands of tickets a day can't give each one an address there.

[Nuntly](https://nuntly.com/docs/guides/receiving-inboxes) and [MailSlurp](https://www.mailslurp.com/docs/custom-domains/) add one catch-all inbox per domain, which takes the mail for every address without an inbox of its own. That solves the receiving, and it also shows where the routing really lives. The catch-all is one bucket for the whole domain, and the platform still reads the ticket off the recipient address. That is an address filter, with an inbox around it.

On a verified domain the address could simply be accepted. The domain is the platform's, and the local part is its routing data.

### Nothing an address filter doesn't already give

Reading an agent's mail through its inbox returns the same conversations as asking for the threads on that agent's address. In AI Inbx that is `threads.list({ mailbox: "sales@acme.agents.app" })`. Per-customer scope already lives in the platform's auth, so the inbox adds no access control the platform can use.

## Shouldn't customers get a key of their own?

Some inbox-first APIs issue keys scoped to one inbox or to one customer's pod, so a platform can hand each customer a provider credential that reaches only their mail. AgentMail's [multi-tenancy guide](https://docs.agentmail.to/multi-tenancy) says to "create a `Pod` per customer, give them a scoped API key", while its [Terms of Service](https://www.agentmail.to/legal/terms-of-service) (§8(l), updated 12 October 2026) forbid making "your API keys or account credentials" available to any third party. Ask AgentMail which of the two applies before you hand a key to a customer.

Either way, I think that draws the line in the wrong place. A platform's customers should call the platform's API, and the email provider is a subprocessor behind it, like the database or the payment processor.

Giving customers a key to the provider has three costs:

-   **The auth boundary moves into the vendor's system.** What a customer may read is then decided by the provider's scope model, and the platform's own rules no longer sit in front of every request.
-   **Customers get coupled to the vendor.** Their code calls the provider's endpoints with the provider's ids, so switching email provider breaks every customer's integration.
-   **Customers meet a subprocessor they never agreed to deal with.** Its terms, its changes and its outages reach them directly, when they signed up with the platform.

A scoped credential is right only where there is no backend in between, which is the personal agent above. That is the one place AI Inbx scopes a credential, to the addresses you pick. For a platform, an AI Inbx API key acts for the whole workspace, and your customers call your API.

## What should an email API charge for?

An email API should charge for what costs it money: emails sent and received, storage, and keeping domains and connected mailboxes in working order. From running one, I can say an extra address costs close to nothing.

When plans scale inbox caps with volume and sell extra inboxes as add-ons, I read inbox count as a tiering device. For a platform with many low-volume agents, that cap limits how many customers it can serve, not how much mail it sends, and a per-inbox fee charges an idle agent the same as a busy one.

I don't pitch AI Inbx as the cheapest option, and for up to three agents it isn't. I think our pricing is fair: it follows those costs, and at those prices AI Inbx runs as a healthy business. In my view, a monthly fee per inbox is margin, not cost.

Abuse is the fair objection. A provider that hands out addresses on its own domain has to limit what those addresses can do, but that is a limit on the shared domain and doesn't need the inbox to be the core entity. AI Inbx caps what the provided `<slug>.aiinbx.app` domain can send (100 emails a day, 20 an hour, 10 a day to any one recipient), and mail from a domain of your own isn't held to those ceilings.

Here is one platform worked through: 2,000 agents, one address each, each sending 3 emails a week (about 26,000 a month), with a third of them answered (about 8,700 replies). That is about 34,700 emails a month.

-   **Inbox metered at $2 a month per extra inbox.** [AgentMail](https://www.agentmail.to/pricing) Startup is $200 a month with 150 inboxes, and Developer and Startup sell extra inboxes at $2 a month each. 1,850 extra inboxes are $3,700, so $3,900 a month.
-   **Inbox metered at €1 a month per extra inbox.** [OpenMail](https://openmail.sh/pricing) Pro is €9 a month with 10 inboxes, then €1 per inbox. 1,990 extra inboxes make €1,999 a month, plus €16 to €25 for the emails above the 10,000 included (depending on whether received mail counts, which the pricing page doesn't say) and storage. OpenMail also caps new recipients per account at 150 to 500 a day, so if most of this platform's roughly 870 sends a day go to people its agents haven't written to before, they don't fit under that cap.
-   **Volume only.** AI Inbx Growth is $29 a month with 30,000 emails, sent and received both counted. The 4,700 over that cost $4.70 at $1 per 1,000 with extra usage turned on, so $33.70 a month. Without extra usage, Scale is $99 a month with 100,000 emails.

AgentMail and OpenMail also sell Enterprise plans priced on request. For up to three agents, both cost less than AI Inbx: their free plans include 3 inboxes, while AI Inbx has no free plan and starts at $5 a month.

That $5 Developer plan includes 5,000 emails, up to 50 custom domains and up to 100 connected Gmail or Outlook mailboxes. From Growth up, domains and mailboxes are unlimited, and subdomains under a wildcard don't count as custom domains on any plan. Addresses on your domains are never counted. The full list is on the [pricing page](/pricing).

## How does AI Inbx handle addresses?

Verify a domain once, and every address on it sends and receives with nothing to create. The same holds for the `<slug>.aiinbx.app` domain every workspace comes with.

For the support desk, the ticket's address is the routing:

```
import AIInbx from "aiinbx"

const aiinbx = new AIInbx() // reads AI_INBX_API_KEY

// Ticket 123: send from support@, collect the answer on the ticket's address.
await aiinbx.emails.send({
  from: "support@acme.com",
  to: "grace@example.com",
  reply_to: "reply+t123@acme.com",
  subject: "Your ticket #123",
  text: "We found the problem and fixed it. Reply here if it happens again.",
})
```

Grace's answer to `reply+t123@acme.com` arrives as an `email.received` webhook with the address in `data.to`, and the handler reads the ticket id off it. Nothing was registered for ticket 123, and nothing needs deleting when it closes.

Accepting every address means mail to made-up addresses arrives too. Each inbound email carries a `category`, `spam` among them, and the receiving side's `verdicts`. A webhook endpoint's [routing rules](https://docs.aiinbx.com/webhooks#routing) decide which recipient addresses reach it: put an `allow` rule on `to` matching `reply+*@acme.com` on the ticket endpoint, and mail to any other address never gets there. That mail is still stored, and it counts as received email on the bill.

For the agent platform, three pieces keep customers apart:

-   **A wildcard domain.** Verify `*.agents.app` once. Each customer's subdomain, such as `acme.agents.app`, is then one API call with no DNS of its own, and every address on it works from that moment.
-   **A space per customer.** A space holds the customer's domains and mailboxes, and with them every email and thread. Pacing rules and suppression lists can sit in it too, and sending reputation is kept per space, so AI Inbx never pauses one customer's mail for another's bounces. A platform can't do that separation on its own side, which is why there is a record per customer while the addresses inside it need nothing.
-   **Filters on reads.** Lists of emails, threads, domains and mailboxes take `space` to narrow them to one customer, and each webhook event carries `space_id`, so your handler knows which customer it is about.

The same filter covers a customer's own Gmail or Outlook mailbox, connected through your OAuth app: its mail lands in the same threads and events, and `threads.list({ mailbox })` reads it like any other address. AgentMail's docs describe no way to connect an existing mailbox.

```
const space = await aiinbx.spaces.create({
  name: "Acme",
  external_id: "cus_8812",
})

await aiinbx.domains.create({ name: "acme.agents.app", space_id: space.id })

// sales@, billing@ and any other address on acme.agents.app now send and receive.
for await (const thread of aiinbx.threads.list({
  mailbox: "sales@acme.agents.app",
})) {
  console.log(thread.subject)
}
```

`external_id` is the customer's id in your system. A second space with the same one is refused with `409 external_id_taken`, so a retried create can't make a duplicate, and `spaces.list({ external_id: "cus_8812" })` finds the first.

The [spaces guide](https://docs.aiinbx.com/guides/spaces) walks through this setup end to end, including customers who bring their own domain or connect Gmail. The [wildcard domains page](/features/wildcard-domains) covers the DNS side.

## When does AI Inbx use an inbox?

AI Inbx has an inbox only as an optional access scope, for an agent that holds its own credential: the personal agent from the start of this post.

Connect the inbox MCP server at `https://mcp.aiinbx.com/inbox`, or run `aiinbx login --inbox` in the CLI, and pick its addresses on the consent page. The agent can then send as those addresses and read the threads they are on. Every other operation answers `403 forbidden`, including domains, mailboxes, webhooks, keys and settings.

Each address can be any address the workspace already sends from: one on a verified domain, the provided `<slug>.aiinbx.app` domain, or a connected Gmail or Outlook mailbox. Each sends and receives with or without the scope, because the scope belongs to the agent's connection rather than to the address. The [agent inbox guide](https://docs.aiinbx.com/guides/agent-inbox) has the setup for Claude Code, Cursor and the CLI.

## Which model fits your product?

An inbox shouldn't be a requirement for receiving mail or the main thing you pay for.

|  | Single personal agent | Platform serving customers |
| --- | --- | --- |
| Who holds the credential | The agent | The platform's backend |
| Who decides what it may read | The provider, through the credential's scope | The platform's own auth |
| Scoped provider credential | Needed, one per agent | Not needed: customers call the platform's API |
| A new address takes | Picking it when the agent connects | Nothing |
| Per-customer separation | Not needed | Required: domains, rules, suppressions and reputation per customer |
| In AI Inbx | Inbox MCP server or `aiinbx login --inbox` | One API key, a space per customer, a wildcard domain |

If you're choosing between providers built on each model, I compared [AI Inbx head to head with an inbox-first API](/blog/ai-inbx-vs-agentmail), listed [alternatives for teams moving off one](/blog/agentmail-alternatives), and compared [email APIs for AI agents](/blog/best-email-api-for-ai-agents) more broadly. To try the address-as-filter model, start with the [quickstart](https://docs.aiinbx.com/quickstart).

*Last checked: 6 November 2026. Work at one of these companies and spotted something wrong? Email [pau@aiinbx.com](mailto:pau@aiinbx.com) with a link and I'll correct it.*

Written by

[Pau Kraft](https://paukraft.com)

[@paukraft on X](https://x.com/paukraft)

Before AI Inbx, Pau built email agents that run in production for enterprises in the sourcing industry, processing thousands of emails a month, where a single reply filed on the wrong conversation is not acceptable. AI Inbx is built on what those systems taught him: the threading edge cases, the replies cut in the wrong place, the email that went out at 02:30 on a Sunday.

Keep reading

## More from the blog

[All posts](/blog)

-   [5 November 2026ComparisonsAI Inbx vs AgentMail: inboxes vs addresses (2026)AgentMail bills per inbox; on AI Inbx every address works and the bill follows email. Threads, out-of-office dates, opt-outs, pacing and three worked bills.Pau Kraft](/blog/ai-inbx-vs-agentmail)
-   [5 November 2026ComparisonsThe best AgentMail alternatives (2026)Seven AgentMail alternatives for platforms, compared on per-inbox pricing, catch-all domains, users' Gmail and Outlook, opt-out replies and outreach rules.Pau Kraft](/blog/agentmail-alternatives)
-   [5 November 2026ComparisonsBest email APIs for AI agents (2026)Why I think AI Inbx is the best email API for products that give agents email, the bugs it saves you from, and when AgentMail, Nylas or Postmark fit better.Pau Kraft](/blog/best-email-api-for-ai-agents)

## Give your product an inbox. The hard parts are already handled.

[Get started](/signup)
