fix: wire email platform into toolset mappings + add documentation
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
This commit is contained in:
parent
184aa5b2b3
commit
eac5f8f40f
5 changed files with 197 additions and 10 deletions
|
|
@ -2023,6 +2023,7 @@ class GatewayRunner:
|
||||||
Platform.SLACK: "hermes-slack",
|
Platform.SLACK: "hermes-slack",
|
||||||
Platform.SIGNAL: "hermes-signal",
|
Platform.SIGNAL: "hermes-signal",
|
||||||
Platform.HOMEASSISTANT: "hermes-homeassistant",
|
Platform.HOMEASSISTANT: "hermes-homeassistant",
|
||||||
|
Platform.EMAIL: "hermes-email",
|
||||||
}
|
}
|
||||||
platform_toolsets_config = {}
|
platform_toolsets_config = {}
|
||||||
try:
|
try:
|
||||||
|
|
@ -2043,6 +2044,7 @@ class GatewayRunner:
|
||||||
Platform.SLACK: "slack",
|
Platform.SLACK: "slack",
|
||||||
Platform.SIGNAL: "signal",
|
Platform.SIGNAL: "signal",
|
||||||
Platform.HOMEASSISTANT: "homeassistant",
|
Platform.HOMEASSISTANT: "homeassistant",
|
||||||
|
Platform.EMAIL: "email",
|
||||||
}.get(source.platform, "telegram")
|
}.get(source.platform, "telegram")
|
||||||
|
|
||||||
config_toolsets = platform_toolsets_config.get(platform_config_key)
|
config_toolsets = platform_toolsets_config.get(platform_config_key)
|
||||||
|
|
@ -2835,6 +2837,7 @@ class GatewayRunner:
|
||||||
Platform.SLACK: "hermes-slack",
|
Platform.SLACK: "hermes-slack",
|
||||||
Platform.SIGNAL: "hermes-signal",
|
Platform.SIGNAL: "hermes-signal",
|
||||||
Platform.HOMEASSISTANT: "hermes-homeassistant",
|
Platform.HOMEASSISTANT: "hermes-homeassistant",
|
||||||
|
Platform.EMAIL: "hermes-email",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try to load platform_toolsets from config
|
# Try to load platform_toolsets from config
|
||||||
|
|
@ -2858,6 +2861,7 @@ class GatewayRunner:
|
||||||
Platform.SLACK: "slack",
|
Platform.SLACK: "slack",
|
||||||
Platform.SIGNAL: "signal",
|
Platform.SIGNAL: "signal",
|
||||||
Platform.HOMEASSISTANT: "homeassistant",
|
Platform.HOMEASSISTANT: "homeassistant",
|
||||||
|
Platform.EMAIL: "email",
|
||||||
}.get(source.platform, "telegram")
|
}.get(source.platform, "telegram")
|
||||||
|
|
||||||
# Use config override if present (list of toolsets), otherwise hardcoded default
|
# Use config override if present (list of toolsets), otherwise hardcoded default
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ PLATFORMS = {
|
||||||
"discord": "💬 Discord",
|
"discord": "💬 Discord",
|
||||||
"slack": "💼 Slack",
|
"slack": "💼 Slack",
|
||||||
"whatsapp": "📱 WhatsApp",
|
"whatsapp": "📱 WhatsApp",
|
||||||
|
"signal": "📡 Signal",
|
||||||
|
"email": "📧 Email",
|
||||||
}
|
}
|
||||||
|
|
||||||
# ─── Config Helpers ───────────────────────────────────────────────────────────
|
# ─── Config Helpers ───────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,8 @@ PLATFORMS = {
|
||||||
"discord": {"label": "💬 Discord", "default_toolset": "hermes-discord"},
|
"discord": {"label": "💬 Discord", "default_toolset": "hermes-discord"},
|
||||||
"slack": {"label": "💼 Slack", "default_toolset": "hermes-slack"},
|
"slack": {"label": "💼 Slack", "default_toolset": "hermes-slack"},
|
||||||
"whatsapp": {"label": "📱 WhatsApp", "default_toolset": "hermes-whatsapp"},
|
"whatsapp": {"label": "📱 WhatsApp", "default_toolset": "hermes-whatsapp"},
|
||||||
|
"signal": {"label": "📡 Signal", "default_toolset": "hermes-signal"},
|
||||||
|
"email": {"label": "📧 Email", "default_toolset": "hermes-email"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
176
website/docs/user-guide/messaging/email.md
Normal file
176
website/docs/user-guide/messaging/email.md
Normal file
|
|
@ -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) |
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 1
|
||||||
title: "Messaging Gateway"
|
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
|
# 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
|
## Architecture
|
||||||
|
|
||||||
|
|
@ -15,12 +15,12 @@ Chat with Hermes from Telegram, Discord, Slack, WhatsApp, or Signal. The gateway
|
||||||
│ Hermes Gateway │
|
│ Hermes Gateway │
|
||||||
├─────────────────────────────────────────────────────────────────┤
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌───────┐│
|
||||||
│ │ Telegram │ │ Discord │ │ WhatsApp │ │ Slack │ │ Signal │ │
|
│ │ Telegram │ │ Discord │ │ WhatsApp │ │ Slack │ │ Signal │ │ Email ││
|
||||||
│ │ Adapter │ │ Adapter │ │ Adapter │ │ Adapter │ │ Adapter│ │
|
│ │ Adapter │ │ Adapter │ │ Adapter │ │Adapter │ │Adapter │ │Adapter││
|
||||||
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ │
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ └───┬────┘ └──┬────┘│
|
||||||
│ │ │ │ │ │ │
|
│ │ │ │ │ │ │ │
|
||||||
│ └─────────────┼────────────┼─────────────┼───────────┘ │
|
│ └─────────────┼────────────┼────────────┼──────────┼─────────┘ │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ┌────────▼────────┐ │
|
│ ┌────────▼────────┐ │
|
||||||
│ │ Session Store │ │
|
│ │ Session Store │ │
|
||||||
|
|
@ -114,9 +114,10 @@ Configure per-platform overrides in `~/.hermes/gateway.json`:
|
||||||
# Restrict to specific users (recommended):
|
# Restrict to specific users (recommended):
|
||||||
TELEGRAM_ALLOWED_USERS=123456789,987654321
|
TELEGRAM_ALLOWED_USERS=123456789,987654321
|
||||||
DISCORD_ALLOWED_USERS=123456789012345678
|
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
|
GATEWAY_ALLOWED_USERS=123456789,987654321
|
||||||
|
|
||||||
# Or explicitly allow all users (NOT recommended for bots with terminal access):
|
# 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 |
|
| WhatsApp | `hermes-whatsapp` | Full tools including terminal |
|
||||||
| Slack | `hermes-slack` | Full tools including terminal |
|
| Slack | `hermes-slack` | Full tools including terminal |
|
||||||
| Signal | `hermes-signal` | Full tools including terminal |
|
| Signal | `hermes-signal` | Full tools including terminal |
|
||||||
|
| Email | `hermes-email` | Full tools including terminal |
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
|
|
@ -210,3 +212,4 @@ Each platform has its own toolset:
|
||||||
- [Slack Setup](slack.md)
|
- [Slack Setup](slack.md)
|
||||||
- [WhatsApp Setup](whatsapp.md)
|
- [WhatsApp Setup](whatsapp.md)
|
||||||
- [Signal Setup](signal.md)
|
- [Signal Setup](signal.md)
|
||||||
|
- [Email Setup](email.md)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue