Назад към всички

claw-mail

// 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, OAu

$ git log --oneline --stat
stars:1,933
forks:367
updated:March 4, 2026
SKILL.mdreadonly
SKILL.md Frontmatter
nameclaw-mail
descriptionMulti-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.
licenseMIT
metadata[object Object]
compatibilityRequires Python 3.11+ and PyYAML. Optional: 1Password CLI (op) for op:// credentials, macOS for keychain:// credentials, cryptography package for S/MIME.
allowed-toolsBash(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 --account uses 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.py and the heartbeat honor per-account archive_root/archive_frequency defaults so messages routed to the archive action land in folders such as Archive-202603, Archive-W09, or Archive-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

ScriptPurpose
scripts/fetch_mail.pyFetch emails from an IMAP folder
scripts/read_mail.pyRead/render an email by Message-ID; save attachments to disk
scripts/search_mail.pySearch emails by subject, sender, body, date, flags
scripts/send_mail.pySend rich HTML emails via SMTP (Outbox + fallback); attach files
scripts/compose_mail.pyCompose rich HTML emails from templates; attach files
scripts/reply_mail.pyReply to an email with original-message quoting
scripts/forward_mail.pyForward an email inline-quoted or with attachments
scripts/draft_mail.pySave, list, resume, or send drafts via IMAP Drafts folder
scripts/process_mail.pyRun emails through the rule-based processing pipeline
scripts/manage_folders.pyList, create, delete, rename, and move IMAP folders
scripts/move_mail.pyMove emails between IMAP folders (batch support)
scripts/heartbeat.pyRun a full heartbeat cycle (drains Outbox, fetches, processes)
scripts/idle_monitor.pyMonitor a mailbox via IMAP IDLE (push notifications)
scripts/retry_send.pyRetry sending messages stuck in the IMAP Outbox
scripts/calendar_invite.pyCompose and send iCalendar meeting invitations
scripts/mail_merge.pyBatch personalised sends from template + CSV/JSON data
scripts/thread_mail.pyGroup messages into conversation threads
scripts/archive_mail.pyAuto-archive old messages into dated folders (daily/weekly/monthly/yearly)

Library Modules

ModulePurpose
scripts/lib/imap_client.pyIMAP client with IDLE, search, folder management, TLS 1.2+
scripts/lib/smtp_client.pySMTP client with TLS 1.2+, RFC 5322, OAuth2, MIME building
scripts/lib/composer.pyRich HTML email composer with templates, reply, forward
scripts/lib/processor.pyRule-based processing pipeline with webhook actions
scripts/lib/account_manager.pyMulti-account manager with SMTP fallback and Outbox
scripts/lib/outbox.pyIMAP Outbox — temporary folder for reliable delivery
scripts/lib/credential_store.pySecure credential storage (1Password, Keychain, env)
scripts/lib/pool.pyConnection pool for IMAP/SMTP reuse
scripts/lib/send_queue.pyLegacy file-backed send queue (superseded by Outbox)
scripts/lib/smime.pyS/MIME signing and encryption
scripts/lib/oauth2.pyOAuth2 (XOAUTH2) token management
scripts/lib/models.pyData models (EmailMessage, EmailAddress, etc.)

Reference Documents

ReferenceWhen to read
references/REFERENCE.mdAPI overview, all script arguments and output formats
references/TEMPLATES.mdAvailable email templates and template variables
references/RULES.mdHow to configure processing rules
ROADMAP.mdFeature 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:

SchemeBackendExample
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".