claw-mail
Multi-account email management skill for IMAP/SMTP. Fetches, reads, searches, composes, sends, replies, forwards, and organizes emails across multiple accoun...
Description
name: claw-mail description: > Multi-account email management skill for IMAP/SMTP. Fetches, reads, searches, composes, sends, replies, forwards, and organizes emails across multiple accounts. Features IMAP Outbox for reliable delivery, secure credential storage via 1Password and macOS Keychain, TLS 1.2+ with hardened ciphers, OAuth2 authentication, IMAP IDLE push monitoring, connection pooling, S/MIME signing, calendar invitations, mail merge, conversation threading, webhook rule actions, and configurable dated-folder archival. license: MIT metadata: author: openclaw version: "0.7.0" compatibility: > Requires Python 3.11+ and PyYAML. Optional: 1Password CLI (op) for op:// credentials, macOS for keychain:// credentials, cryptography package for S/MIME. allowed-tools: Bash(python3 *) Read Write
clawMail Skill
You are an email management agent with multi-account IMAP/SMTP support. You can fetch, read, search, process, compose, send, reply, forward, move, and manage emails, drafts, and folders across multiple email accounts.
Multi-Account Model
- Account profiles: Each account has its own IMAP/SMTP credentials, mailboxes, fetch limits, archival settings, and processing rules.
- Default account: One account is designated as the default. Any script invoked
without
--accountuses the default automatically. - SMTP fallback: If an account's SMTP server fails, the system automatically retries via a configured fallback relay.
- IMAP Outbox: Messages are staged in a temporary Outbox folder before SMTP delivery. If SMTP fails, the message stays in Outbox for retry by the heartbeat.
- Per-account + global rules: Each account has its own rules, plus global rules that apply to all accounts.
- OAuth2: Accounts can use OAuth2 (XOAUTH2) authentication instead of passwords.
- Dated-folder archival:
archive_mail.pyand the heartbeat honor per-accountarchive_root/archive_frequencydefaults so messages routed to thearchiveaction land in folders such asArchive-202603,Archive-W09, orArchive-20260315.
Security
- TLS 1.2+: All IMAP and SMTP connections enforce TLS 1.2 or higher.
- Hardened ciphers: Only ECDHE+AESGCM, ECDHE+CHACHA20, DHE+AESGCM, and DHE+CHACHA20 cipher suites are allowed. Weak ciphers (MD5, RC4, 3DES, DSS) are explicitly blocked.
- Certificate verification: Hostname checking and certificate validation are always enabled.
- RFC 5322 compliance: All outgoing emails include required Date, Message-ID, and MIME-Version headers automatically.
- Secure credential storage: Passwords in config support 1Password CLI
(
op://vault/item/field), macOS Keychain (keychain://service/account), and environment variables (env://VAR_NAME).
Available Scripts
All scripts are in the scripts/ directory. Run with
python3 scripts/<name>.py from the skill root. Every script accepts
--account <name> to target a specific account.
Core Scripts
| Script | Purpose |
|---|---|
scripts/fetch_mail.py |
Fetch emails from an IMAP folder |
scripts/read_mail.py |
Read/render an email by Message-ID; save attachments to disk |
scripts/search_mail.py |
Search emails by subject, sender, body, date, flags |
scripts/send_mail.py |
Send rich HTML emails via SMTP (Outbox + fallback); attach files |
scripts/compose_mail.py |
Compose rich HTML emails from templates; attach files |
scripts/reply_mail.py |
Reply to an email with original-message quoting |
scripts/forward_mail.py |
Forward an email inline-quoted or with attachments |
scripts/draft_mail.py |
Save, list, resume, or send drafts via IMAP Drafts folder |
scripts/process_mail.py |
Run emails through the rule-based processing pipeline |
scripts/manage_folders.py |
List, create, delete, rename, and move IMAP folders |
scripts/move_mail.py |
Move emails between IMAP folders (batch support) |
scripts/heartbeat.py |
Run a full heartbeat cycle (drains Outbox, fetches, processes) |
scripts/idle_monitor.py |
Monitor a mailbox via IMAP IDLE (push notifications) |
scripts/retry_send.py |
Retry sending messages stuck in the IMAP Outbox |
scripts/calendar_invite.py |
Compose and send iCalendar meeting invitations |
scripts/mail_merge.py |
Batch personalised sends from template + CSV/JSON data |
scripts/thread_mail.py |
Group messages into conversation threads |
scripts/archive_mail.py |
Auto-archive old messages into dated folders (daily/weekly/monthly/yearly) |
Library Modules
| Module | Purpose |
|---|---|
scripts/lib/imap_client.py |
IMAP client with IDLE, search, folder management, TLS 1.2+ |
scripts/lib/smtp_client.py |
SMTP client with TLS 1.2+, RFC 5322, OAuth2, MIME building |
scripts/lib/composer.py |
Rich HTML email composer with templates, reply, forward |
scripts/lib/processor.py |
Rule-based processing pipeline with webhook actions |
scripts/lib/account_manager.py |
Multi-account manager with SMTP fallback and Outbox |
scripts/lib/outbox.py |
IMAP Outbox — temporary folder for reliable delivery |
scripts/lib/credential_store.py |
Secure credential storage (1Password, Keychain, env) |
scripts/lib/pool.py |
Connection pool for IMAP/SMTP reuse |
scripts/lib/send_queue.py |
Legacy file-backed send queue (superseded by Outbox) |
scripts/lib/smime.py |
S/MIME signing and encryption |
scripts/lib/oauth2.py |
OAuth2 (XOAUTH2) token management |
scripts/lib/models.py |
Data models (EmailMessage, EmailAddress, etc.) |
Reference Documents
| Reference | When to read |
|---|---|
references/REFERENCE.md |
API overview, all script arguments and output formats |
references/TEMPLATES.md |
Available email templates and template variables |
references/RULES.md |
How to configure processing rules |
ROADMAP.md |
Feature roadmap and progress tracker |
Quick Start
Fetching Mail
python3 scripts/fetch_mail.py --config config.yaml
python3 scripts/fetch_mail.py --account personal --unread-only --format cli --config config.yaml
Sending Rich Emails
Messages are staged in a temporary IMAP Outbox folder, sent via SMTP (with automatic fallback), then removed from Outbox on success.
python3 scripts/send_mail.py \
--to "recipient@example.com" \
--subject "Weekly Report" \
--body "<p>Here are this week's results.</p>" \
--template default \
--attach report.pdf \
--config config.yaml
Replying and Forwarding
python3 scripts/reply_mail.py --message-id "<id@example.com>" --body "Thanks!" --config config.yaml
python3 scripts/forward_mail.py --message-id "<id@example.com>" --to "colleague@x.com" --config config.yaml
Searching Emails
python3 scripts/search_mail.py --subject "invoice" --unseen --config config.yaml
python3 scripts/search_mail.py --criteria '(FROM "alice@x.com" SINCE 01-Jan-2026)' --config config.yaml
Working with Drafts
python3 scripts/draft_mail.py --action save --to "user@x.com" --subject "WIP" --body "..." --config config.yaml
python3 scripts/draft_mail.py --action list --format cli --config config.yaml
python3 scripts/draft_mail.py --action send --message-id "<draft@x.com>" --config config.yaml
Outbox & Send Retry
python3 scripts/retry_send.py --config config.yaml
python3 scripts/retry_send.py --config config.yaml --list
Heartbeat Cycle
The heartbeat drains each account's Outbox, then fetches and processes mail:
python3 scripts/heartbeat.py --config config.yaml
python3 scripts/heartbeat.py --config config.yaml --account work
Archiving Old Messages
python3 scripts/archive_mail.py --config config.yaml --days 90 --frequency monthly
python3 scripts/archive_mail.py --config config.yaml --days 30 --frequency daily --archive-root "Old Mail" --dry-run --format cli
Archiving honors archive_root / archive_frequency settings (defaults: Archive, monthly). The heartbeat and any rule with the archive action move the message into folders named Archive-202603, Archive-W09, or Archive-20260315 based on the configured cadence.
Calendar Invitations
python3 scripts/calendar_invite.py \
--to "bob@example.com" --subject "Standup" \
--start "2026-03-01T09:00:00" --end "2026-03-01T09:30:00" \
--location "Zoom" --config config.yaml
Mail Merge
python3 scripts/mail_merge.py \
--data contacts.csv --subject "Hello {{name}}" \
--body "<p>Dear {{name}}, your code is {{code}}.</p>" \
--to-field email --config config.yaml
Configuration
Create a config.yaml from assets/config.example.yaml:
default_account: work
accounts:
work:
label: "Work"
sender_address: "alice@company.com"
sender_name: "Alice Smith"
imap:
host: imap.company.com
port: 993
username: "alice@company.com"
password: "op://Work/IMAP/password" # 1Password CLI
ssl: true
smtp:
host: smtp.company.com
port: 587
username: "alice@company.com"
password: "op://Work/SMTP/password" # 1Password CLI
tls: true
mailboxes: [INBOX, Projects]
fetch_limit: 50
rules:
- name: flag_urgent
sender_pattern: "boss@company\\.com"
actions: [flag, tag]
tag: urgent
personal:
label: "Personal"
sender_address: "alice@gmail.com"
imap:
host: imap.gmail.com
password: "keychain://imap.gmail.com/alice@gmail.com" # macOS Keychain
smtp:
host: smtp.gmail.com
password: "keychain://smtp.gmail.com/alice@gmail.com" # macOS Keychain
You can also define archive_root (e.g., Archive) and archive_frequency (daily, weekly, monthly, yearly) either globally or per- account. These defaults drive both the archive_mail.py script and the heartbeat's handling of the archive rule action so that archived messages consistently live under folders like Archive-202603, Archive-W09, or Archive-20260315.
Secure Credential Storage
Passwords in config support four backends:
| Scheme | Backend | Example |
|---|---|---|
op:// |
1Password CLI | "op://Work/IMAP/password" |
keychain:// |
macOS Keychain | "keychain://imap.gmail.com/alice" |
env:// |
Environment variable | "env://GMAIL_APP_PASSWORD" |
| (plain text) | Literal value | "my-password" (logs a warning) |
OAuth2 Authentication (Gmail, Outlook 365)
For providers that require OAuth2, set auth: oauth2 on the IMAP/SMTP block:
imap:
host: imap.gmail.com
username: "user@gmail.com"
auth: oauth2
oauth2:
client_id: "your-client-id"
client_secret: "your-client-secret"
refresh_token: "your-refresh-token"
token_uri: "https://oauth2.googleapis.com/token"
Legacy Single-Account Config
Flat imap: / smtp: at root is automatically treated as a single account
named "default".
Reviews (0)
No reviews yet. Be the first to review!
Comments (0)
No comments yet. Be the first to share your thoughts!