# mail-mcp Rust MCP server for Sulkta-hosted email. SMTP send + IMAP read with RFC-correct headers, multipart/alternative when HTML is included, multipart/mixed for attachments, threading via `In-Reply-To`/`References`. Replaces the `scripts/kayos_mail.py` CLI path that lived in `kayos/openclaw-workspace` since 2026-04-23. ## Why a server, not a CLI `kayos_mail.py` shipped without `Date` or `Message-ID` headers until a 2026-05-18 patch — exactly the kind of header-discipline regression a typed Rust server prevents at compile time. The "no spam bin" framing is mostly upstream of any client (Rackham postfix + rspamd DKIM-sign at the relay; mail-tester scored 10/10 and port25 SpamAssassin −7.31 on 2026-05-20), but a correct client doesn't trip filters with bad MIME structure, broken threading, or missing headers. ## Tools (v0.1) - `mail_send` — send mail. Args: `account?`, `to`, `cc[]?`, `bcc[]?`, `subject`, `body`, `body_html?`, `attachments[]?`, `in_reply_to?`, `references[]?`. Returns `{message_id, sent_at}`. - `mail_inbox_list` — list folder messages newest-first. Args: `account?`, `since?` (YYYY-MM-DD), `unread_only?`, `limit?` (default 50, max 500), `folder?` (default INBOX). Uses `BODY.PEEK` so it does not toggle `\Seen`. - `mail_inbox_read` — fetch one message by UID. Args: `account?`, `uid`, `folder?`, `format?` (`text`|`html`|`raw_eml`). Attachment payloads are not inlined — only filename/mime_type/size metadata. ## Headers we guarantee on outbound - `Date` — UTC, RFC 5322 (lettre auto) - `Message-ID` — `>` — own-domain, never the container hostname - `From` — `name ` - `MIME-Version: 1.0` - `User-Agent: mail-mcp/` - `In-Reply-To` + `References` when threading args present - `Content-Type` correct for the body shape (text-only / alternative / mixed) DKIM-Signature is applied by the relay (rspamd on Rackham), not the client. ## Build ```bash cargo build --release ``` Binary lands at `target/release/mail-mcp`. ## Config ```bash mkdir -p ~/.config/mail-mcp cp config.example.toml ~/.config/mail-mcp/config.toml chmod 600 ~/.config/mail-mcp/config.toml ``` Edit accounts as needed. Passwords are NEVER inline: 1. Looked up from the env var named in `password_env` 2. Falling back to `password_file` (shell-format: `KEY=VALUE` per line) 3. Hard-failing with a vault-pointer hint if neither resolves Vault canonical: `bw.sulkta.com` → `kayos@sulkta.com — IMAP/SMTP`. ## MCP wiring (Claude Code / kayos-house) ```json { "mcpServers": { "mail-mcp": { "command": "/usr/local/bin/mail-mcp", "args": [] } } } ``` Logging is stderr-only — stdout is the JSON-RPC transport. ## Future phases - **Phase B** (~200 LOC): multi-account routing across all configured `[accounts.*]`, plus `mail_thread` and `mail_search`. - **Phase C** (~150 LOC): `mail_mark` (read/unread/flag/trash/archive), `mail_attachment_get`, `mail_reply` helper. Full locked spec: `kayos/openclaw-workspace` → `memory/spec-mail-mcp.md`.