Skip to content

Digidai/mails

 
 

Repository files navigation

mails-agent

Email infrastructure for AI agents. Send, receive, search, and extract verification codes.

npm license downloads

日本語 | 中文

Agent Integration: Use mails-skills to give your Claude Code, OpenClaw, or any AI agent email capabilities with one command.

Why mails?

Unlike raw email APIs that only send, mails gives your agent a complete email identity — send, receive, search, and extract verification codes in one package. Deploy on your own domain with Cloudflare (free tier). Full control, no third-party dependency.

Features

  • Send emails — via Resend with attachment support
  • Receive emails — via Cloudflare Email Routing → Worker → D1
  • Search inbox — FTS5 full-text search across subject, body, sender, code
  • Semantic search — AI-powered vector search via Workers AI + Cloudflare Vectorize (keyword, semantic, hybrid modes)
  • Dashboard console — visual email management UI at mails0.com/console
  • Verification code extraction — auto-extracts 4-8 char codes (EN/ZH/JA/KO)
  • Email threading — auto-assign thread_id via In-Reply-To / References headers
  • Auto labels — rule-based classification: newsletter, notification, code, personal
  • Structured data extraction — extract orders, shipping, calendar, receipts from emails (rule-based, no LLM)
  • Attachments — send via CLI (--attach) or SDK; receive with R2 storage for large files
  • Webhook notifications — POST to your URL on email receive, with HMAC-SHA256 signature
  • Mailbox isolation — per-token mailbox binding via auth_tokens D1 table
  • Delete API — remove processed emails with cascade cleanup (attachments + R2)
  • Storage providers — local SQLite (dev) or remote Worker API (production)
  • Zero runtime dependencies — all providers use raw fetch()
  • Self-hosted — deploy your own Worker on Cloudflare (free tier), full control over your data

Install

npm install -g mails-agent
# or
bun install -g mails-agent
# or use directly
npx mails-agent

Quick Start

# 1. Deploy your Worker (see Self-Hosted Deployment guide below)
cd worker && wrangler deploy

# 2. Configure the CLI
mails config set worker_url https://your-worker.example.com
mails config set worker_token YOUR_TOKEN
mails config set mailbox agent@yourdomain.com
mails config set default_from agent@yourdomain.com

# 3. Use it
mails send --to user@example.com --subject "Hello" --body "World"
mails inbox                          # List received emails
mails inbox --query "password"       # Search emails
mails code --to agent@yourdomain.com # Wait for verification code

How it works

                          SENDING                                    RECEIVING

  Agent                                              External
    |                                                  |
    |  mails send --to user@example.com                |  email to agent@yourdomain.com
    |                                                  |
    v                                                  v
+--------+                                   +-------------------+
|  CLI   |------ /api/send ----------------->| Cloudflare Email  |
|  /SDK  |<----- /api/inbox -----------------|     Routing       |
+--------+                                   +-------------------+
    |                                                  |
    v                                                  v
+--------------------------------------------------+
|              Your Cloudflare Worker               |
|  /api/send → Resend API → SMTP delivery          |
|  /api/inbox, /api/code → D1 query (FTS5 search)  |
|  email() handler → parse MIME → store in D1       |
+--------------------------------------------------+
    |               |
    v               v
+--------+    +------------+
|   D1   |    |     R2     |
| emails |    | attachments|
+--------+    +------------+
    |
    |  query via CLI/SDK
    v
  Agent
    mails inbox
    mails inbox --query "code"
    mails code --to agent@yourdomain.com

CLI Reference

send

mails send --to <email> --subject <subject> --body <text>
mails send --to <email> --subject <subject> --html "<h1>Hello</h1>"
mails send --from "Name <email>" --to <email> --subject <subject> --body <text>
mails send --to <email> --subject "Report" --body "See attached" --attach report.pdf

inbox

mails inbox                                  # List recent emails
mails inbox --mailbox agent@test.com         # Specific mailbox
mails inbox --query "password reset"         # Search emails
mails inbox --query "invoice" --direction inbound --limit 10
mails inbox <id>                             # View email details + attachments

code

mails code --to agent@test.com              # Wait for code (default 30s)
mails code --to agent@test.com --timeout 60 # Custom timeout

The code is printed to stdout for easy piping: CODE=$(mails code --to agent@test.com)

config

mails config                    # Show all config
mails config set <key> <value>  # Set a value
mails config get <key>          # Get a value

SDK Usage

import { send, getInbox, searchInbox, getEmail, deleteEmail, waitForCode } from 'mails-agent'

// Send
const result = await send({
  to: 'user@example.com',
  subject: 'Hello',
  text: 'World',
})

// Send with attachment
await send({
  to: 'user@example.com',
  subject: 'Report',
  text: 'See attached',
  attachments: [{ path: './report.pdf' }],
})

// List inbox
const emails = await getInbox('agent@yourdomain.com', { limit: 10 })

// Search inbox
const results = await searchInbox('agent@yourdomain.com', {
  query: 'password reset',
  direction: 'inbound',
})

// Get email details (with attachments)
const email = await getEmail('email-id')

// Delete email (cascade: attachments + R2)
await deleteEmail('email-id')

// Wait for verification code
const code = await waitForCode('agent@yourdomain.com', { timeout: 30 })
if (code) console.log(code.code) // "123456"

Storage Providers

The CLI auto-detects the storage provider:

  • worker_url in config → remote (queries Worker API)
  • Otherwise → local SQLite (~/.mails/mails.db)
Config Keys
Key Set by Description
mailbox manual Your receiving address
worker_url manual Worker URL (enables remote provider)
worker_token manual Auth token for Worker
resend_api_key manual Resend API key (not needed when worker_url is set)
default_from manual Default sender address
storage_provider auto sqlite or remote (auto-detected)
Self-Hosted Deployment (Full Guide)

Run the entire email system on your own domain using Cloudflare + Resend. Full control, no third-party dependency.

Prerequisites

What Why Cost
A domain (e.g. example.com) Email address agent@example.com You already own one
Cloudflare account DNS, Email Routing, Worker, D1 Free tier is enough
Resend account SMTP delivery Free 100 emails/day

Step 1: Add domain to Cloudflare

If your domain's DNS is not already on Cloudflare, add it at dash.cloudflare.com. Update your registrar's nameservers to the ones Cloudflare provides.

Step 2: Set up Resend for sending

  1. Create a Resend account
  2. Go to DomainsAdd Domain → enter your domain (e.g. example.com)
  3. Resend will give you DNS records to add. Go to Cloudflare DNS and add:
    • SPFTXT record on @: v=spf1 include:amazonses.com ~all (Resend uses SES)
    • DKIMCNAME records as provided by Resend (usually 3 records)
    • DMARCTXT record on _dmarc: v=DMARC1; p=none; (start with none, tighten later)
  4. Wait for Resend to verify your domain (usually minutes, can take up to 48h)
  5. Copy your Resend API key (re_...) from the Resend dashboard

Step 3: Deploy the Worker

cd worker
bun install

# Create D1 database
wrangler d1 create mails
# → Copy the database_id from the output

# Edit wrangler.toml — paste your database_id
# Replace REPLACE_WITH_YOUR_DATABASE_ID with the actual ID

# Initialize database schema
wrangler d1 execute mails --file=schema.sql

# Set secrets
wrangler secret put AUTH_TOKEN         # Choose a strong random token
wrangler secret put RESEND_API_KEY     # Paste your re_... key from Resend

# Deploy
wrangler deploy
# → Note the Worker URL: https://mails-worker.<your-subdomain>.workers.dev

Step 4: Set up Cloudflare Email Routing

  1. Go to Cloudflare Dashboard → your domain → EmailEmail Routing
  2. Click Enable Email Routing (Cloudflare will add MX records automatically)
  3. Go to Routing rulesCatch-all address → set action to Send to a Worker → select your deployed Worker
  4. Now all emails to *@example.com will be routed to your Worker

Step 5: (Optional) Create R2 bucket for large attachments

wrangler r2 create mails-attachments

The R2 binding is already configured in wrangler.toml. Redeploy after creating the bucket:

wrangler deploy

Step 6: Configure the CLI

mails config set worker_url https://mails-worker.<your-subdomain>.workers.dev
mails config set worker_token YOUR_AUTH_TOKEN       # Same token from Step 3
mails config set mailbox agent@example.com          # Your email address
mails config set default_from agent@example.com     # Default sender

Step 7: Verify

# Check Worker is reachable
curl https://mails-worker.<your-subdomain>.workers.dev/health

# Check inbox (should be empty)
mails inbox

# Send a test email
mails send --to your-personal@gmail.com --subject "Test" --body "Hello from self-hosted mails"

# Send an email TO your mailbox from any email client, then:
mails inbox

Architecture after setup

Your Agent                              External sender
    |                                        |
    |  mails send / mails inbox              |  email to agent@example.com
    v                                        v
+--------+                         +-------------------+
|  CLI   |------ /api/send ------->|  Cloudflare Email |
|  /SDK  |<----- /api/inbox -------|     Routing       |
+--------+                         +-------------------+
    |                                        |
    v                                        v
+--------------------------------------------------+
|              Your Cloudflare Worker               |
|  /api/send → Resend API → SMTP delivery          |
|  /api/inbox, /api/code → D1 query (FTS5 search)  |
|  email() handler → parse MIME → store in D1       |
+--------------------------------------------------+
    |               |
    v               v
+--------+    +------------+
|   D1   |    |     R2     |
| emails |    | attachments|
+--------+    +------------+

Worker Secrets Reference

Secret Required Description
AUTH_TOKEN Recommended API authentication token. If set, all /api/* endpoints require Authorization: Bearer <token>
RESEND_API_KEY Yes (for sending) Resend API key (re_...). The Worker uses this to send emails via /api/send
WEBHOOK_SECRET Optional HMAC-SHA256 key for signing webhook payloads (X-Webhook-Signature header)

Worker API Endpoints

Endpoint Description
POST /api/send Send email (requires RESEND_API_KEY secret)
GET /api/inbox?to=<addr>&limit=20 List emails
GET /api/inbox?to=<addr>&query=<text> Search emails (FTS5 full-text search)
GET /api/code?to=<addr>&timeout=30 Long-poll for verification code
GET /api/email?id=<id> Get email by ID (with attachments)
DELETE /api/email?id=<id> Delete email (and its attachments + R2 objects)
GET /api/attachment?id=<id> Download attachment
GET /api/threads?to=<addr> List conversation threads
GET /api/thread?id=<id>&to=<addr> Get all emails in a thread
GET /api/search?to=<addr>&q=<text>&mode=hybrid Semantic/hybrid search (alias for inbox with mode=hybrid)
POST /api/extract Extract structured data (order, shipping, calendar, receipt, code)
GET /api/me Worker info and capabilities
GET /health Health check (always public, no auth)

Send Priority

When the CLI/SDK sends an email, it checks config in this order:

  1. worker_url → sends via your Worker's /api/send (recommended)
  2. resend_api_key → sends directly to Resend API

Once worker_url is set, you don't need resend_api_key on the client — the Worker holds the Resend key as a secret.

Testing
bun test              # Unit + mock E2E tests
bun test:coverage     # With coverage report
bun test:live         # Live E2E with real Resend + Cloudflare (requires .env)

298 tests across 29 test files.

Ecosystem

┌─────────────────────────────────────────────────────────────┐
│                        mails ecosystem                       │
│                                                              │
│  ┌──────────────┐    ┌──────────────────┐    ┌───────────┐  │
│  │  mails CLI   │    │  mails Worker    │    │   mails   │  │
│  │  & SDK       │───▶│  (Cloudflare)    │◀───│  -skills  │  │
│  │              │    │                  │    │           │  │
│  │ npm i mails- │    │  Receive + Send  │    │  Agent    │  │
│  │    agent     │    │                  │    │           │  │
│  │              │    │  + Search + Code │    │  Skills   │  │
│  └──────────────┘    └──────────────────┘    └───────────┘  │
│    Human / Script        Infrastructure        AI Agents    │
└─────────────────────────────────────────────────────────────┘
Project What it is Who uses it
mails (this repo) Email server (Worker) + CLI + SDK Developers deploying email infra
mails-agent-mcp MCP Server for AI agents Claude Desktop, Cursor, any MCP client
mails-agent (Python) Python SDK Python developers, async agents
mails-skills Skill files for AI agents AI agents (Claude Code, OpenClaw, Cursor)

Quick agent setup:

# MCP Server (Claude Desktop / Cursor)
npm install -g mails-agent-mcp

# Python SDK
pip install mails-agent

# Agent Skills
git clone https://github.com/Digidai/mails-skills && cd mails-skills && ./install.sh

Contributing

See CONTRIBUTING.md for development setup, project structure, and PR guidelines.

Acknowledgments

This project is based on mails by turing, originally created as email infrastructure for AI agents. We forked and extended it with mailbox isolation, webhook notifications, delete API, R2 attachment storage, Worker file refactoring, and comprehensive test coverage (298 tests). Thank you to the original author for the excellent foundation.

License

MIT — see LICENSE for details. Original copyright retained per MIT terms.

About

mails-agent: Email infrastructure for AI agents. Send, receive, search, extract verification codes. CLI + SDK + Cloudflare Worker. Based on chekusu/mails.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

No contributors

Languages

  • TypeScript 100.0%