email for agents

Claim a mailbox for your AI agent. One click, no signup required.

@mails0.com
Mailbox
API Key
Save your API key now — it won't be shown again.

Install npm install -g mails-agent

$ mails claim myagent
$ mails send --to user@example.com --subject "Hello" --body "World"
$ mails inbox
$ mails inbox --query "verification code"
$ mails code --to myagent@mails0.com

Give your AI agent email capabilities.

npx npx mails-skills
curl curl -sL mails0.com/skill.md > ~/.claude/skills/email.md
mails0.com

What mails-agent does

📨

Send emails

Send via Resend API with attachment support. Plain text, HTML, or both. Up to 50 recipients per email.

📬

Receive emails

Cloudflare Email Routing catches all mail to your domain and stores it in D1. Query via API or CLI.

🔍

Search inbox

FTS5 full-text search across subject, body, sender, and codes. LIKE fallback for email addresses.

🔑

Verification codes

Auto-extract 4-8 character codes from emails. Supports EN, ZH, JA, KO. Long-poll until code arrives.

📎

Attachments

Send files via CLI or SDK. Receive with R2 storage for large files (>100KB auto-uploaded).

🔔

Webhooks

POST notification on every received email. HMAC-SHA256 signed. Fire-and-forget via waitUntil.

🔒

Mailbox isolation

Per-token mailbox binding. Each API key is scoped to one mailbox. No cross-mailbox access.

🗑️

Delete API

Remove processed emails with cascade cleanup — attachments and R2 objects deleted automatically.

Get started in 4 steps

1

Install the CLI

npm install -g mails-agent
2

Claim your mailbox

On this page, type a name and click Claim. Or from the terminal:

mails claim myagent

This opens your browser to confirm. Once confirmed, your api_key, mailbox, and default_from are saved to ~/.mails/config.json.

3

Verify it works

Send a test email to your new mailbox, then check the inbox:

mails send --to myagent@mails0.com \ --subject "Test" --body "Hello from mails" mails inbox
4

Send, receive, and search

mails send --to user@example.com \ --subject "Hello" --body "World" mails inbox --query "password reset" mails code --to myagent@mails0.com --timeout 60
+

Give your AI agent email

Install the skill so Claude Code, Cursor, or any AI agent can use email:

npx mails-skills

CLI Reference

claim

mails claim <name> # Claim name@mails0.com

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 file.pdf mails send --to <email> --subject <subject> \ --body <text> --reply-to <email>

inbox

mails inbox # List recent mails inbox --mailbox <addr> # Specific mailbox mails inbox --query "keyword" # Search mails inbox --direction inbound # Filter mails inbox --limit 10 # Limit (default: 20) mails inbox <id> # View details

code

mails code --to <addr> # Wait for code (30s) mails code --to <addr> --timeout 60 mails code --to <addr> \ --since 2024-01-01T00:00:00Z

config

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

Config keys

KeyDescription
modeOperation mode: hosted or selfhosted
domainEmail domain (default: mails0.com)
mailboxYour receiving address
default_fromDefault sender address
api_keyAPI key for hosted mode (saved by mails claim)
send_providerSend provider: resend, worker, or hosted
storage_providerStorage provider: sqlite or remote
worker_urlWorker URL (enables remote provider)
worker_tokenAuth token for Worker
resend_api_keyResend API key (not needed with worker_url)

Environment Variables

VariableDescription
MAILS_API_URLOverride API base URL (default: https://mails-worker.genedai.workers.dev)
MAILS_CLAIM_URLOverride claim page URL (default: https://mails0.com)

Worker API Endpoints

Self-hosted: /api/*

Auth via Authorization: Bearer <AUTH_TOKEN> when configured. Mailbox passed as ?to= parameter.

MethodEndpointDescription
POST/api/sendSend email (requires RESEND_API_KEY)
GET/api/inbox?to=<addr>List emails. Params: query, limit, offset, direction
GET/api/code?to=<addr>Long-poll for verification code. Params: timeout, since
GET/api/email?id=<id>Get email details with attachments
DELETE/api/email?id=<id>Delete email + attachments + R2 objects
GET/api/attachment?id=<id>Download attachment
GET/api/meWorker info and capabilities
GET/healthHealth check (no auth)

Hosted: /v1/*

Token-scoped to a mailbox (from auth_tokens table). Same routes as /api/* but mailbox is bound to the token — no ?to= needed.

MethodEndpointDescription
POST/v1/sendSend email from bound mailbox
GET/v1/inboxList emails for bound mailbox
GET/v1/codeWait for verification code
GET/v1/email?id=<id>Get email details
DELETE/v1/email?id=<id>Delete email
GET/v1/attachment?id=<id>Download attachment
GET/v1/meResolve token to mailbox

Claim (hosted only)

MethodEndpointDescription
POST/v1/claim/startStart a claim session. Body: { "name": "myagent" }
POST/v1/claim/confirmConfirm a claim. Body: { "session_id": "..." }
GET/v1/claim/poll?session=<id>Poll claim status (used by CLI)

Webhook Payload

When a mailbox has a webhook_url configured in auth_tokens, each received email triggers a POST request. Signed with WEBHOOK_SECRET via HMAC-SHA256 in the X-Signature header.

{ "event": "email.received", "mailbox": "agent@mails0.com", "email": { "id": "msg_abc123", "from": "sender@example.com", "to": "agent@mails0.com", "subject": "Your verification code", "text": "Your code is 847291", "html": "<p>Your code is 847291</p>", "date": "2026-03-27T10:00:00Z", "has_attachments": false } }

SDK Usage

import { send, getInbox, searchInbox, getEmail, waitForCode, deleteEmail } from 'mails-agent' await send({ to: 'user@example.com', subject: 'Hello', text: 'World' }) const emails = await getInbox( 'agent@mails0.com', { limit: 10 } ) const results = await searchInbox( 'agent@mails0.com', { query: 'invoice' } ) const code = await waitForCode( 'agent@mails0.com', { timeout: 60 } ) await deleteEmail('email-id')

Self-Host on Your Domain

Deploy on Cloudflare (free tier). Full control, no third-party dependency.

Prerequisites

WhatWhyCost
Domain on CloudflareEmail address agent@yourdomain.comYou own it
Resend accountSMTP deliveryFree 100/day

Deploy

git clone https://github.com/Digidai/mails cd mails/worker && bun install # Create D1 database wrangler d1 create mails # Paste database_id into wrangler.toml # Initialize schema wrangler d1 execute mails \ --remote --file=schema.sql # (Optional) R2 for large attachments wrangler r2 create mails-attachments # Set secrets wrangler secret put RESEND_API_KEY wrangler secret put AUTH_TOKEN # Deploy wrangler deploy

Configure Email Routing

In Cloudflare Dashboard → your domain → Email → Email Routing:

  1. Enable Email Routing (adds MX records)
  2. Routing rules → Catch-all → Send to Worker → select your worker
  3. Enable the catch-all rule

Configure the CLI

mails config set mode selfhosted mails config set worker_url \ https://your-worker.workers.dev mails config set worker_token YOUR_AUTH_TOKEN mails config set mailbox agent@yourdomain.com mails config set default_from agent@yourdomain.com