# MailCli

> A local-first email interface for AI agents — structured inbox context, search, triage, and safe actions over your existing mailbox.

- **Type:** MCP server
- **Install:** `agentstack add mcp-nonozone-mailcli`
- **Verified:** Pending review
- **Seller:** [nonozone](https://agentstack.voostack.com/s/nonozone)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [nonozone](https://github.com/nonozone)
- **Source:** https://github.com/nonozone/MailCli

## Install

```sh
agentstack add mcp-nonozone-mailcli
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

[中文文档](README.zh-CN.md) | English

# MailCLI

**A local-first email interface for AI agents, built on top of the mailboxes people already use.**

MailCLI connects Gmail, Outlook / Microsoft 365, QQ Mail, 163 Mail, generic IMAP accounts, and local `.eml` fixtures to a stable CLI and JSON contract for agents.

It turns messy email into structured agent context:

- raw MIME becomes `StandardMessage` JSON and clean Markdown
- local mailboxes become searchable indexes and thread context
- deterministic parser output becomes triage evidence an agent can reason over
- outbound work uses `DraftMessage`, `ReplyDraft`, prepare/confirm steps, and operation logs

The core is written in Go and keeps provider quirks, MIME parsing, local indexing, and transport details behind explicit commands. Model-backed enrichment can be connected around that boundary, but MailCLI does not require a hosted mailbox service or a bundled LLM to be useful.

## What It Is

MailCLI is:

- an AI-facing layer over existing email accounts
- a provider-neutral CLI and JSON contract for email automation
- a local-first toolkit for parsing, indexing, searching, threading, triage evidence, and safe outbound workflows
- an MCP server for exposing read/setup workflows to local agents

MailCLI is not:

- a hosted agent mailbox with a new address
- a replacement for a human mail client like Gmail, Outlook, or Apple Mail
- a service that grants agents automatic permission to send, delete, move, or mark mail
- a promise that a model has made a decision for you inside the Go core

By default, the MCP server exposes read and setup tools: parse, list, get, sync, search, threads, thread, and config diagnostics/capabilities. Mutating mailbox actions such as send, delete, move, and mark are not exposed through the default MCP server.

## Who It Is For

MailCLI is useful if you are building:

- AI agents that need reliable inbox context without pasting raw email into prompts
- workflow automation that searches and summarizes real mailboxes
- tools that need a stable email JSON contract across multiple providers
- local-first prototypes that should work before OAuth, API quotas, or hosted mail infrastructure exist
- safety-sensitive outbound flows where drafts, intents, confirmation, and audit logs matter

## Try It Locally In 2 Minutes

You do not need a real mailbox or network access to understand the agent boundary.

```bash
go build -o mailcli ./cmd/mailcli
./mailcli parse --format json testdata/emails/invoice.eml
./mailcli triage message testdata/emails/invoice.eml
./mailcli sync --config examples/config/fixtures-dir.yaml --account fixtures --index /tmp/mailcli-fixtures-index.db --limit 0
./mailcli threads --index /tmp/mailcli-fixtures-index.db invoice
```

Those commands show the read and local-index side. The full MailCLI boundary also covers safe outbound work:

```mermaid
flowchart LR
  A["Existing mailbox or .eml"] --> B["MailCLI"]
  B --> C["StandardMessage / Triage Evidence"]
  C --> D["Local Index / Thread Context"]
  D --> E["Agent or Automation"]
  E --> F["Draft / Intent"]
  F --> G["Confirm / Operation Log"]
```

For a full local round trip, see [Local Thread Demo](docs/en/examples/local-thread-demo.md). For fixed outbound JSON and MIME pairs, see [Outbound Draft Patterns](docs/en/examples/outbound-draft-patterns.md).

## Install

macOS / Linux:

```bash
curl -fsSL https://raw.githubusercontent.com/nonozone/MailCli/main/install.sh | sh
```

Windows PowerShell:

```powershell
irm https://raw.githubusercontent.com/nonozone/MailCli/main/install.ps1 | iex
```

The installer detects your OS and CPU architecture, downloads the matching
GitHub Release asset, verifies `checksums.txt` when available, installs the
`mailcli` binary, and runs:

```bash
mailcli agent doctor
```

`agent doctor` detects local agent CLIs such as Codex and Claude Code and prints
the MCP registration commands for `mailcli mcp serve`.

To install and register MailCLI with detected agents in one step:

```bash
curl -fsSL https://raw.githubusercontent.com/nonozone/MailCli/main/install.sh | sh -s -- --auto-configure
```

Windows:

```powershell
$env:MAILCLI_AGENT_AUTO_CONFIGURE = "1"
irm https://raw.githubusercontent.com/nonozone/MailCli/main/install.ps1 | iex
```

If you are maintaining the repository itself, the local demo artifacts now have a standard check entrypoint:

```bash
make demo-local-thread-check
```

## Project Status

MailCLI has a published **v0.2.0** release with one-command installation and MCP agent setup. The current `main` branch adds existing-mailbox onboarding work.

Working today:

- parse local `.eml` input or stdin into `StandardMessage`
- add existing mailbox accounts with provider presets for Gmail, Outlook / Microsoft 365, QQ Mail, 163 Mail, and generic IMAP
- list messages from configured IMAP accounts (with `--since`/`--before` date filters)
- fetch and parse messages by sequence number, UID, or `Message-ID`
- sync recent messages into a local searchable index (BulkFetcher, BulkUpsert single-transaction, error isolation)
- search a local message index with FTS5 full-text search and field-weighted ranking
- inspect local conversation/thread summaries from indexed messages
- compile outbound drafts and replies (RFC 2047 encoded headers)
- send through SMTP-backed IMAP-style accounts (returns `message_id`)
- prepare and confirm send/reply intents with local operation logs for agent-safe outbound workflows
- delete, move, mark-read/unread on remote mailboxes
- export the local index as JSONL, JSON, or CSV
- **watch** one or more mailboxes with IMAP IDLE push (streaming JSONL event feed, persistent seen state across restarts)
- create, inspect, diagnose, test, and inspect account capabilities with `mailcli config init` / `mailcli config show` / `mailcli config doctor` / `mailcli config test` / `mailcli config capabilities`
- start an experimental local-only Mail Center with `mailcli web` for account
  status, sync, unified indexed inbox, message/thread reading, and operation
  queue inspection
- integrate with Go, shell, and external agent workflows through stable JSON contracts
- LLM tool-use schemas for OpenAI and Anthropic (`tools/` directory)

Stable enough to build against in current `main`:

- `mailcli parse`
- `mailcli list`
- `mailcli get`
- `mailcli sync`
- `mailcli search`
- `mailcli threads`
- `mailcli thread`
- `mailcli triage message|thread`
- `mailcli send`
- `mailcli send prepare|confirm`
- `mailcli reply`
- `mailcli reply prepare|confirm`
- `mailcli delete`
- `mailcli move`
- `mailcli mark`
- `mailcli operations list|show`
- `mailcli export`
- `mailcli watch`
- `mailcli account add`
- `mailcli config init|show|doctor|test|capabilities`
- `StandardMessage`
- `TriageRecord` / `TriageEnrichment`
- `DraftMessage`
- `ReplyDraft`
- `SendResult` (now includes `message_id`)
- `OperationIntentResult`
- `OperationLogEntry`
- `OperationResult` (delete / move / mark)

Still evolving:

- HTML cleanup and URL normalization heuristics
- richer list/search semantics for inbox workflows
- richer outbound HTML rendering and attachment ergonomics
- broader provider coverage and extension guidance
- local Web panel reply flows, native forwarding, and attachment download
  ergonomics

### Experimental local Web panel

`mailcli web` starts a temporary browser control panel bound to `127.0.0.1`.
It prints a per-run tokenized URL and serves embedded static assets from the
same Go binary:

```bash
mailcli web --config ~/.config/mailcli/config.yaml --index ~/.local/state/mailcli/index.db
```

By default it uses `127.0.0.1:5566`. Pass `--port 0` if you want a random
available local port.

For fixture-only local testing:

```bash
mailcli web --config examples/config/fixtures-dir.yaml --index /tmp/mailcli-web.db --no-open
```

The v1 Web panel is local-only. It does not expose a LAN/public server, does not
store secrets in the browser, and does not give AI automatic send/delete/move
authority.

Current built-in driver types:

- `imap` for real mailbox access
- `dir` for local `.eml` directories and zero-network agent workflows
- `stub` for local development, tests, and driver-extension examples

Current parser fixture coverage now includes:

- plaintext mail
- newsletter/promo mail
- subscription/unsubscribe mail
- delivery failure mail
- postfix-style DSN / bounce mail
- verification mail
- multilingual verification mail with full-width digits
- quoted-reply verification mail
- invoice/payment mail
- security reset mail
- security reset mail with corporate safe-link wrappers
- attachment-entry mail
- multipart/related inline-image mail

Heuristic areas to treat as evolving:

- action extraction coverage and classification
- verification-code extraction beyond common OTP layouts
- HTML body selection and cleanup for unusual templates
- token estimates

Detailed next-step planning:

- [Next Development Roadmap](docs/en/project/next-roadmap.md)

## Vision

In the AI era, email should not be treated as a pile of HTML and transport headers.

It should behave like a structured API resource.

MailCLI exists to make email as easy for agents to consume and produce as a JSON document.

## Key Features

- **AI-first parser**
  Convert noisy raw email into normalized JSON and Markdown suitable for agent reasoning.
- **Protocol/content separation**
  Drivers handle transport, parsers handle content, composers handle outbound MIME.
- **Action extraction**
  Extract unsubscribe links, security entry points, verification codes, invoice/payment entry points, attachment entry points, inbound MIME attachment metadata, bounce/error context, and thread-related metadata.
  Verification-code extraction is conservative but now handles common multilingual and next-line layouts, and can expose `expires_in_seconds` when the mail states a relative expiry.
- **Developer-friendly CLI**
  Support `json`, `yaml`, and `table` output formats, stdin pipelines, and scriptable commands.
- **Bidirectional workflow**
  Read mail with `list/get/parse`, then produce `DraftMessage` and `ReplyDraft` flows for outbound delivery.
- **Provider-agnostic architecture**
  Designed to support IMAP, SMTP, APIs, and future ecosystem integrations without redefining the core model.

## Why MailCLI Exists

Raw email is a poor interface for agents:

- MIME trees are noisy
- HTML templates are token-expensive
- reply threading is easy to break
- provider APIs differ too much

MailCLI solves that by providing a stable boundary:

- inbound email becomes `StandardMessage`
- machine-usable artifacts such as actions, codes, inbound attachment metadata, and bounce context are extracted
- outbound intent becomes `DraftMessage` or `ReplyDraft`
- transport stays behind drivers

## Current Capabilities

### Read path

- `mailcli parse --format json|yaml|table `
- `mailcli list [--account] [--mailbox] [--limit] [--since] [--before] [--format json|table]`
- `mailcli get [--account] [--mailbox] `
- `mailcli sync [--account] [--mailbox] [--limit] [--since] [--before] [--refresh] [--index]`
- `mailcli search [--index] [--account] [--mailbox] [--since] [--before] [--thread] [--limit] [--full] `
- `mailcli threads [query] [--index] [--account] [--mailbox] [--since] [--before] [--category] [--action] [--has-codes] [--limit]`
- `mailcli thread  [--index] [--account] [--mailbox] [--limit]`
- `mailcli triage message [--enrichment ] `
- `mailcli triage thread [--index] [--account] [--mailbox] [--enrichment ] `
- `mailcli export [query] [--index] [--account] [--mailbox] [--since] [--before] [--format jsonl|json|csv] [--output] [--limit]`

### Write path

- `mailcli send [--account] [--dry-run] ` for direct send or MIME preview
- `mailcli send prepare [--account] [--operations] ` for agent-safe outbound intent creation
- `mailcli send confirm [--account] [--operations] ` to execute a prepared send intent
- `mailcli reply [--account] [--dry-run] ` for direct reply or MIME preview
- `mailcli reply prepare [--account] [--operations] ` for agent-safe reply intent creation
- `mailcli reply confirm [--account] [--operations] ` to execute a prepared reply intent
- `mailcli operations list [--operations]`
- `mailcli operations show [--operations] `
- `mailcli delete [--account] [--mailbox] `
- `mailcli move [--account] [--mailbox]  `
- `mailcli mark [--account] [--mailbox] [--unread] `

### Watch (streaming events)

- `mailcli watch [--account] [--mailbox ...] [--poll 30s] [--since] [--auto-sync] [--index] [--heartbeat 5m]`

  Streams JSONL events to stdout: `watching`, `new_message` (full `StandardMessage`), `heartbeat`, `error`.
  Uses IMAP IDLE when available; falls back to polling otherwise.

  When `--index` is provided, maintains a persistent **seen set** in SQLite so
  restarts never re-emit already-processed messages.

  ```bash
  # Pipe to AI agent with persistent deduplication:
  mailcli watch --account work --index ~/.config/mailcli/index.db \
    | go run ./examples/go/watch_reply_agent --from-address support@nono.im
  ```

### Config management

- `mailcli account add [--provider gmail|outlook|microsoft365|qq|163|generic-imap] [--email ]` — add an existing mailbox with provider defaults, human prompts, and environment-backed secret references
- `mailcli config init [--config] --account  --driver imap --host  --username  --password-env ` — create a starter config file that stores secret environment references such as `${MAILCLI_IMAP_PASSWORD}`, not raw passwords
- `mailcli config show [--config]` — print accounts (passwords redacted)
- `mailcli config doctor [--config]` — run local static diagnostics without connecting to IMAP or SMTP
- `mailcli config test [--config] [--account]` — test live connection
- `mailcli config capabilities [--config] [--account]` — print machine-readable account capabilities without connecting to the mailbox server

`account add`, `config init`, `config doctor`, and `config capabilities` are safe onboarding commands for agents and setup scripts. They do not print configured password values. `config doctor` distinguishes missing secret references from unset environment variables such as `imap_password_env_unset`. `config test` is the command that performs a live mailbox connection check.

Recommended human setup path:

```bash
mailcli account add
```

Recommended agent/script setup path:

```bash
mailcli account add \
  --provider gmail \
  --email you@gmail.com \
  --password-env MAILCLI_GMAIL_APP_PASSWORD \
  --format json
```

`account add` writes provider metadata and an `auth_method`, but it still stores
only secret references such as `${MAILCLI_GMAIL_APP_PASSWORD}`. Gmail, QQ Mail,
and 163 Mail presets use app passwords or authorization codes. Outlook and
Microsoft 365 presets are read-first because many accounts require OAuth or
tenant policy changes that MailCLI does not implement yet.

### Outbound Markdown baseline

- headings
- Markdown links rendered as clickable HTML anchors with readable plain-text fallbacks
- unordered lists as `ul/li`
- ordered lists as `ol/li`
- blockquotes
- simple Markdown tables

### Reply support

- `reply_to_message_id` is supported
- `reply_to_id` is supported
- when `reply_to_id` is used, MailCLI can fetch the original message and derive:
  - `In-Reply-To`
  - `References`
  - default reply subject
  - default reply recipient when `to` is omitted
- for non-dry-run outbound commands, MailCLI can also derive `from.address` from configured `smtp_username` or `username`

## Architecture

MailCLI follows a layered architecture so contributors can work on clear boundaries:

1. **Driver Layer**
   Fetch raw messages and send raw bytes.
2. **Parser Engine**
   Decode MIME, normalize charsets, clean HTML, convert to Markdown, and extract actions.
3. **Composer**
   Compile `DraftMessage` and `ReplyDraft` into standards-compliant outbound MIME.
4. **CLI Core**
   Handle account selection, command routing, output formatting, and workflow orchestration.

Core rule:

**proto

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [nonozone](https://github.com/nonozone)
- **Source:** [nonozone/MailCli](https://github.com/nonozone/MailCli)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-nonozone-mailcli
- Seller: https://agentstack.voostack.com/s/nonozone
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
