PHASE 0 · LOCAL

Agent-First
Email

A complete email infrastructure where AI agents are the primary interface. Stalwart JMAP backend, REST API, MCP server, and CLI — one docker compose up away.

MCP JMAP CLI REST API
Indigo Workspace
2
The Problem

AI agents can't send email

Every AI team hits the same wall. Email is locked behind OAuth flows, rate limits, and APIs designed for humans clicking buttons.

1

OAuth Maze

Gmail and Microsoft APIs require multi-step OAuth consent, refresh tokens, and per-user scoping. Agents need programmatic access — not browser redirects.

2

No Agent Primitives

Existing email APIs weren't built for agents. No tool schemas, no structured parameters, no thread-aware operations. Just raw REST mapped to human mailbox concepts.

3

Vendor Lock-in

Google Workspace and Microsoft 365 own the mailbox. You can't self-host, you can't inspect, and you can't run it locally for development.

3
Architecture

Three layers. One command.

Stalwart handles the mail engine. Hono wraps it in REST. MCP and CLI give agents and humans equal access.

Stalwart JMAP + SMTP + IMAP
Hono REST API Provisioning + Email Ops
MCP Server Claude tool interface
CLI · sendbox Human terminal interface
Mail Engine
Stalwart

Production-grade mail server. JMAP for modern access, SMTP/IMAP for compatibility. Runs in Docker with persistent volumes.

API Layer
Hono + Node

TypeScript REST API. Account provisioning, domain management, Cloudflare DNS automation, JMAP email operations. Zod-validated.

Agent Interface
MCP + CLI

10 typed MCP tools for Claude. CLI (sendbox) for humans. Same REST backend, different transports.

4
MCP Server

10 tools. Typed schemas.

Every email operation an agent needs — exposed as MCP tools with Zod-validated parameters and structured responses.

Email Operations
send_email
Send from any provisioned mailbox. To, CC, BCC, HTML body, reply-to threading.
list_emails
List with filters — sender, recipient, subject, date range. Paginated.
read_email
Full email by ID — headers, body, attachment metadata.
search_emails
Free-text search across subject, sender, date range.
list_threads
Conversations grouped by References/In-Reply-To headers.
read_thread
All messages in a thread, chronological order.
Provisioning
create_account
Provision a new mailbox. Creates Stalwart user + Postgres record.
list_accounts
All accounts with email, display name, domain, creation date.
Domain & DNS
add_domain
Register a domain + auto-create MX, SPF, DKIM, DMARC records via Cloudflare.
list_domains
All domains with DNS verification status and record details.
5
Protocol

JMAP, not IMAP

JMAP is the modern replacement for IMAP — JSON over HTTP, stateless, push-capable, and designed for the way applications actually consume email.

JMAP

  • JSON over HTTP — no binary protocol parsing
  • Batched requests — send + submit in one call
  • Stateless — no long-lived connections
  • Push via EventSource — no polling
  • Built-in threading and identity management

IMAP (Legacy)

  • Binary protocol from 1986
  • Stateful connections — fragile at scale
  • No batching — one command at a time
  • IDLE polling for new messages
  • No native threading
// Send flow: draft + submit in one batched JMAP request Email/set → create draft in Drafts mailbox EmailSubmission/set → submit with onSuccessDestroyEmail // Result: email sent + draft auto-deleted. One round-trip.
6
DNS Automation

Add a domain. DNS configures itself.

Register a domain through the API or MCP. Cloudflare DNS records are created automatically — MX, SPF, DKIM, DMARC. No manual configuration.

MX

Routes inbound mail
to Stalwart

SPF

Authorizes your server
to send

DKIM

Cryptographic signing
for authenticity

DMARC

Policy enforcement
+ reporting

# Via MCP (Claude) "Add domain acme.com with Cloudflare token cf_xxx" → Domain added. 4 DNS records created. Verification: pending. # Via CLI sendbox domain add --name acme.com --cf-token cf_xxx ✓ MX → mail.acme.com (priority 10) ✓ SPF → "v=spf1 mx ~all" ✓ DKIM → mail._domainkey.acme.com ✓ DMARC → _dmarc.acme.com
7
CLI

sendbox commands

Everything the MCP server can do, humans can do from the terminal. Interactive prompts, color output, config persistence.

# Initialize connection sendbox init ? API URL: http://localhost:3100 ? API Key: iws_a1b2c3... ✓ Config saved to ~/.sendbox/config.json # Create a mailbox sendbox account create --email agent@acme.com ✓ Account created: agent@acme.com # Send email sendbox email send --from agent@acme.com \ --to user@example.com \ --subject "Hello from sendbox" \ --body "Sent by an agent." ✓ Email sent (id: e_7kx9m2)

Account Commands

account create
account list
account delete

Domain Commands

domain add
domain list
domain verify

Email Commands

email send
email list
email read
email search

8
Quickstart

Running in 60 seconds

Docker Compose handles everything. Stalwart, Postgres, health checks, schema migrations. One copy-paste block.

# Clone and configure git clone git@github.com:indigoai-us/indigo-workspace.git cd indigo-workspace cp .env.example .env # Start everything (waits for health checks) docker compose up -d --wait ✔ Container indigo-postgres Healthy ✔ Container indigo-stalwart Healthy # Setup database + get API key npm install && npm run db:migrate && npm run seed → API Key: iws_a1b2c3d4e5f6... # Start API server npm run dev → Hono listening on http://localhost:3100
2
Docker Containers
6
Protocols Exposed
10
MCP Tools
74
E2E Tests
9
Security

API keys. Not OAuth.

Agents get a hashed API key. No refresh tokens, no browser redirects, no expiry headaches. Cloudflare tokens encrypted at rest.

API Authentication

  • x-api-key header on every request
  • Keys stored as bcrypt hashes in Postgres
  • Raw key shown once at seed — never retrievable
  • No OAuth, no refresh tokens, no scoping

Credential Flow

npm run seed
generates nanoid key (iws_...)
bcrypt hash stored in api_keys
raw key printed to stdout (once)

DNS Token Encryption

  • Cloudflare API tokens encrypted at the app layer
  • 64-char hex ENCRYPTION_KEY required
  • Stored encrypted in domains table
  • Decrypted only at DNS operation time

Infrastructure Auth

  • Stalwart admin: Basic auth (admin + password from env)
  • Postgres: user/password from env, local network only
  • All JMAP calls routed through admin — API enforces per-account scoping
10
Roadmap

Phase 0 is complete.

Email works. Agents can send, read, search, and thread. Domains auto-configure via Cloudflare. The foundation is set.

Phase 1

  • Calendar via JMAP CalDAV
  • Contacts / address book
  • Multi-tenant account isolation
  • Webhook notifications on inbound

Phase 2

  • Cloud deployment (ECS / Fly.io)
  • Web UI for account admin
  • S3-backed blob storage
  • Attachment handling in MCP

Phase 3

  • Full Google Workspace replacement
  • Drive-equivalent file storage
  • Shared mailboxes / aliases
  • Agent-to-agent email routing
7 / 7 STORIES COMPLETE Self-hosted email for agents. No Google. No OAuth. No permission.
10 / 10