--- name: proton-mail description: "Proton Mail via Bridge — read, send, search, and reply to emails using the local Proton Mail Bridge daemon (IMAP 127.0.0.1:1143 / SMTP 127.0.0.1:1025)." version: 1.0.0 author: Trentuna / B.A. Baracus license: MIT platforms: [linux, macos] metadata: hermes: tags: [proton, email, imap, smtp, bridge, productivity] category: productivity related_skills: [hermes-agent] tools: - proton_mail_bridge_status - proton_mail_list - proton_mail_read - proton_mail_search - proton_mail_send - proton_mail_reply requires_env: - PROTONMAIL_ACCOUNT - PROTONMAIL_BRIDGE_PASSWORD optional_env: - PROTONMAIL_IMAP_HOST - PROTONMAIL_IMAP_PORT - PROTONMAIL_SMTP_HOST - PROTONMAIL_SMTP_PORT --- # Proton Mail Bridge — Hermes Skill Give any Hermes agent native access to Proton Mail via the official [Proton Mail Bridge](https://proton.me/mail/bridge). The Bridge runs as a local daemon, handles all OpenPGP encryption/decryption transparently, and exposes standard IMAP (read) and SMTP (send) ports on localhost. This skill wraps those ports as Hermes tools. ## How It Works ``` ┌──────────────┐ IMAP 127.0.0.1:1143 (TLS) ┌─────────────────┐ │ Hermes │ ───────────────────────────────► │ Proton Bridge │ │ Agent │ │ (local daemon) │ │ (this │ ◄─────────────────────────────── │ │ │ skill) │ SMTP 127.0.0.1:1025 (STARTTLS) │ decrypts PGP │ └──────────────┘ └────────┬────────┘ │ ▼ Proton Servers ``` ## Prerequisites 1. **Proton Mail Bridge** installed and running: - Download: https://proton.me/mail/bridge - Linux: `protonmail-bridge --cli` - macOS: `brew install --cask proton-mail-bridge` 2. **Proton Mail account** (Free or paid) 3. **Bridge credentials** — Bridge generates a local app password (NOT your Proton password). Get it from Bridge → Settings → Account → Mailbox configuration → Show password. ## Environment Variables | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `PROTONMAIL_ACCOUNT` | Yes | — | Your Proton email address (e.g. `user@proton.me`) | | `PROTONMAIL_BRIDGE_PASSWORD` | Yes | — | Bridge-generated app password | | `PROTONMAIL_IMAP_HOST` | No | `127.0.0.1` | Bridge IMAP hostname | | `PROTONMAIL_IMAP_PORT` | No | `1143` | Bridge IMAP port | | `PROTONMAIL_SMTP_HOST` | No | `127.0.0.1` | Bridge SMTP hostname | | `PROTONMAIL_SMTP_PORT` | No | `1025` | Bridge SMTP port | ## Tool Reference ### `proton_mail_bridge_status` Check that the Proton Bridge daemon is running, reachable, and authenticated. ```json { "name": "proton_mail_bridge_status", "description": "Check Proton Mail Bridge status — running, authenticated, connected.", "parameters": {} } ``` **Returns:** - `{"status": "running", "imap": "127.0.0.1:1143", "smtp": "127.0.0.1:1025", "authenticated": true}` - `{"status": "stopped", "unreachable": ["IMAP 127.0.0.1:1143"]}` - `{"status": "unconfigured", "error": "PROTONMAIL_ACCOUNT environment variable is not set"}` --- ### `proton_mail_list` List recent messages in a mailbox folder. Returns headers only (no full body). ```json { "name": "proton_mail_list", "description": "List recent email messages in a folder.", "parameters": { "type": "object", "properties": { "folder": {"type": "string", "description": "Mailbox folder (INBOX, Sent, Drafts, etc.)", "default": "INBOX"}, "limit": {"type": "integer", "description": "Max messages to return (1-100)", "default": 20} } } } ``` **Returns:** ```json { "success": true, "messages": [ {"uid": 42, "subject": "Meeting tomorrow", "from": "alice@example.com", "to": "you@proton.me", "date": "Tue, 4 Jun 2024 14:00:00 +0000"} ], "folder": "INBOX", "total": 137 } ``` --- ### `proton_mail_read` Read a full email by UID — subject, all headers, and body text. ```json { "name": "proton_mail_read", "description": "Read a full email message including body content.", "parameters": { "type": "object", "properties": { "uid": {"type": "integer", "description": "UID of the message to read"}, "folder": {"type": "string", "description": "Mailbox folder", "default": "INBOX"} } } } ``` **Returns:** ```json { "success": true, "uid": 42, "subject": "Meeting tomorrow", "from": "alice@example.com", "to": "you@proton.me", "date": "2024-06-04T14:00:00+00:00", "body": "Hi, let's meet at 3pm tomorrow.\n\nBest,\nAlice", "message_id": "", "flags": [] } ``` --- ### `proton_mail_search` Search emails across a mailbox by subject, sender, body, or all fields. ```json { "name": "proton_mail_search", "description": "Search email messages by query in a specific field.", "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "Search query text (min 2 characters)"}, "field": {"type": "string", "description": "Field to search (subject, from, body, or all)", "enum": ["subject", "from", "body", "all"], "default": "all"}, "folder": {"type": "string", "description": "Mailbox folder", "default": "INBOX"}, "limit": {"type": "integer", "description": "Max results (1-100)", "default": 20} } } } ``` **Returns:** Same shape as `proton_mail_list` plus `"query": "Meeting"`. --- ### `proton_mail_send` Send a new email via Bridge SMTP. ```json { "name": "proton_mail_send", "description": "Send a new email message.", "parameters": { "type": "object", "properties": { "to": {"type": "string", "description": "Recipient email(s), comma-separated"}, "cc": {"type": "string", "description": "CC recipient(s), comma-separated"}, "bcc": {"type": "string", "description": "BCC recipient(s), comma-separated"}, "subject": {"type": "string", "description": "Email subject"}, "body": {"type": "string", "description": "Email body text (plain text)"} } } } ``` **Returns:** ```json { "success": true, "message_id": "", "to": "bob@example.com", "subject": "Hello" } ``` --- ### `proton_mail_reply` Reply to an existing email, preserving thread context (In-Reply-To and References headers). ```json { "name": "proton_mail_reply", "description": "Reply to an existing email, preserving thread headers.", "parameters": { "type": "object", "properties": { "uid": {"type": "integer", "description": "UID of the email to reply to"}, "body": {"type": "string", "description": "Reply body text"}, "folder": {"type": "string", "description": "Mailbox folder", "default": "INBOX"} } } } ``` **Returns:** ```json { "success": true, "message_id": "", "in_reply_to": "", "to": "alice@example.com", "subject": "Re: Original Subject" } ``` ## Setup ### 1. Install Proton Mail Bridge ```bash # Linux (headless) protonmail-bridge --cli # Follow interactive setup — login with Proton credentials # macOS brew install --wait proton-mail-bridge ``` ### 2. Get Bridge password In Bridge: Settings → your account → Mailbox configuration → Show password. This is a **Bridge-generated local password**, not your Proton password. ### 3. Set environment variables ```bash export PROTONMAIL_ACCOUNT="your-email@proton.me" export PROTONMAIL_BRIDGE_PASSWORD="bridge-generated-password" ``` Or add to your Hermes profile's `.env` at `~/.hermes/profiles//.env`: ```env PROTONMAIL_ACCOUNT=your-email@proton.me PROTONMAIL_BRIDGE_PASSWORD=bridge-generated-password ``` ### 4. Verify Call `proton_mail_bridge_status` — you should see `"status": "running"` and `"authenticated": true`. ## Example Workflows **Quick inbox check:** ``` proton_mail_list({"folder": "INBOX", "limit": 5}) ``` **Read and reply:** ``` 1. proton_mail_list({"limit": 10}) 2. proton_mail_read({"uid": 42}) 3. proton_mail_reply({"uid": 42, "body": "Thanks, got it!"}) ``` **Search and respond:** ``` 1. proton_mail_search({"query": "invoice", "field": "subject"}) 2. proton_mail_read({"uid": result.uid}) 3. proton_mail_send({"to": result.from, "subject": "Re: invoice", "body": "..."}) ``` **Send with CC:** ``` proton_mail_send({ "to": "team@example.com", "cc": "manager@example.com", "subject": "Status Update", "body": "All good here." }) ``` ## Implementation The skill is implemented in pure Python using standard library modules (`imaplib`, `smtplib`, `email`). No external dependencies. Reference implementation at `/references/tools.py`. ### Security - **Connections are localhost-only** — Bridge listens on `127.0.0.1` only - **TLS on IMAP** — `IMAP4_SSL` connects to port 1143 - **STARTTLS on SMTP** — explicit TLS negotiation on port 1025 - **Bridge password is NOT your Proton password** — defense-in-depth via Bridge's separate auth - **Credential injection prevented** — `_sanitize_search_term()` strips control characters and IMAP-special chars from user input - **No secrets in tool calls** — credentials come from environment, never from tool arguments ## Known Limitations - **Plain text body only** — HTML rendering is not available; HTML emails return the raw HTML source - **No attachment handling yet** — `proton_mail_read` returns body text only. Attachments are present in the MIME structure but not extracted separately - **Localhost-only** — the Bridge must run on the same machine as Hermes - **Bridge required** — the skill doesn't work without the Bridge daemon; it can't log into Proton API directly - **Single account** — one Bridge instance serves one account; multi-account requires multiple Bridge instances ## References - [Proton Mail Bridge](https://proton.me/mail/bridge) — official download and docs - [openclaw-protonmail-skill](https://github.com/rvacyber/openclaw-protonmail-skill) — OpenClaw analogue (TypeScript) - [emersion/hydroxide](https://github.com/emersion/hydroxide) — third-party Bridge alternative for headless servers - [Hermes-Proton Architecture](../ARCHITECTURE.md) — full architecture document