Cloudflare Workers email inbox service with a Rust CLI. Receives emails via Email Routing (catch-all), stores in D1, exposes token-protected REST API for AI agents.
- Runtime: Cloudflare Workers
- Framework: Hono.js + TypeScript
- Database: Cloudflare D1
- Attachment storage: Cloudflare R2 (
ATTACHMENTSbucket) - Email Parsing: postal-mime + html-to-text
- CLI: Rust (clap + reqwest + serde)
- Package Manager: Bun
- Linter/Formatter: Biome (tabs, double quotes, semicolons, 100 char width)
bun run dev— Local dev (remote mode)bun run deploy— Deploy to Cloudflarebun run tsc— Type checkbun run check— Biome lint + format checkbun run check:fix— Biome lint + format with auto-fixbun run lint— Biome lint onlybun run lint:fix— Biome lint with auto-fixbun run format— Biome format onlybun run tail— Wrangler tail (live logs)bun run cf-typegen— Generate Cloudflare binding typesbun run r2:create— Create R2 attachment bucketbun run db:create— Create D1 databasebun run db:tables— Apply schema (idempotent; also adds theattachmentstable)bun run db:indexes— Apply indexes
src/ # Cloudflare Worker (TypeScript)
├── index.ts # Worker entry (fetch + email handlers)
├── app.ts # Hono app setup, middleware, routes
├── env.d.ts # CloudflareBindings secret extensions
├── types.ts # TypeScript types
├── middleware/auth.ts # Bearer token auth
├── routes/emails.ts # Email CRUD + export + send endpoints
├── routes/health.ts # Health check
├── database/d1.ts # All D1 query functions
├── handlers/email.ts # Email Routing handler (parse + store)
├── providers/ # Email send providers
│ ├── types.ts # EmailProvider interface
│ ├── resend.ts # Resend API provider
│ ├── cloudflare.ts # Cloudflare Email Service provider
│ └── index.ts # Provider factory
└── utils/ # http, helpers, mail processing
rust-cli/ # Rust CLI
└── main.rs # CLI entry (list, export, get, delete, send, health, config)
skills/mailclaw/SKILL.md # Claude Code skill definition
install.sh # Cross-platform CLI install script
.github/workflows/
└── release-cli.yml # CI: build + publish CLI binaries on tag push
All /api/emails* routes require Authorization: Bearer <token>.
GET /api/emails— List (metadata only, paginated)GET /api/emails/export— List with full content (paginated)GET /api/emails/:id— Single email detail (includesattachmentsmetadata)DELETE /api/emails/:id— Delete email (and its R2 attachments)GET /api/emails/:id/attachments— List attachment metadataGET /api/emails/:id/attachments/:attachmentId— Download raw attachment bytes (not the JSON envelope)POST /api/emails/send— Send email (via Resend or Cloudflare provider)GET /api/health— Health check (no auth)
from, to, q (keyword), after, before (date), limit, offset
The Rust CLI (mailclaw) wraps the REST API. Config is stored in ~/.mailclaw/config.json.
mailclaw config set --host <URL> --api-token <TOKEN>— Save credentialsmailclaw config show— Show current configmailclaw list/export/get <id>/delete <id>/send/health— API operationsmailclaw attachments <id>— List an email's attachmentsmailclaw download <email_id> <attachment_id> [-o path]— Download one attachment- All commands support
--jsonfor machine-readable output
Push a tag (v*) to trigger release-cli.yml, which builds binaries for linux-x86_64, linux-aarch64, macos-x86_64, macos-aarch64, and windows-x86_64, then uploads them to the GitHub Release.