LM

leeguooooo/mail-use

Developer tools
47 stars 8 forks Quality 84 Trend 27MIT

Email for AI agents — read, search, send and triage Gmail / QQ / 163 / any IMAP from the CLI or MCP. Part of the *-use family.

Overview

One CLI over Gmail, QQ, 163, Outlook and any IMAP/SMTP box — every command speaks JSON, every destructive one is dry-run until you pass --confirm. Part of the *-use family — small tools that each give an agent hands on one real thing. - Every response carries success: boolean, and failures carry error_code from a fixed set (auth_failed, folder_not_found, imap_error, …). Documented in docs/CLI_JSON_CONTRACT.md. - Cached reads report from_cache, cache_age_seconds and cache_stale, and a snapshot old enough to mean "nothing is syncing" is refused in favour of a live fetch. An empty inbox is never a silent "nothing arrived". - delete / mark / move / send return a dry-run preview — grouped per account and folder, with sample subjects — and change nothing until --confirm. --all-folders skips Sent/Drafts/Junk/Trash unless asked.

README

mail-use

Email, as something an AI agent can actually operate. One CLI over Gmail, QQ, 163, Outlook and any IMAP/SMTP box — every command speaks JSON, every destructive one is dry-run until you pass --confirm.

mail-use code --json          # the newest verification code, one live pass
mail-use email recent --format compact --json
mail-use email delete --from [email protected] --confirm --json

Part of the *-use family — small tools that each give an agent hands on one real thing.

Why this and not an IMAP snippet

  • A stable JSON contract, not scraped text. Every response carries success: boolean, and failures carry error_code from a fixed set (auth_failed, folder_not_found, imap_error, …). Documented in docs/CLI_JSON_CONTRACT.md.
  • It tells you when it might be wrong. Cached reads report from_cache, cache_age_seconds and cache_stale, and a snapshot old enough to mean “nothing is syncing” is refused in favour of a live fetch. An empty inbox is never a silent “nothing arrived”.
  • Destructive by consent only. delete / mark / move / send return a dry-run preview — grouped per account and folder, with sample subjects — and change nothing until --confirm. --all-folders skips Sent/Drafts/Junk/Trash unless asked.
  • Built for token budgets. --format compact projects each email to the ten fields worth scanning (~30% smaller than the full shape), --with-preview folds a body snippet into the list call, and batch show reuses one IMAP connection.
  • Fast enough to call in a loop. A persistent daemon pools IMAP connections and syncs to local SQLite in the background: five sequential email list calls go from 25s to 0.83s. See the table below.
  • MCP too. mail-use mcp config --json prints a paste-ready entry; the server exposes 16 tools with the same dry-run defaults.

Renamed from Mailbox to mail-use. The command is now mail-use; mailbox still works as an alias, and your config in ~/.config/mailbox is untouched.

Supported providers

163 / 126 · QQ · Gmail · Outlook / Hotmail · any custom IMAP+SMTP server.

Search behaves differently per provider and the CLI says so: Gmail searches bodies server-side via X-GM-RAW, while QQ/163/Outlook have broken IMAP TEXT search, so --query falls back to matching subject + sender only. Use --from / --subject there for predictable results.

Install

One line, no npm, no Node

curl -fsSL https://raw.githubusercontent.com/leeguooooo/mail-use/main/install.sh | sh
mail-use --help

Downloads the prebuilt binary for your platform (macOS arm64/x64, Linux x64/arm64) from the latest GitHub Release, verifies its checksum, and installs to ~/.local/bin. Pin a version with MAIL_USE_VERSION=v2.11.2, or change the dir with MAIL_USE_INSTALL_DIR=.... A missing .sha256 aborts the install (MAIL_USE_INSECURE=1 overrides; a mismatch is always fatal). Each tarball also carries signed build provenance: gh attestation verify mail-use-.tar.gz --repo leeguooooo/mail-use.

The installer also drops a mailbox symlink next to it, so scripts written against the old name keep working.

There is no npm package. Distribution is GitHub Release binaries only — that keeps releases free of NPM_TOKEN and 2FA prompts, and keeps install free of a Node toolchain. The pre-rename @leeguoo/mailbox-cli packages on npm are frozen and no longer updated.

Upgrading

mail-use upgrade --check     # is there a newer release? (`mail-use 3.3.1 -> 3.3.2`)
mail-use upgrade --check --json  # the same check as JSON: name, current, latest, update_available, skills, install_channel, checked_only
mail-use upgrade             # (--json only changes the output format) CLI only: download, verify sha256, check the new binary's version, swap atomically, restart the daemon
mail-use upgrade --skills    # the same, then refresh this tool's own skill copies (skill-only when the CLI is current)
mail-use upgrade --tag v3.1.0   # pin an exact release (also the way to roll back)

Exit code 0 means the command worked (an update being available is not an error); 2 means the check, the download or the verification failed (the installed binary is left as it was); 1 means it refused because Homebrew, npm or a source checkout owns this install (it prints that manager’s command instead), or a skill could not be refreshed.

A plain upgrade only lists the skill copies it finds, with the command that would refresh each. upgrade --skills refreshes them: a Claude Code plugin (claude plugin update mail-use@leeguooooo-plugins, or printed if claude isn’t on PATH), a git checkout linked into ~/.agents/skills, ~/.claude/skills or ~/.codex/skills (git pull --ff-only, never forced), or a copied folder from npx skills add (it prints npx skills update mail-use for you to run).

Any other command checks for a new release at most once a day (cached in ${XDG_CACHE_HOME:-~/.cache}/mail-use/update-check.json, 2 s timeout, failures silent) and, when one exists, prints a single line to stderr — stdout stays clean JSON: mail-use 3.3.2 is available (you have 3.3.1). Upgrade: mail-use upgrade. Set CI, MAIL_USE_NO_UPDATE_CHECK or USE_NO_UPDATE_CHECK to turn it off.

When the daemon is running it notices new releases for you: one unauthenticated GET to the GitHub releases API per day (MAILBOX_UPDATE_CHECK_HOURS, 0 disables), surfaced as update in mail-use daemon status --json. It only ever reports — it never downloads or installs anything.

upgrade is never automatic and never runs on its own: a tool that silently replaces its own executable is a supply-chain surprise, not a convenience. It refuses to install a tarball whose published .sha256 is missing or doesn’t match, or whose binary does not report the requested version, and refuses to run at all from a Homebrew, npm or dev-checkout install. Re-running the curl … install.sh | sh line does the same job.

As an AI Skill (Claude Code / Cursor / etc.)

# Project scope — installs into ./.claude/skills/mail-use (or ./.cursor/skills/...):
npx skills add leeguooooo/mail-use --skill mail-use

# User scope — installs into ~/.claude/skills/mail-use:
npx skills add leeguooooo/mail-use --skill mail-use -g

The skill assumes the CLI is on PATH (install via the curl … install.sh | sh above). For the biggest speedup also run mail-use daemon install once.

MCP server (Claude Desktop / Code / Cursor)

mail-use mcp config --json   # prints a paste-ready mcpServers entry

From source (development)

pnpm install
pnpm test

# build a local platform binary into dist/mail-use
pnpm build:binary

If a test run is interrupted (editor task killed, agent session closed), its Vitest workers can be left behind and hold memory. Check with pgrep -fl vitest and kill what remains.

Configure accounts

mkdir -p ~/.config/mailbox
cp examples/accounts.example.json ~/.config/mailbox/auth.json

Config locations:

  • Credentials: ~/.config/mailbox/auth.json
  • Other settings: ~/.config/mailbox/config.toml

Apple Mail, both ways

Agents use mail-use, people use Apple Mail; both talk to the same server, so an account only has to be set up once:

mail-use apple-mail status    # which mailboxes each side has
mail-use apple-mail           # mail-use → Apple Mail: opens System Settings on the profile, click Install
mail-use apple-mail import    # Apple Mail → mail-use: paste one app password / authorization code per mailbox
mail-use account add          # neither side has it yet: start here

Apple Mail keeps its passwords to itself (and Gmail added through Google sign-in has none), so importing needs one authorization code per mailbox; macOS only installs profiles through System Settings, so exporting needs one click. Mailboxes already in Apple Mail are skipped, so nothing gets duplicated. Step-by-step guide (Chinese), where to get each provider’s code, and FAQ: docs/guides/apple-mail.md.

Common commands

# CLI help
mail-use --help

# newest verification code across all accounts, one live pass
mail-use code --json

# list accounts
mail-use account list --json

# list unread emails (cache by default; --from filters cache-side)
mail-use email list --unread-only --limit 20 --json
mail-use email list --account-id my_account_id --from "newsletter" --json

# show one email (response includes list_unsubscribe when the header is set)
mail-use email show 123456 --account-id my_account_id --json

# mark read (use --dry-run to validate first)
mail-use email mark 123456 --read --account-id my_account_id --folder INBOX --dry-run --json
mail-use email mark 123456 --read --account-id my_account_id --folder INBOX --confirm --json

# delete
mail-use email delete 123456 --account-id my_account_id --folder INBOX --confirm --json

# bulk mutate by sender or subject (no UID list needed)
mail-use email mark --from "[email protected]" --read --confirm --account-id my_account_id --json
mail-use email delete --from "newsletter" --account-id my_account_id --json    # dry-run preview
mail-use email delete --subject "[ad]" --account-id my_account_id --confirm --json

Cache + sync

  • Cache DB default: ~/.local/share/mailbox/email_sync.db
  • Listing uses cache by default where possible. Add --live to force IMAP.
mail-use sync status --json
mail-use sync force --json
mail-use sync init
mail-use sync daemon

Persistent daemon (5-30× faster CLI calls)

Each one-shot invocation otherwise spends 1-3s on TCP+TLS+IMAP LOGIN. With the daemon running, calls reuse pooled connections and a background SQLite sync means email list usually doesn’t touch IMAP at all.

The curl … install.sh | sh installer sets this up for you when accounts are already configured (MAIL_USE_NO_DAEMON=1 opts out). Otherwise:

mail-use daemon install      # autostart at login (macOS launchd / Linux systemd-user)
mail-use daemon status --json
mail-use daemon reload       # drop pooled connections after editing auth.json

Measured on Gmail INBOX, M2 MacBook over residential WAN:

Operation No daemon Daemon (--live) Daemon (cached)
Single email list 5.0s 1.0s 0.17s
email folders 5.0s 0.85s n/a
5 sequential email list 25s 5.3s 0.83s
3 parallel email show ~15s 2.7s 0.88s

Resource footprint (many agent sessions on one machine)

The daemon is one process per user, shared by every agent session through a Unix socket — so more sessions do not mean more IMAP connections. Measured idle on macOS with 3 accounts connected:

Idle CPU ~0.15%
Idle RSS 3-15 MB
Connections max 3 per account (MAILBOX_POOL_MAX), reaped back to 1 after 10 min idle
12 concurrent calls 1.6s wall clock, pool stayed at 1 connection per account

Knobs, if the defaults do not suit you:

Env Default Effect
MAILBOX_POOL_MAX 3 Max concurrent IMAP connections per account
MAILBOX_POOL_IDLE_MS 600000 Close connections idle this long (0 disables reaping)
MAILBOX_POOL_KEEP_WARM 1 Connections per account kept warm through reaping
MAILBOX_NO_DAEMON unset 1 makes the CLI skip the daemon entirely
MAILBOX_UPDATE_CHECK_HOURS 24 Daemon’s passive update check (0 disables it and the CLI’s daily notice)
MAIL_USE_NO_UPDATE_CHECK / USE_NO_UPDATE_CHECK unset Any value turns off the CLI’s daily “new version” notice

AI usage guide

Mail classification belongs to the calling AI. mail-use cleanup --limit 50 --json returns live metadata, body previews and gids for review; use --offset for the next page and email show for full content. The AI selects specific gids and executes them with email move, mark, flag or delete. cleanup and inbox never classify or choose actions, and legacy category cleanup is rejected.

If you’re integrating this CLI into an AI agent, start here:

  • docs/AI_SKILL_MAIL_USE.md

OpenClaw integration

This repo includes an OpenClaw skill at skills/mail-use/SKILL.md.

OpenClaw loads skills from:

  • /skills
  • ~/.openclaw/skills

Quick link helper (symlink into ~/.openclaw/skills):

./scripts/link_openclaw_skill.sh

Force replace an existing link:

./scripts/link_openclaw_skill.sh --force

To use this repo without copying files, add the repo skills directory to skills.load.extraDirs in ~/.openclaw/openclaw.json:

{
  "skills": {
    "load": {
      "extraDirs": [
        "/path/to/mcp-email-service/skills"
      ]
    }
  }
}

OpenClaw handles channel delivery and scheduling; mail-use returns structured JSON outputs and optional text summaries.

Verify OpenClaw picked up the skill:

openclaw skills list --eligible
openclaw skills check

The *-use family

Small, composable CLIs that give an AI agent hands on one real thing. Same shape everywhere: curl … install.sh | sh to install, npx skills add leeguooooo/ to teach your agent, JSON on stdout.

Repo Gives your agent
chrome-use A real browser — logged-in sessions, forms, scraping, screenshots
mail-use Email — read, search, send, triage across Gmail / QQ / 163 / any IMAP
iphone-use A real iPhone — tap, type, screenshot, pull on-device data
wechat-use WeChat on macOS — send messages, query contacts and history
discord-use Discord — messages, channels, forums, webhooks (REST-only, Rust)
cookie-use Many logged-in accounts per site — capture, switch, apply sessions
profile-use Your personal profile, safely — fill signup / KYC / checkout forms
bitwarden-use Bitwarden / Vaultwarden — headless passkey (FIDO2) login
chatgpt-use Your ChatGPT subscription as a coding-agent backend — no API key
computer-use The macOS desktop itself
pixcake-use Read-only PixCake probing — snapshot / diff / SQLite inspection

Contract

  • docs/CLI_JSON_CONTRACT.md

Built by leeguooooo — field notes on AI agents, reverse engineering & Cloudflare Workers at blog.misonote.com · follow on X @leeguooooo

Author

Built by 郭立 (Guo Li / leeguoo) — leeguoo.com · GitHub · X · more tools in the *-use family.

View the full README on GitHub

Install

npx skills update mail-use` for you to run).
New to MCP? Start with the mcpskill.org guide →