Skip to content
cd ..

Designing a REST API with 107 Endpoints for AI Agent Email

// · 5 min read

When you tell someone your API has 107 endpoints, you get a look. The “are you sure that’s not a code smell” look. But email is a deceptively large domain, and when you’re building an email platform for AI agents, every capability needs its own endpoint. Agents don’t read documentation or guess at polymorphic payloads. They need one URL per action, with a clear schema for what goes in and what comes back.

The @agenticmail/api package is the core server that powers everything. It’s an Express application, organized into 11 route modules, each owning a slice of the domain.

The factory pattern

The server boots through a createApp() factory function rather than a singleton export. This matters for testing. You can spin up multiple isolated instances with different configurations, run them in parallel, and tear them down without worrying about shared state. It also lets the CLI package create an app with one config while the test suite creates another.

createApp() wires up the middleware chain, mounts all 11 route modules, and returns the Express app without calling listen(). The caller decides when and where to bind. This separation means the same app can run behind a Unix socket in production, on a random port in tests, or inside a serverless wrapper.

The middleware chain

Every request passes through four global middleware layers before reaching a route handler.

CORS is configured per deployment, not hardcoded. In relay mode, the allowed origins differ from domain mode. The middleware reads from the running configuration and applies it.

Rate limiting is set to 10,000 requests per 60 second window. That sounds high, but agents are chatty. A single agent checking for new mail, processing messages, and sending responses can easily generate dozens of requests per minute. Multiply that by several agents and you need headroom. The limiter uses a sliding window and returns standard rate limit headers so clients can back off gracefully.

Bearer token authentication validates the token on every request. No session cookies, no JWTs with expiry windows to manage. Stateless auth that works the same whether the request comes from an MCP server, a CLI tool, or a direct HTTP call.

Error handling catches anything that slips through. Unhandled rejections, thrown errors, malformed responses. It normalizes everything into a consistent JSON error format with status codes that actually mean something.

The 11 route modules

Here’s where the 107 endpoints live:

Accounts (12 endpoints): Agent account CRUD, configuration, credential management. Each agent has its own account with its own mailbox, settings, and permissions.

Mail (22 endpoints): The core email operations. Send, receive, search, reply, forward, move, delete, manage folders, handle attachments. This is the largest module because email itself has so many operations.

Events (1 endpoint): A single SSE endpoint for real time push notifications. One endpoint, but it keeps persistent connections open and streams events as they happen.

Features (18 endpoints): Templates, scheduling, drafts, signatures, tags, rules, and filters. These are the convenience features that make agents effective at managing ongoing email workflows rather than just sending one off messages.

Gateway (11 endpoints): SMTP relay configuration, domain verification, connectivity testing, queue management. The gateway is the bridge between AgenticMail and the outside email world.

Tasks (7 endpoints): Inter agent task assignment, claiming, completion, and RPC. Agents can delegate work to other agents through the task system.

SMS (7 endpoints): Google Voice integration for reading text messages and extracting verification codes. A surprisingly useful capability when agents need to handle 2FA.

Storage (22 endpoints): A full database layer for agents. DDL, DML, indexes, import/export. Agents need persistent state, and this gives them a proper relational store.

Domains (4 endpoints): Custom domain management. DNS verification, MX record guidance, domain status.

Inbound (1 endpoint): The webhook receiver for incoming email from the SMTP gateway. One endpoint that handles all inbound mail processing.

Health (2 endpoints): Liveness and readiness checks. The liveness endpoint returns immediately. The readiness endpoint verifies database connectivity and IMAP access before reporting healthy.

Connection pooling

The API maintains a pool of IMAP connections with a 10 minute TTL. Opening an IMAP connection involves a TCP handshake, TLS negotiation, and authentication, which can take hundreds of milliseconds. Pooling eliminates that cost for subsequent requests.

The pool uses LRU eviction. When it hits capacity, the least recently used connection gets closed to make room. Connections older than 10 minutes get proactively closed before use, because IMAP servers will drop idle connections and you’d rather open a fresh one than discover a stale one mid request.

Each agent gets its own pool slot, keyed by account credentials. Agent A’s connection is never reused for Agent B, even if both connect to the same IMAP server.

Why Express in 2026

People ask why Express and not Hono, Fastify, or Elysia. Express is boring in the best way. The middleware ecosystem is massive, the debugging story is well understood, every hosting platform supports it natively, and the performance is more than adequate for an API that’s IO bound on IMAP and SMTP operations. The bottleneck is never the HTTP framework. It’s always the email server on the other end.

107 endpoints is a lot. But each one is focused, well typed, and does exactly one thing. When an AI agent needs to interact with email, it doesn’t have to reason about which parameters to combine. It picks the endpoint that matches its intent, calls it, and moves on. That clarity is worth the endpoint count.

Source Code

View the full source on GitHub

// share

// subscribe

New posts and updates straight to your inbox. No noise.

cd ..