From eac5f8f40f9ddb7b5eb158c84bbc91e376d10382 Mon Sep 17 00:00:00 2001 From: teknium1 Date: Wed, 11 Mar 2026 06:34:32 -0700 Subject: [PATCH] fix: wire email platform into toolset mappings + add documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-merge fixes for the email gateway (PR #797): 1. Add Platform.EMAIL to all 4 platform-to-toolset/config mapping dicts in gateway/run.py. Without this, email sessions silently fell back to the Telegram toolset because these dicts were added after the PR branched off main. 2. Add email (and signal) to hermes_cli/tools_config.py and hermes_cli/skills_config.py PLATFORMS dicts so they appear in 'hermes tools' and 'hermes skills' CLI commands. 3. Add full email setup documentation: - website/docs/user-guide/messaging/email.md β€” setup guide with Gmail/Outlook instructions, configuration, troubleshooting, security advice, and env var reference - Update messaging/index.md β€” add email to architecture diagram, platform toolset table, security examples, and next steps --- gateway/run.py | 4 + hermes_cli/skills_config.py | 2 + hermes_cli/tools_config.py | 2 + website/docs/user-guide/messaging/email.md | 176 +++++++++++++++++++++ website/docs/user-guide/messaging/index.md | 23 +-- 5 files changed, 197 insertions(+), 10 deletions(-) create mode 100644 website/docs/user-guide/messaging/email.md diff --git a/gateway/run.py b/gateway/run.py index d91215a6f..96d43672f 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -2023,6 +2023,7 @@ class GatewayRunner: Platform.SLACK: "hermes-slack", Platform.SIGNAL: "hermes-signal", Platform.HOMEASSISTANT: "hermes-homeassistant", + Platform.EMAIL: "hermes-email", } platform_toolsets_config = {} try: @@ -2043,6 +2044,7 @@ class GatewayRunner: Platform.SLACK: "slack", Platform.SIGNAL: "signal", Platform.HOMEASSISTANT: "homeassistant", + Platform.EMAIL: "email", }.get(source.platform, "telegram") config_toolsets = platform_toolsets_config.get(platform_config_key) @@ -2835,6 +2837,7 @@ class GatewayRunner: Platform.SLACK: "hermes-slack", Platform.SIGNAL: "hermes-signal", Platform.HOMEASSISTANT: "hermes-homeassistant", + Platform.EMAIL: "hermes-email", } # Try to load platform_toolsets from config @@ -2858,6 +2861,7 @@ class GatewayRunner: Platform.SLACK: "slack", Platform.SIGNAL: "signal", Platform.HOMEASSISTANT: "homeassistant", + Platform.EMAIL: "email", }.get(source.platform, "telegram") # Use config override if present (list of toolsets), otherwise hardcoded default diff --git a/hermes_cli/skills_config.py b/hermes_cli/skills_config.py index 56abed8ed..808b61762 100644 --- a/hermes_cli/skills_config.py +++ b/hermes_cli/skills_config.py @@ -22,6 +22,8 @@ PLATFORMS = { "discord": "πŸ’¬ Discord", "slack": "πŸ’Ό Slack", "whatsapp": "πŸ“± WhatsApp", + "signal": "πŸ“‘ Signal", + "email": "πŸ“§ Email", } # ─── Config Helpers ─────────────────────────────────────────────────────────── diff --git a/hermes_cli/tools_config.py b/hermes_cli/tools_config.py index 8b060016d..cb9b99657 100644 --- a/hermes_cli/tools_config.py +++ b/hermes_cli/tools_config.py @@ -108,6 +108,8 @@ PLATFORMS = { "discord": {"label": "πŸ’¬ Discord", "default_toolset": "hermes-discord"}, "slack": {"label": "πŸ’Ό Slack", "default_toolset": "hermes-slack"}, "whatsapp": {"label": "πŸ“± WhatsApp", "default_toolset": "hermes-whatsapp"}, + "signal": {"label": "πŸ“‘ Signal", "default_toolset": "hermes-signal"}, + "email": {"label": "πŸ“§ Email", "default_toolset": "hermes-email"}, } diff --git a/website/docs/user-guide/messaging/email.md b/website/docs/user-guide/messaging/email.md new file mode 100644 index 000000000..f6746290b --- /dev/null +++ b/website/docs/user-guide/messaging/email.md @@ -0,0 +1,176 @@ +--- +sidebar_position: 7 +title: "Email" +description: "Set up Hermes Agent as an email assistant via IMAP/SMTP" +--- + +# Email Setup + +Hermes can receive and reply to emails using standard IMAP and SMTP protocols. Send an email to the agent's address and it replies in-thread β€” no special client or bot API needed. Works with Gmail, Outlook, Yahoo, Fastmail, or any provider that supports IMAP/SMTP. + +:::info No External Dependencies +The Email adapter uses Python's built-in `imaplib`, `smtplib`, and `email` modules. No additional packages or external services are required. +::: + +--- + +## Prerequisites + +- **A dedicated email account** for your Hermes agent (don't use your personal email) +- **IMAP enabled** on the email account +- **An app password** if using Gmail or another provider with 2FA + +### Gmail Setup + +1. Enable 2-Factor Authentication on your Google Account +2. Go to [App Passwords](https://myaccount.google.com/apppasswords) +3. Create a new App Password (select "Mail" or "Other") +4. Copy the 16-character password β€” you'll use this instead of your regular password + +### Outlook / Microsoft 365 + +1. Go to [Security Settings](https://account.microsoft.com/security) +2. Enable 2FA if not already active +3. Create an App Password under "Additional security options" +4. IMAP host: `outlook.office365.com`, SMTP host: `smtp.office365.com` + +### Other Providers + +Most email providers support IMAP/SMTP. Check your provider's documentation for: +- IMAP host and port (usually port 993 with SSL) +- SMTP host and port (usually port 587 with STARTTLS) +- Whether app passwords are required + +--- + +## Step 1: Configure Hermes + +The easiest way: + +```bash +hermes gateway setup +``` + +Select **Email** from the platform menu. The wizard prompts for your email address, password, IMAP/SMTP hosts, and allowed senders. + +### Manual Configuration + +Add to `~/.hermes/.env`: + +```bash +# Required +EMAIL_ADDRESS=hermes@gmail.com +EMAIL_PASSWORD=abcd efgh ijkl mnop # App password (not your regular password) +EMAIL_IMAP_HOST=imap.gmail.com +EMAIL_SMTP_HOST=smtp.gmail.com + +# Security (recommended) +EMAIL_ALLOWED_USERS=your@email.com,colleague@work.com + +# Optional +EMAIL_IMAP_PORT=993 # Default: 993 (IMAP SSL) +EMAIL_SMTP_PORT=587 # Default: 587 (SMTP STARTTLS) +EMAIL_POLL_INTERVAL=15 # Seconds between inbox checks (default: 15) +EMAIL_HOME_ADDRESS=your@email.com # Default delivery target for cron jobs +``` + +--- + +## Step 2: Start the Gateway + +```bash +hermes gateway # Run in foreground +hermes gateway install # Install as a system service +``` + +On startup, the adapter: +1. Tests IMAP and SMTP connections +2. Marks all existing inbox messages as "seen" (only processes new emails) +3. Starts polling for new messages + +--- + +## How It Works + +### Receiving Messages + +The adapter polls the IMAP inbox for UNSEEN messages at a configurable interval (default: 15 seconds). For each new email: + +- **Subject line** is included as context (e.g., `[Subject: Deploy to production]`) +- **Reply emails** (subject starting with `Re:`) skip the subject prefix β€” the thread context is already established +- **Attachments** are cached locally: + - Images (JPEG, PNG, GIF, WebP) β†’ available to the vision tool + - Documents (PDF, ZIP, etc.) β†’ available for file access +- **HTML-only emails** have tags stripped for plain text extraction +- **Self-messages** are filtered out to prevent reply loops + +### Sending Replies + +Replies are sent via SMTP with proper email threading: + +- **In-Reply-To** and **References** headers maintain the thread +- **Subject line** preserved with `Re:` prefix (no double `Re: Re:`) +- **Message-ID** generated with the agent's domain +- Responses are sent as plain text (UTF-8) + +### File Attachments + +The agent can send file attachments in replies. Include `MEDIA:/path/to/file` in the response and the file is attached to the outgoing email. + +--- + +## Access Control + +Email access follows the same pattern as all other Hermes platforms: + +1. **`EMAIL_ALLOWED_USERS` set** β†’ only emails from those addresses are processed +2. **No allowlist set** β†’ unknown senders get a pairing code +3. **`EMAIL_ALLOW_ALL_USERS=true`** β†’ any sender is accepted (use with caution) + +:::warning +**Always configure `EMAIL_ALLOWED_USERS`.** Without it, anyone who knows the agent's email address could send commands. The agent has terminal access by default. +::: + +--- + +## Troubleshooting + +| Problem | Solution | +|---------|----------| +| **"IMAP connection failed"** at startup | Verify `EMAIL_IMAP_HOST` and `EMAIL_IMAP_PORT`. Ensure IMAP is enabled on the account. For Gmail, enable it in Settings β†’ Forwarding and POP/IMAP. | +| **"SMTP connection failed"** at startup | Verify `EMAIL_SMTP_HOST` and `EMAIL_SMTP_PORT`. Check that your password is correct (use App Password for Gmail). | +| **Messages not received** | Check `EMAIL_ALLOWED_USERS` includes the sender's email. Check spam folder β€” some providers flag automated replies. | +| **"Authentication failed"** | For Gmail, you must use an App Password, not your regular password. Ensure 2FA is enabled first. | +| **Duplicate replies** | Ensure only one gateway instance is running. Check `hermes gateway status`. | +| **Slow response** | The default poll interval is 15 seconds. Reduce with `EMAIL_POLL_INTERVAL=5` for faster response (but more IMAP connections). | +| **Replies not threading** | The adapter uses In-Reply-To headers. Some email clients (especially web-based) may not thread correctly with automated messages. | + +--- + +## Security + +:::warning +**Use a dedicated email account.** Don't use your personal email β€” the agent stores the password in `.env` and has full inbox access via IMAP. +::: + +- Use **App Passwords** instead of your main password (required for Gmail with 2FA) +- Set `EMAIL_ALLOWED_USERS` to restrict who can interact with the agent +- The password is stored in `~/.hermes/.env` β€” protect this file (`chmod 600`) +- IMAP uses SSL (port 993) and SMTP uses STARTTLS (port 587) by default β€” connections are encrypted + +--- + +## Environment Variables Reference + +| Variable | Required | Default | Description | +|----------|----------|---------|-------------| +| `EMAIL_ADDRESS` | Yes | β€” | Agent's email address | +| `EMAIL_PASSWORD` | Yes | β€” | Email password or app password | +| `EMAIL_IMAP_HOST` | Yes | β€” | IMAP server host (e.g., `imap.gmail.com`) | +| `EMAIL_SMTP_HOST` | Yes | β€” | SMTP server host (e.g., `smtp.gmail.com`) | +| `EMAIL_IMAP_PORT` | No | `993` | IMAP server port | +| `EMAIL_SMTP_PORT` | No | `587` | SMTP server port | +| `EMAIL_POLL_INTERVAL` | No | `15` | Seconds between inbox checks | +| `EMAIL_ALLOWED_USERS` | No | β€” | Comma-separated allowed sender addresses | +| `EMAIL_HOME_ADDRESS` | No | β€” | Default delivery target for cron jobs | +| `EMAIL_ALLOW_ALL_USERS` | No | `false` | Allow all senders (not recommended) | diff --git a/website/docs/user-guide/messaging/index.md b/website/docs/user-guide/messaging/index.md index 913f2fdc5..8ff3a49e7 100644 --- a/website/docs/user-guide/messaging/index.md +++ b/website/docs/user-guide/messaging/index.md @@ -1,12 +1,12 @@ --- sidebar_position: 1 title: "Messaging Gateway" -description: "Chat with Hermes from Telegram, Discord, Slack, WhatsApp, or Signal β€” architecture and setup overview" +description: "Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, or Email β€” architecture and setup overview" --- # Messaging Gateway -Chat with Hermes from Telegram, Discord, Slack, WhatsApp, or Signal. The gateway is a single background process that connects to all your configured platforms, handles sessions, runs cron jobs, and delivers voice messages. +Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, or Email. The gateway is a single background process that connects to all your configured platforms, handles sessions, runs cron jobs, and delivers voice messages. ## Architecture @@ -15,12 +15,12 @@ Chat with Hermes from Telegram, Discord, Slack, WhatsApp, or Signal. The gateway β”‚ Hermes Gateway β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Telegram β”‚ β”‚ Discord β”‚ β”‚ WhatsApp β”‚ β”‚ Slack β”‚ β”‚ Signal β”‚ β”‚ -β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚ Adapterβ”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”β”‚ +β”‚ β”‚ Telegram β”‚ β”‚ Discord β”‚ β”‚ WhatsApp β”‚ β”‚ Slack β”‚ β”‚ Signal β”‚ β”‚ Email β”‚β”‚ +β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚ Adapter β”‚ β”‚Adapter β”‚ β”‚Adapter β”‚ β”‚Adapterβ”‚β”‚ +β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”¬β”€β”€β”€β”€β”˜β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Session Store β”‚ β”‚ @@ -114,9 +114,10 @@ Configure per-platform overrides in `~/.hermes/gateway.json`: # Restrict to specific users (recommended): TELEGRAM_ALLOWED_USERS=123456789,987654321 DISCORD_ALLOWED_USERS=123456789012345678 -SIGNAL_ALLOWED_USERS=+15551234567,+15559876543 +SIGNAL_ALLOWED_USERS=+155****4567,+155****6543 +EMAIL_ALLOWED_USERS=trusted@example.com,colleague@work.com -# Or allow specific users across all platforms (comma-separated user IDs): +# Or allow GATEWAY_ALLOWED_USERS=123456789,987654321 # Or explicitly allow all users (NOT recommended for bots with terminal access): @@ -202,6 +203,7 @@ Each platform has its own toolset: | WhatsApp | `hermes-whatsapp` | Full tools including terminal | | Slack | `hermes-slack` | Full tools including terminal | | Signal | `hermes-signal` | Full tools including terminal | +| Email | `hermes-email` | Full tools including terminal | ## Next Steps @@ -210,3 +212,4 @@ Each platform has its own toolset: - [Slack Setup](slack.md) - [WhatsApp Setup](whatsapp.md) - [Signal Setup](signal.md) +- [Email Setup](email.md)