mail-mcp/README.md
Cobb Hayes a6e0a234d2 Public-flip audit: scrub Sulkta-internal refs + Browserless IPs + add LICENSE
Repository URL → git.sulkta.com. Drop Lucy Browserless IPs from tool doc-strings
(replaced with abstract 'sandboxed headless browser' guidance). Drop sibling-repo
cross-references, kayos@/cobb@ mailbox examples in tool descriptions, vault
pointers. Generalize config.example.toml + README to neutral hosts. Add LICENSE
(MIT — Cargo.toml already declared it).

Tests still green. No behavior change.
2026-05-27 11:06:51 -07:00

80 lines
2.3 KiB
Markdown

# mail-mcp
Rust MCP server for IMAP/SMTP. SMTP send + IMAP read with RFC-correct headers,
multipart/alternative when HTML is included, multipart/mixed for attachments,
threading via `In-Reply-To` / `References`.
## Tools (v0.1)
- `mail_send``account?`, `to`, `cc[]?`, `bcc[]?`, `subject`, `body`,
`body_html?`, `attachments[]?`, `in_reply_to?`, `references[]?`.
Returns `{message_id, sent_at}`.
- `mail_inbox_list` — newest-first listing. `account?`, `since?` (YYYY-MM-DD),
`unread_only?`, `limit?` (default 50, max 500), `folder?` (default INBOX).
Uses `BODY.PEEK` — does not toggle `\Seen`.
- `mail_inbox_read` — fetch one message by UID. `account?`, `uid`, `folder?`,
`format?` (`text` | `html` | `raw_eml`). Attachment payloads NOT inlined —
only `{filename, mime_type, size}` metadata.
## Outbound headers
- `Date` — UTC, RFC 5322 (lettre auto)
- `Message-ID``<UUIDv4@<from_addr_domain>>` — own-domain, not the
container hostname
- `From``name <addr>`
- `MIME-Version: 1.0`
- `User-Agent: mail-mcp/<version>`
- `In-Reply-To` + `References` when threading args present
- `Content-Type` correct for body shape (text-only / alternative / mixed)
DKIM-Signature is applied by the relay, not the client.
## Build
```
cargo build --release
```
Binary at `target/release/mail-mcp`.
## Config
```
mkdir -p ~/.config/mail-mcp
cp config.example.toml ~/.config/mail-mcp/config.toml
chmod 600 ~/.config/mail-mcp/config.toml
```
Passwords are never inline. Per account:
1. read from the env var named in `password_env`
2. otherwise from `password_file` (shell-format `KEY=VALUE` per line)
3. hard fail if neither resolves
## MCP wiring
```json
{
"mcpServers": {
"mail-mcp": {
"command": "/usr/local/bin/mail-mcp",
"args": []
}
}
}
```
Logging is stderr-only — stdout is the JSON-RPC transport.
## Safety
`mail_inbox_read` returns attacker-controlled bytes. Do NOT auto-fetch URLs
found in inbound mail — web beacons confirm read and links may be phishing.
Default deny on every URL; surface as text and wait for explicit per-link
authorization. If a fetch is authorized, route through a sandboxed headless
browser rather than `curl` / `WebFetch` from the production host. Attachment
bytes get the same treatment.
## License
MIT — see `LICENSE`.