Skip to main content

MailPilot

English | 中文

纯 Python 命令行邮件客户端 —— 收、发、读、搜、标记 —— 内置邮件服务器,并提供完整的智能体(function-calling)API。

GPL-3.0-or-later 许可。零运行时依赖:SMTP、IMAP、POP3 客户端,asyncio 实现的 SMTP+POP3 服务器,SQLite 本地存储,MIME 解析,以及 NTLM 所需的 DES/MD4 等全部 SASL 认证,均基于 Python 标准库自行实现。

功能特性

  • 全部主流协议:SMTP(发送)、IMAP4(收取/搜索/标志/文件夹)、POP3(收取)——全面支持 SSL 与 STARTTLS。
  • 全部主流认证方式:SASL PLAIN、LOGIN、CRAM-MD5、XOAUTH2/OAUTHBEARER、NTLM(内置纯 Python DES + MD4),以及 POP3 的 APOP。auto 模式按服务器通告自动选择。
  • 服务商预设:gmail、outlook、qq、163、126、yahoo、icloud、zoho、aliyun、sina——一个参数填好全部服务器与端口。
  • 内置邮件服务器:没配服务器?mailpilot serve 即可启动本地 SMTP + POP3 服务器(asyncio、零系统依赖),支持按邮箱认证、CRAM-MD5/APOP,并带中继防护。
  • 本地 SQLite 存储:每封收取/发出的邮件都可离线搜索、标记、移动、删除。
  • MIME 处理完善:multipart/alternative、RFC 2047 中文头、附件(列出 + 保存)、HTML→纯文本兜底。
  • 智能体 API:每个操作都有对应的 OpenAI function-calling TOOLS schema + dispatch(),LLM 智能体能像人一样收发、搜索、标记邮件。

安装

要求 Python ≥ 3.10。运行时无任何第三方依赖,全部标准库。

# 推荐:直接装入现有 conda 环境(不需要 venv)
conda activate dev
pip install -e .[dev]        # [dev] 只额外装 pytest/ruff/mypy

只使用 CLI/API 的话,pip install -e . 即可。

数据与文件位置

所有运行时数据集中在一个目录:默认 ~/.mailpilot/。

文件 用途 权限
~/.mailpilot/config.json 账号凭据(邮箱、授权码/token、服务器地址、端口) 0600(保存时强制,仅属主可读写)
~/.mailpilot/mailpilot.db SQLite 存储:每封收取/发出的邮件——原始 RFC822 报文、解析后的头/正文、标志、附件 0600(首次运行后收紧)

目录解析优先级(从高到低):

  1. config.json 内的 data_dir 字段
  2. 环境变量 MAILPILOT_DATA_DIR
  3. 默认 ~/.mailpilot/

邮件数据库同时保存完整原始报文与解析后的字段(主题、发收件人、日期、标志、text/html 正文),因此可离线搜索,附件可随时重新提取。任何真实凭据或邮件内容都不会出现在代码、测试或文档中。

整体迁移(config + 邮件):

export MAILPILOT_DATA_DIR=/Volumes/SecureUSB/mailpilot

或在配置文件里设 "data_dir": "/path"。

配置账号(服务商预设)

mailpilot config add qq you@qq.com --password <SMTP授权码> --auth login --provider qq
mailpilot config test -a qq      # 探测 IMAP + POP3 + SMTP 认证

交互式 OAuth 登录(Gmail / Outlook)

Gmail、Outlook 这类 XOAUTH2 账号无需手动找 token,一条命令走浏览器授权:

# 一次性设置你的 OAuth client_id(桌面应用类型)
mailpilot config set-extra gmail-账号名 client_id <你的-client-id>

# 弹出浏览器登录,成功后 token 自动写回配置
mailpilot config login you@gmail.com --provider gmail
mailpilot config login -a 已有账号名          # 对已有账号重新授权

浏览器打开 Google/Microsoft 授权页 → 登录 → 本地回环端口自动接收跳转, access/refresh token 落盘 ~/.mailpilot/config.json(0600)。access token 过期会在下次使用时自动用 refresh token 续期。

收取、列览、阅读、搜索、标记

mailpilot fetch -a qq -n 20      # 拉取新邮件进本地库
mailpilot list --unread          # 按时间倒序
mailpilot search "关键词"
mailpilot read 42                # 头部 + 正文
mailpilot read 42 --save-attachments ./att
mailpilot mark 42 --flags seen,flagged
mailpilot folders

发送

mailpilot send -t bob@example.com -s "你好" -m "正文" \
    --attach ./report.pdf:report-2026.pdf

运行内置服务器

# 无认证模式,localhost,存入 ~/.mailpilot/mailpilot.db
mailpilot serve --smtp-port 2525 --pop-port 1110 --domain localhost

# 带认证的邮箱(--user 可重复)
mailpilot serve --user alice@localhost:secret1 --user bob@localhost:secret2

随后任何 SMTP/POP3 客户端都可连 127.0.0.1:2525 / 127.0.0.1:1110。本地域投递无需认证;向其他域中继需要认证,否则拒绝(550)。

脚本化 JSON 输出

所有命令都接受 --json,统一返回 {"success", "data", "error", "metadata"}:

mailpilot list --json --unread | jq '.data[0].subject'

智能体集成(OpenAI Function Calling)

from mailpilot.agent.tools import TOOLS, dispatch

# 1. 把 TOOLS 加进模型的工具列表。
# 2. 模型发起工具调用时路由:
result = dispatch("mailpilot_send", {
    "to": ["bob@example.com"],
    "subject": "智能体发来的问候",
    "body": "通过 mailpilot 工具调用发送。",
})
print(result)  # {"success": True, "data": {...}, "error": None, "metadata": {...}}

可用工具:mailpilot_send、mailpilot_list、mailpilot_read、mailpilot_search、mailpilot_mark、mailpilot_delete、mailpilot_move、mailpilot_fetch、mailpilot_folders、mailpilot_account_add、mailpilot_account_list、mailpilot_account_test。

查看 schema:mailpilot api --schema。

Python API

from mailpilot import ToolResult, send_mail, list_messages, read_message, search_messages, mark_messages

result = send_mail(to=["bob@example.com"], subject="Hi", body="Hello")
if result.success:
    print(result.data["message_id"])

所有 API 函数返回 ToolResult dataclass(success、data、error、metadata、.to_dict()、__bool__ 真值判断)。

配置

账号存于 ~/.mailpilot/config.json(0600)。完整布局与迁移方法见上文数据与文件位置。运行期覆盖:

  • MAILPILOT_DATA_DIR — 数据目录
  • mailpilot serve --db <path> — 内置服务器的自定义数据库路径

项目结构

mailpilot/
├── core/            # config(账号/预设)、errors(ToolResult)、
│                    # auth(PLAIN/LOGIN/CRAM-MD5/XOAUTH2/NTLM/APOP)、
│                    # _des + _md4(NTLM 所需纯 Python 密码学原语)
├── mail/            # smtp_client、imap_client、pop_client、
│                    # parser(MIME 构建/解析/渲染)、store(SQLite)
├── serve/           # 内置 asyncio SMTP + POP3 服务器
├── agent/           # OpenAI function-calling TOOLS + dispatch
└── cli/             # argparse CLI(config/send/fetch/list/read/search/…)
tests/               # pytest 套件,含客户端↔内置服务器端到端回环

开发

conda activate dev      # 用现有环境,无需 venv
pip install -e .[dev]
pytest                  # 59 个测试
ruff check . && ruff format .
mypy mailpilot

备注

  • QQ/163/126 邮箱使用"授权码"而非登录密码——通过 --password 传入。凭据只存于 ~/.mailpilot/config.json(0600),绝不落入代码、测试或文档。
  • XOAUTH2 token 可用 mailpilot config test -a acct --oauth2-token <token> 或 Account.oauth2_token 提供(Gmail/Outlook OAuth 流程)。
  • 内置服务器把投递的邮件存进同一个 SQLite 库,因此 mailpilot fetch --protocol pop3 可以对它完整回环——测试智能体时不必碰真实邮箱。
  • 开发直接使用 conda 环境(如 conda activate dev && pip install -e .[dev])——无需 virtualenv。

许可

GPL-3.0-or-later(见 LICENSE)。


MailPilot

English | 中文

Pure-Python command-line mail client — send, fetch, read, search, mark — with a built-in mail server and a full agent (function-calling) API.

GPL-3.0-or-later licensed. Zero runtime dependencies: everything (SMTP, IMAP, POP3 clients, an asyncio SMTP+POP3 server, SQLite storage, MIME parsing, SASL auth incl. DES/MD4 for NTLM) is built on the Python standard library.

Features

  • All mainstream protocols: SMTP (send), IMAP4 (fetch/search/flags/folders), POP3 (fetch) — SSL and STARTTLS everywhere.
  • All mainstream auth methods: SASL PLAIN, LOGIN, CRAM-MD5, XOAUTH2/OAUTHBEARER, NTLM (with a pure-Python DES + MD4), and POP3 APOP. auto mode tries what the server advertises.
  • Provider presets: gmail, outlook, qq, 163, 126, yahoo, icloud, zoho, aliyun, sina — one flag fills all host/port settings.
  • Built-in mail server: no server configured? Run mailpilot serve to start a local SMTP + POP3 server (asyncio, zero system dependencies) with optional per-mailbox auth, CRAM-MD5/APOP support and relay protection.
  • Local SQLite store: every fetched/sent message is searchable, flaggable, movable, deletable — offline.
  • MIME done right: multipart/alternative, RFC 2047 CJK headers, attachments (list + save), HTML→text fallback.
  • Agent API: an OpenAI function-calling TOOLS schema + dispatch() for every operation, so an LLM agent can read/write/search/mark mail exactly like a human user.

Installation

Requires Python ≥ 3.10. No runtime dependencies — everything is standard library.

# Recommended: install into your existing conda env (no venv needed)
conda activate dev
pip install -e .[dev]        # [dev] adds pytest/ruff/mypy only

pip install -e . alone is enough for CLI/API usage.

Data & file locations

All runtime data lives in one directory: ~/.mailpilot/ by default.

File Purpose Permissions
~/.mailpilot/config.json Account credentials (email, auth code/token, server hosts, ports) 0600 (owner-only, enforced on save)
~/.mailpilot/mailpilot.db SQLite store: every fetched/sent message — raw RFC822 source, parsed headers/body, flags, attachments 0600 (tightened after first run)

Location resolution order (highest first):

  1. data_dir field inside config.json
  2. Environment variable MAILPILOT_DATA_DIR
  3. Default ~/.mailpilot/

The mail database stores the full raw message plus parsed fields (subject, from/to, date, flags, text/html bodies), so searches work offline and attachments can be re-extracted any time. No message content is kept anywhere else — no code, no tests, no README ever contain real credentials or message data.

To move everything (config + mail) elsewhere:

export MAILPILOT_DATA_DIR=/Volumes/SecureUSB/mailpilot

Or set "data_dir": "/path" in the config file.

Configure an account (provider preset)

Configure an account (provider preset)

mailpilot config add qq you@qq.com --password <SMTP-auth-code> --auth login --provider qq
mailpilot config test -a qq        # probes IMAP + POP3 + SMTP auth

Interactive OAuth login (Gmail / Outlook)

XOAUTH2 accounts (Gmail, Outlook) need no manual token hunting — one command runs the browser consent flow:

# One-time: set your OAuth client_id (Desktop app type)
mailpilot config set-extra <account-name> client_id <your-client-id>

# Opens the browser; tokens are saved back into config.json
mailpilot config login you@gmail.com
mailpilot config login -a <existing-account>   # re-authorize an account

The provider's consent page opens in your default browser; a temporary local loopback port catches the redirect, then access/refresh tokens are persisted to ~/.mailpilot/config.json (0600). An expired access token is refreshed automatically with the stored refresh token on next use.

Fetch, list, read, search, mark

mailpilot fetch -a qq -n 20   # same as before        # pull new mail into local store
mailpilot list --unread            # newest first
mailpilot search "Foxmail"
mailpilot read 42                  # headers + body
mailpilot read 42 --save-attachments ./att
mailpilot mark 42 --flags seen,flagged
mailpilot folders

Send

mailpilot send -t bob@example.com -s "Hello" -m "Body text" \
    --attach ./report.pdf:report-2026.pdf

Run the built-in server

# Open (no auth) on localhost, storing into ~/.mailpilot/mailpilot.db
mailpilot serve --smtp-port 2525 --pop-port 1110 --domain localhost

# Auth-protected mailboxes (repeat --user)
mailpilot serve --user alice@localhost:secret1 --user bob@localhost:secret2

Then point any SMTP/POP3 client at 127.0.0.1:2525 / 127.0.0.1:1110. Local-domain delivery is accepted without auth; relaying to other domains requires authentication and is otherwise denied (550).

JSON output for scripting

Every command accepts --json and returns {"success", "data", "error", "metadata"}:

mailpilot list --json --unread | jq '.data[0].subject'

Agent Integration (OpenAI Function Calling)

from mailpilot.agent.tools import TOOLS, dispatch

# 1. Pass TOOLS to your model's tool list.
# 2. When the model calls a tool, route it:
result = dispatch("mailpilot_send", {
    "to": ["bob@example.com"],
    "subject": "Hi from the agent",
    "body": "Sent via mailpilot tool call.",
})
print(result)  # {"success": True, "data": {...}, "error": None, "metadata": {...}}

Available tools: mailpilot_send, mailpilot_list, mailpilot_read, mailpilot_search, mailpilot_mark, mailpilot_delete, mailpilot_move, mailpilot_fetch, mailpilot_folders, mailpilot_account_add, mailpilot_account_list, mailpilot_account_test.

Inspect the schema yourself: mailpilot api --schema.

Python API

from mailpilot import ToolResult, send_mail, list_messages, read_message, search_messages, mark_messages

result = send_mail(to=["bob@example.com"], subject="Hi", body="Hello")
if result.success:
    print(result.data["message_id"])

All API functions return a ToolResult dataclass (success, data, error, metadata, .to_dict(), truthiness via __bool__).

Configuration

Accounts live in ~/.mailpilot/config.json (0600). See Data & file locations above for the full layout and how to relocate it. Per-run overrides:

  • MAILPILOT_DATA_DIR — data directory
  • mailpilot serve --db <path> — custom database path for the built-in server

Project structure

mailpilot/
├── core/            # config (accounts/presets), errors (ToolResult),
│                    # auth (SASL PLAIN/LOGIN/CRAM-MD5/XOAUTH2/NTLM/APOP),
│                    # _des + _md4 (pure-Python crypto primitives for NTLM)
├── mail/            # smtp_client, imap_client, pop_client,
│                    # parser (MIME build/parse/render), store (SQLite)
├── serve/           # built-in asyncio SMTP + POP3 server
├── agent/           # OpenAI function-calling TOOLS + dispatch
└── cli/             # argparse CLI (config/send/fetch/list/read/search/…)
tests/               # pytest suite incl. end-to-end client↔built-in-server loops

Development

conda activate dev      # your existing env; no venv needed
pip install -e .[dev]
pytest                  # 59 tests
ruff check . && ruff format .
mypy mailpilot

Notes

  • QQ/163/126 mailboxes use "authorization codes" (授权码) instead of the account password — pass it via --password. Credentials are stored only in ~/.mailpilot/config.json (0600); they never appear in code, tests, or docs.
  • XOAUTH2 tokens can be supplied with mailpilot config test -a acct --oauth2-token <token> or Account.oauth2_token for Gmail/Outlook OAuth flows.
  • The built-in server stores delivered mail in the same SQLite store, so mailpilot fetch --protocol pop3 round-trips against it — useful for testing agents without touching a real mailbox.
  • Development uses a conda env directly (e.g. conda activate dev && pip install -e .[dev]) — no virtualenv required.

License

GPL-3.0-or-later (see LICENSE).

Release files for cycleuser-mailpilot 0.0.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cycleuser-mailpilot 0.0.4
File Size Uploaded
cycleuser_mailpilot-0.0.4.tar.gz 69.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cycleuser-mailpilot 0.0.4
File Interpreter ABI Platform
cycleuser_mailpilot-0.0.4-py3-none-any.whl Python 3 none any Details

Total release size: 137.1 kB

Release files / cycleuser_mailpilot-0.0.4.tar.gz

Download URL cycleuser_mailpilot-0.0.4.tar.gz
Size 69.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c0cc1e23efdce14f24bd327f0dee01180a85e6d2923d664e9af87f582b8c85b5
BLAKE2b-256 checksum
How to use checksums
24612a37c1268c0d02de31e5f094599fa1883c3fa82f6612e4700bcdd5f4a85b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release files / cycleuser_mailpilot-0.0.4-py3-none-any.whl

Download URL cycleuser_mailpilot-0.0.4-py3-none-any.whl
Size 67.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c50c0dd1d5a4490178b5a5637221fe1a6d99a70c8042abe04b53445cf0eca69d
BLAKE2b-256 checksum
How to use checksums
98f5074962554838ad0301f6ebf71df5a06f9492b101874501673923756a0bca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release history Release notifications | RSS feed

This release

0.0.4 This release

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page