CLI tool
cloudflare/agentic-inbox avatar
cloudflare/agentic-inbox

Cloudflare Agentic Inbox: a self-hosted mail client where the agent lives in a Durable Object

A self-hosted email client with an AI agent, running entirely on Cloudflare Workers

7,633 stars975 forksTypeScriptApache-2.0

At a glance

What is it?
Agentic Inbox puts a React email client, per-mailbox SQLite Durable Objects, R2 attachments and a Workers AI agent behind one Cloudflare Access policy. It is a good fit for a single operator or a small trusted group on a Cloudflare-hosted domain, and a poor fit for anyone who needs per-mailbox authorization.
Who is it for?
Adopt it if you already run a domain on Cloudflare, you are comfortable enabling Cloudflare Access, and everyone who passes that one policy is allowed to read every mailbox. Do not adopt it if you need per-mailbox permissions or per-user isolation, or if you are unwilling to run a Cloudflare Workers deployment.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 145 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem it solves: mail for one domain, with an agent that can read it

Running mail for a domain normally means either paying a hosted provider or assembling a mail server. Agentic Inbox takes a third route. It receives mail through Cloudflare Email Routing, stores each mailbox in a Durable Object backed by SQLite, keeps attachments in R2, and serves a React client from a Hono Worker. The whole thing runs on the operator's own Cloudflare account.

The audience is narrow and specific. You need a Cloudflare account with a domain, and the README lists Email Routing, Email Service, Workers AI and Cloudflare Access as prerequisites. That is four Cloudflare products configured before the app is useful. Someone who wants a mail client they can point at an existing IMAP server is not the target here. The target is someone who already treats Cloudflare as their hosting layer and wants an inbox with an agent attached to it, without running a separate backend.

The agent is not a side feature bolted onto a settings page. The README describes a side panel with nine email tools for reading, searching, drafting and sending, plus auto-draft on new email. The auto-draft path reads inbound mail and generates a reply, and the README states it always requires explicit confirmation before sending. That confirmation step is the design decision that makes an auto-drafting agent tolerable in a real inbox.

Two Durable Objects per deployment, and what each one holds

The architecture diagram in the README shows a browser running a React SPA with an agent panel, talking to a Hono Worker that handles API and SSR, and the Worker fanning out to two Durable Object classes. MailboxDO holds SQLite plus R2 references. EmailAgentDO extends AIChatAgent from the Cloudflare Agents SDK and exposes the nine tools, calling Workers AI.

The split matters. Mail data and agent state are separate objects, so the agent does not sit between the client and the mailbox for ordinary reads. The client talks to the Worker, the Worker talks to MailboxDO. The agent panel connects over WebSocket, which the diagram labels explicitly, and that socket goes to the agent object. Chat history and streaming responses therefore live on the agent side, not in the mailbox database.

Per-mailbox isolation is the claim, and the README is precise about what it means: each mailbox runs in its own Durable Object with SQLite storage and R2 for attachments. That gives you a natural unit for storage and for the custom system prompt, which the README says is configurable per mailbox. It does not give you a unit of authorization, and the README says so directly. Any user who passes the shared Cloudflare Access policy can reach every mailbox. The isolation is structural, not a permission boundary.

The model in use is named in the stack section: `@cf/moonshotai/kimi-k2.5` through Workers AI, with AI SDK v6 underneath. The README does not state context limits, token costs or fallback behaviour if that model is unavailable in a region, so treat those as unverified until you check Workers AI documentation for your account.

Getting it running: deploy button, then the steps people skip

The README opens its setup section with a warning: clicking the Deploy to Cloudflare button is only one part of the setup, and the after-deploying steps are mandatory. That warning exists because the deploy flow provisions infrastructure but cannot configure your domain's routing or your Access policy.

For local work the commands are `npm install` followed by `npm run dev`. Two configuration items are named. Set your domain in `wrangler.jsonc`, and create the R2 bucket with `wrangler r2 bucket create agentic-inbox`. The bucket name is fixed in the instructions, so if you rename it you also need to change the binding. Deployment is `npm run deploy`.

The hosted path is longer. The deploy flow prompts for `DOMAINS`, the domain you want to receive mail for, and automatically provisions R2, Durable Objects and Workers AI. Then you enable one-click Cloudflare Access on the Worker under Settings, Domains and Routes. The modal that appears shows your `POLICY_AUD` and `TEAM_DOMAIN` values, and the README states you must set both as Worker secrets. `TEAM_DOMAIN` accepts either the Access team URL or the full `.../cdn-cgi/access/certs` URL.

After that: create a catch-all Email Routing rule that forwards to the Worker, enable the `send_email` binding so outbound mail works, and visit the app to create a mailbox for an address on your domain such as `hello@example.com`. Two error strings in the troubleshooting section tell you which step you missed. `Invalid or expired Access token` points at wrong `POLICY_AUD` or `TEAM_DOMAIN` secrets. `Cloudflare Access must be configured in production` is the app refusing to serve an unauthenticated inbox, and the README describes that enforcement as intentional.

The Access policy is the only authorization layer, and the MCP endpoint inherits it

This is the part to read twice. The README states that any user who passes the shared Cloudflare Access policy can access all mailboxes by design. It then extends that to the MCP server at `/mcp`: external AI tools such as Claude Code or Cursor connect over MCP and can operate on any mailbox by passing a `mailboxId` parameter. There is no per-mailbox authorization. The Access policy is described as the single trust boundary.

So the `mailboxId` parameter is a routing argument, not a capability check. An MCP client that has passed Access and knows or guesses a mailbox identifier can act on it. If that surprises you, the design is wrong for your situation, and no amount of configuration will fix it, because the README presents it as intended behaviour rather than a gap.

For a solo operator this is coherent. One person, one Access policy, several mailboxes for different addresses, and an agent that can search across them. For a team, the calculus changes the moment two people need different access. You would be relying on Access rules at the application level, and the README does not describe any mechanism for scoping a session to a subset of mailboxes.

There is a second consequence worth naming. Connecting an external agent over MCP hands that agent the same reach as the web UI, including the ability to send. The README's confirmation requirement is described for the auto-draft flow inside the app. It does not state that the MCP path enforces an equivalent confirmation gate, so do not assume it does.

What the feature list does not cover

The README lists a rich text composer, reply and forward threading, folder organization, search and attachments. It does not mention rules or filters, scheduled sending, contact management, signatures, or import from another mail provider. None of that is promised, so none of it is missing in a broken sense, but anyone migrating an existing mailbox should expect to move mail themselves or keep the old account alongside this one.

The stack is also version-pinned in ways that carry maintenance weight. React 19, React Router v7, Tailwind, Zustand, TipTap, `@cloudflare/kumo` on the front end; Hono, Durable Objects, R2 and Email Routing on the back; Cloudflare Agents SDK with `AIChatAgent`, AI SDK v6, and `react-markdown` with `remark-gfm` for rendering. That is a lot of surface, and the agent layer in particular is the part of the Cloudflare platform that has moved fastest.

There are no retrieved releases, which means there is no changelog to read for upgrade guidance. Updating means pulling the repository, checking whether `wrangler.jsonc` bindings changed, and redeploying with `npm run deploy`. Durable Object migrations are the risk to watch: if a future version changes the MailboxDO storage schema, the migration path will be in the code rather than in release notes, because there are no release notes to speak of.

Licensing is Apache-2.0, which permits commercial use and modification and includes a patent grant. It also means if you fork and run a modified version for other people, the licence terms travel with your distribution. That is a general property of the licence, not advice about your situation.

How it differs from a hosted provider's agent features and from a plain mail server

Two comparisons are worth drawing, because they lead to different decisions.

Against a hosted mail provider that has added AI features, the difference is where the data and the policy live. Here, mail lands in Email Routing on your domain, sits in a Durable Object in your account, and attachments sit in your R2 bucket. The agent runs on Workers AI against that same storage. You are not sending your inbox to a third party's assistant, but you are sending it to Cloudflare's inference service, which is a different trade rather than no trade. The provider route gives you a support contract and a migration path; this route gives you the source and the bindings.

Against running your own mail server, the difference is the amount of infrastructure you do not operate. There is no IMAP or SMTP daemon to patch, no spam pipeline to tune, no TLS certificate rotation. In exchange, you inherit Cloudflare's product boundaries. Receiving depends on Email Routing, sending depends on the `send_email` binding and Email Service, and access depends on Cloudflare Access. If any of those is unavailable to your account or your plan, the feature that depends on it stops working, and the README offers no fallback.

The agent design also differs from most assistant integrations. Auto-draft on new email is a push model: the agent reacts to inbound mail without being asked. That is only safe because sending requires explicit confirmation, per the README. An assistant that waits for you to open a thread has a smaller blast radius. This one trades that for drafts that are already written when you arrive.

Who should run this, and what to confirm before you do

Adopt it if you already run a domain on Cloudflare, you are willing to enable Cloudflare Access, and every person who passes that policy is allowed to read every mailbox. The setup is documented well enough to follow, the deploy flow does the provisioning, and the two error strings in the troubleshooting section cover the mistakes most people will make.

Do not adopt it if you need per-mailbox permissions, if you plan to connect an MCP client you do not fully trust, or if you want a mail system that does not depend on four Cloudflare products being enabled on your account. The absence of per-mailbox authorization is stated in the README, not hidden, and it is the constraint that decides most adoption questions.

Before you commit, verify these in your own account rather than from the README. Confirm the `send_email` binding is present on the deployed Worker, because outbound mail fails silently from the UI's perspective if it is not. Confirm the `POLICY_AUD` and `TEAM_DOMAIN` secrets match the values in the Access modal after you enable one-click Access, since the README attributes the token error to exactly that mismatch. Confirm your catch-all Email Routing rule forwards to this Worker and not to a mailbox, or inbound mail will never reach a Durable Object. And check whether `@cf/moonshotai/kimi-k2.5` is available through Workers AI in your account before you rely on auto-draft, because the README names the model but says nothing about availability or fallback.

Editorial conclusion

Adopt it if you already run a domain on Cloudflare, you are comfortable enabling Cloudflare Access, and everyone who passes that one policy is allowed to read every mailbox. Do not adopt it if you need per-mailbox permissions or per-user isolation, or if you are unwilling to run a Cloudflare Workers deployment. Before you commit, verify three things in your own account: that the send_email binding is present on the Worker, that POLICY_AUD and TEAM_DOMAIN match the values shown in the Access modal, and that the catch-all Email Routing rule points at this Worker rather than at a mailbox.

Official sources

  1. cloudflare/agentic-inbox on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
Community notes

Community notes