Skill: polumish/imap-mail (version 1.5.4)

--- name: imap-mail description: Personal email via your own IMAP/SMTP server. Send and receive emails, manage folders, and search messages using standard protocols — no third-party email platform required. Use when you need to check inbox, send emails, move messages between folders, search by sender/subject/date, list all mailboxes, schedule emails for future delivery, save attachments, or get push notifications for new mail (IMAP IDLE). metadata: {"openclaw":{"requires":{"bins":["python3"]},"install":{"uv":{"packages":["fastapi","uvicorn"]}}}} --- # IMAP Mail Skill Send and receive email through your own IMAP/SMTP server. A lightweight local REST API (FastAPI) runs as a bridge between the agent and your mail server — no third-party email platform needed. ## Setup (first time) ### 1. Install dependencies ```bash pip3 install fastapi uvicorn ``` ### 2. Configure credentials Create `/etc/imap-mail.env` (or any path, then set `IMAP_MAIL_ENV`): ```env MAIL_IMAP_HOST=mail.example.com MAIL_IMAP_PORT=993 MAIL_SMTP_HOST=mail.example.com MAIL_SMTP_PORT=465 MAIL_USER=[REDACTED_SECRET] MAIL_PASS=yourpassword MAIL_FROM_NAME=MyAgent ``` ### 3. Start the API server ```bash # One-time / foreground python3 {baseDir}/scripts/mail-api.py # Or as a systemd service (recommended) # See: {baseDir}/references/systemd.md ``` The API listens on `http://127.0.0.1:8025` by default. ## Checking Email ```bash # List recent messages python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] # Unread only python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] --unseen # Specific folder python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] --folder Sent # Read a specific message (use UID from list output) python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] --message 42 # Read message and save all its attachments python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] --message 42 --save-attachments /tmp/mail/ # List threads python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] --threads # List all folders python3 {baseDir}/scripts/check_inbox.py --inbox [REDACTED_SECRET] --folders ``` ## Searching Email ```bash # Search by keyword (subject + body) python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --q "invoice" # Search by sender python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --from "[REDACTED_SECRET]" # Search by subject + date range python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --subject "meeting" --since 2026-01-01 # Find unread messages python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --unseen # Find messages with attachments and save them python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --has-attachments --save-attachments /tmp/mail/ # Find messages from VIP senders only python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --vip # Find only flagged/starred messages python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --flagged # Find flagged messages from a specific sender python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --from "[REDACTED_SECRET]" --flagged # Combined filters: unread messages from a specific sender since a date python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --from "[REDACTED_SECRET]" --since 2026-03-01 --unseen # Unread messages with a specific subject keyword python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --subject "invoice" --unseen # Search in a specific folder python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --q "report" --folder Archive ``` ## Sorting Inbox (Personal vs Forwarded) Automatically move messages into sub-folders based on addressing: - **Personal** — inbox address is directly in `To:` or `Cc:` - **Forwarded** — subject starts with `Fwd:` / `FW:`, or `X-Forwarded-*` / `Resent-*` headers present - Forwarded takes priority over Personal when both apply ```bash # Preview what would be moved (no changes) python3 {baseDir}/scripts/sort_inbox.py --inbox [REDACTED_SECRET] --dry-run # Sort all messages python3 {baseDir}/scripts/sort_inbox.py --inbox [REDACTED_SECRET] # Sort only unread messages python3 {baseDir}/scripts/sort_inbox.py --inbox [REDACTED_SECRET] --unseen # Custom folder names python3 {baseDir}/scripts/sort_inbox.py --inbox [REDACTED_SECRET] \ --personal-folder MyInbox --forwarded-folder Forwards # Sort a specific source folder python3 {baseDir}/scripts/sort_inbox.py --inbox [REDACTED_SECRET] --folder AllMail ``` Messages that match neither category (e.g. BCC, bulk mail) stay in the source folder. --- ## Folder Management ```bash # List all folders python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --list # Create a folder python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --create Archive # Delete a folder python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --delete OldFolder # Move a message to another folder (use UID from check_inbox output) python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --move 42 --to Archive # Move from a specific source folder python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --move 5 --to INBOX --from-folder Junk # Delete a message python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --delete-msg 42 # Mark all messages in INBOX as read python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --mark-seen # Mark all messages in a specific folder as read python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --mark-seen --from-folder Sent # Mark one specific message as read (use UID from check_inbox output) python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --mark-seen-uid 42 # Mark several specific messages as read (space-separated UIDs) python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --mark-seen-uid 42 55 73 # Flag (star) specific messages as important python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --flag-uid 42 55 73 # Flag ALL messages from a specific sender python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --flag-from "[REDACTED_SECRET]" python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --flag-from "[REDACTED_SECRET]" # Remove flag from messages python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --unflag-uid 42 python3 {baseDir}/scripts/manage_folders.py --inbox [REDACTED_SECRET] --unflag-from "[REDACTED_SECRET]" ``` ## Sending Email ```bash # Send a plain text email python3 {baseDir}/scripts/send_email.py \ --to [REDACTED_SECRET] \ --subject "Hello" \ --text "Message body here" # Send to multiple recipients python3 {baseDir}/scripts/send_email.py \ --to [REDACTED_SECRET] \ --to [REDACTED_SECRET] \ --subject "Hello everyone" \ --text "Hi all!" # Reply to a message (preserves thread) python3 {baseDir}/scripts/send_email.py \ --to [REDACTED_SECRET] \ --subject "Re: Original Subject" \ --text "My reply" \ --reply-to "<original-message-id>" ``` ## Contact Memory (CRM) Persistent notes and history per contact. Flagged senders are automatically tracked — when their message arrives, the agent pulls full context and reports in detail. ```bash # Look up everything about a contact python3 {baseDir}/scripts/manage_contacts.py --get [REDACTED_SECRET] # List all contacts python3 {baseDir}/scripts/manage_contacts.py --list # Save a contact with name and tags python3 {baseDir}/scripts/manage_contacts.py --save [REDACTED_SECRET] --name "Craig Smith" --tags "client,priority" # Append a timestamped note (agent does this automatically after each flagged message) python3 {baseDir}/scripts/manage_contacts.py --note [REDACTED_SECRET] "Wants proposal by Friday. Budget ~$5k." # Delete a contact python3 {baseDir}/scripts/manage_contacts.py --delete [REDACTED_SECRET] ``` **How it works with flagged mail:** 1. Flagged (starred) UNSEEN messages are processed separately from regular mail 2. For each flagged message, the agent fetches the sender's full contact history 3. Reports to user with: who wrote, what they want, full context from previous interactions 4. Automatically saves a note summarizing the new message ## Auto-Rules (persistent flag/action on incoming mail) Rules are defined once and applied automatically to every new (UNSEEN) message on each mail check — until you remove them. ```bash # Flag ALL future messages from Craig as important (persists forever) python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --add --from "[REDACTED_SECRET]" # Flag messages with "URGENT" in subject python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --add --subject "URGENT" # Auto-mark-as-read messages from a newsletter python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --add --from "[REDACTED_SECRET]" --action mark-seen # List all active rules python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --list # Apply all rules right now (without waiting for next cron) python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --apply # Temporarily disable a rule (ID from --list) python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --disable 1 # Re-enable python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --enable 1 # Remove permanently python3 {baseDir}/scripts/manage_rules.py --inbox [REDACTED_SECRET] --remove 1 ``` ## Scheduled Send Queue emails for future delivery. The API background scheduler checks every 60 seconds. ```bash # Schedule via API directly (ISO datetime, UTC recommended) # POST /inboxes/{inbox}/scheduled # Body: {"to": ["[REDACTED_SECRET]"], "subject": "...", "text": "...", "send_at": "2026-03-10T09:00:00Z"} # List all scheduled messages # GET /inboxes/{inbox}/scheduled # Cancel a scheduled message # DELETE /inboxes/{inbox}/scheduled/{id} ``` ## IMAP IDLE (Push Notifications) Instead of polling every N minutes, IDLE keeps a persistent connection open so the server pushes notifications immediately when new mail arrives. Add to your env file: ```env # Required: webhook URL to POST new mail events to MAIL_IDLE_WEBHOOK=http://127.0.0.1:8080/mail-event # Optional: folder to watch (default: INBOX) MAIL_IDLE_FOLDER=INBOX ``` When new mail arrives, the API POSTs to the webhook: ```json { "event": "new_mail", "uid": "123", "subject": "Hello", "from_": [{"name": "Alice", "email": "[REDACTED_SECRET]"}], "vip": false, ...full message fields... } ``` Check IDLE status: ```bash # GET http://127.0.0.1:8025/idle/status ``` ## VIP Sender List Mark specific senders as VIP — their messages will have `"vip": true` in the API response and in IDLE webhook payloads, enabling urgent/priority handling. Add to your env file: ```env MAIL_VIP_SENDERS=[REDACTED_SECRET],[REDACTED_SECRET] ``` Messages from VIP senders are flagged in all responses (`"vip": true`) and can be filtered: ```bash # Show only VIP messages python3 {baseDir}/scripts/search.py --inbox [REDACTED_SECRET] --vip ``` ## API Endpoints The local REST API at `http://127.0.0.1:8025` exposes: | Method | Path | Description | |--------|------|-------------| | GET | `/health` | Check API status (includes IDLE state, VIP list) | | GET | `/idle/status` | IMAP IDLE watcher status | | GET | `/inboxes/{inbox}/folders` | List folders | | POST | `/inboxes/{inbox}/folders` | Create folder | | DELETE | `/inboxes/{inbox}/folders/{name}` | Delete folder | | GET | `/inboxes/{inbox}/messages` | List messages (`?folder=INBOX&limit=N&unseen=true`) | | GET | `/inboxes/{inbox}/messages/{uid}` | Get full message (`?folder=INBOX`) | | GET | `/inboxes/{inbox}/messages/{uid}/attachments/{index}` | Download attachment (base64) | | POST | `/inboxes/{inbox}/messages` | Send email | | POST | `/inboxes/{inbox}/messages/{uid}/move` | Move message (`?folder=src`) | | DELETE | `/inboxes/{inbox}/messages/{uid}` | Delete message | | POST | `/inboxes/{inbox}/sort` | Sort into Personal/Forwarded folders (`?dry_run=true`) | | GET | `/inboxes/{inbox}/search` | Search (`?q=&from=&subject=&since=&vip_only=true`) | | GET | `/inboxes/{inbox}/threads` | List threads | | POST | `/inboxes/{inbox}/scheduled` | Schedule email for future delivery | | GET | `/inboxes/{inbox}/scheduled` | List scheduled messages | | DELETE | `/inboxes/{inbox}/scheduled/{id}` | Cancel scheduled message | ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `MAIL_IMAP_HOST` | — | IMAP server hostname | | `MAIL_IMAP_PORT` | `993` | IMAP port (TLS) | | `MAIL_SMTP_HOST` | — | SMTP server hostname | | `MAIL_SMTP_PORT` | `465` | SMTP port (TLS) | | `MAIL_USER` | — | Email login / address | | `MAIL_PASS` | — | Password | | `MAIL_FROM_NAME` | `Agent` | Display name in From header | | `MAIL_IDLE_WEBHOOK` | — | Webhook URL for IMAP IDLE push events | | `MAIL_IDLE_FOLDER` | `INBOX` | Folder to watch with IDLE | | `MAIL_VIP_SENDERS` | — | Comma-separated VIP email addresses | | `MAIL_SCHEDULED_DB` | `/tmp/imap-mail-scheduled.db` | SQLite path for scheduled sends | | `MAIL_ALLOW_SELF_SIGNED` | `false` | Set `true` to skip TLS cert verification (self-signed certs) | | `IMAP_MAIL_API` | `http://127.0.0.1:8025` | API base URL (for scripts) | | `IMAP_MAIL_ENV` | `/etc/imap-mail.env` | Path to env file | | `IMAP_MAIL_PORT` | `8025` | API listen port | ## Security Notes - **Credentials** — mail login and password are stored in a local env file (e.g. `/etc/imap-mail.env`), readable only by the service user. Never hardcode credentials in scripts. - **SSL/TLS** — all IMAP and SMTP connections use TLS by default. Certificate verification is **enabled** by default (`ssl.create_default_context()`). Set `MAIL_ALLOW_SELF_SIGNED=true` only if your mail server uses a self-signed certificate and you accept the risk. - **Local API only** — the REST bridge listens on `127.0.0.1` (loopback) only and is not exposed to the network. - **Webhook (IDLE)** — if `MAIL_IDLE_WEBHOOK` is set, full message contents (including body) are POSTed to that URL on new mail. Ensure the webhook URL is a trusted local endpoint. ## Compatibility Works with any standard IMAP/SMTP server: - Self-hosted: Dovecot, Postfix, Exim, Maddy - Hosted: Gmail (App Password), Outlook/Hotmail, Yahoo Mail, Fastmail, ProtonMail Bridge, and any provider that supports IMAP > **Note:** Self-signed TLS certificates are accepted automatically. ## References - [Systemd service setup]({baseDir}/references/systemd.md) - [Full API reference]({baseDir}/references/api.md)


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)