From apple-mail
Read and manage Apple Mail.app on macOS Apple Silicon. Use when the user asks about their email, wants to read or find messages, check unread mail, list accounts or mailboxes, send an email, route a domain to a folder, create or apply filter rules, or anything related to Mail.app or email on macOS. Requires: macOS on Apple Silicon (arm64).
How this skill is triggered — by the user, by Claude, or both
Slash command
/apple-mail:apple-mail email task — e.g. 'show unread', 'find emails from X', 'send to Y'email task — e.g. 'show unread', 'find emails from X', 'send to Y'This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Interact with Apple Mail.app via the bundled `amail` CLI (Apple Silicon arm64 binary, no credentials, no IMAP, no API keys). The plugin system automatically adds `amail` to PATH — no manual setup required.
Interact with Apple Mail.app via the bundled amail CLI (Apple Silicon arm64 binary, no credentials, no IMAP, no API keys). The plugin system automatically adds amail to PATH — no manual setup required.
On first amail invocation, macOS will prompt for Mail.app automation permission — tell the user to click Allow.
Use the amail CLI to interact with Apple Mail.app via Apple Events. Mail.app must be running. On first use macOS will prompt once for automation permission — tell the user to click Allow.
List all configured accounts:
amail accounts
List all mailboxes (optionally filtered to one account):
amail mailboxes [--account "Account Name"]
Important: The user may have mailboxes named after people (e.g. chandra, mom, work). Always check amail mailboxes before searching — if a person-named mailbox exists, target it directly with messages list --mailbox instead of using messages search. This is orders of magnitude faster.
List messages in a specific mailbox (account and mailbox are required):
amail messages list --account "Account Name" --mailbox "INBOX" \
[--limit N] [--unread] [--summary]
--limit defaults to 25; use --limit 0 for all messages--unread restricts to unread messages only--summary fetches message bodies and displays a 2-line plain-text preview per message (see below)Output fields per message: id, subject, sender, date, read, flagged, hasAttachments, body (populated when --summary is used)
When the user asks for recent emails from someone (e.g. "last 10 emails from chandra"):
amail mailboxes to check if a person-named mailbox existsmessages list targeting that mailbox directly:
amail messages list --account "iCloud" --mailbox "chandra" --limit 10 --summary
messages search with --from:
amail messages search --from "chandra" --limit 10 --summary
The --summary flag produces a table with subject, date, and a 2-line body preview. Body processing (HTML stripping, whitespace normalization, word-wrap) is done in Go — not in the shell.
amail messages read <message-id>
Returns: id, subject, sender, date, read, flagged, body, attachments[]
amail messages search [--query "text"] [--account "Account Name"] \
[--mailbox "Mailbox Name"] [--from "addr"] [--subject "text"] \
[--limit N] [--summary]
--from and --subject use Mail.app's indexed whose clause — fast even on large mailboxes--query searches subject, sender, and body — slower; always add --mailbox to scope it--mailbox restricts to one mailbox; without it, Trash/Junk/Sent/Drafts/All Mail are automatically skipped--limit defaults to 25; use --limit 0 for all results--summary fetches and displays a 2-line body preview per resultamail send --to "[email protected]" --subject "Subject" --body "Body text" \
[--to "[email protected]"] \
[--cc "[email protected]"] \
[--bcc "[email protected]"] \
[--attachment "/absolute/path/to/file"]
--to, --cc, --bcc, and --attachment are all repeatableAll commands emit a JSON envelope when piped or when --format json is passed:
{
"ok": true,
"data": <T>,
"error": { "code": "...", "message": "..." } | null,
"meta": { "command": "...", "timestamp": "..." }
}
Use --format json whenever you need to parse output. Use --pretty for human-readable JSON. Check ok before reading data.
amail messages list --account "iCloud" --mailbox "chandra" --limit 10 --format json
amail messages search --from "chandra" --limit 10 --format json | jq '.data[].subject'
amail schema
Emits the complete JSON spec of every command, subcommand, flag, type, default, and description. Call this first if you are unsure of available options.
List all Mail.app filter rules:
amail rules list
amail rules list --format json --pretty
Each rule has a name, enabled flag, match mode (any or all), a list of conditions, and an action. Conditions typically look like from ends-with @domain.com. Actions are typically move: FolderName.
amail rules add-condition --rule "RULE_NAME" --expression "domain.com" \
[--type from] [--qualifier ends-with]
--type default from; options: from, to, cc, subject, any-recipient, body, account--qualifier default ends-with; options: contains, not-contains, begins-with, ends-with, equalsamail rules create --name "services2" --move "Services" --expression "domain.com" \
[--account "Account Name"] [--type from] [--qualifier ends-with]
Creates a new enabled rule with OR logic and an initial condition. --account is optional — omit to search all accounts for the destination mailbox.
Targeted mode (fast — recommended): applies a single named rule using indexed whose queries:
amail rules apply --rule "services" [--mailbox INBOX] [--account "Account Name"]
General mode (slower): applies all enabled rules using batched perform mail action:
amail rules apply [--mailbox INBOX] [--account "Account Name"] [--batch-size 500]
Targeted mode is orders of magnitude faster on large mailboxes. Always prefer --rule when you know which rule to apply.
The user's pattern: one rule per destination folder, OR logic (any), from ends-with @domain.com conditions.
amail rules list --format json | jq '.data[] | select(.actions.moveToMailbox == "Services") | {name, count: (.conditions | length)}'
rules add-conditionrules create:
services full → services2; services2 full → services3amail rules apply --rule "services"
Why 80? Mail.app's GUI degrades noticeably beyond 80 conditions per rule.
amail accounts first if you don't know the account name — never guess itamail mailboxes to check for person-named mailboxes before doing a sender search — direct mailbox targeting is far faster than search--from and --subject on messages search are indexed and fast; --query (body search) is slow without --mailbox scoping--format json whenever you need to extract data (e.g. a message id to pass to read)id values come from messages list or messages search output — they are opaque strings, never construct them manuallyok is false in JSON output, surface the error.message to the user and stop--attachment must be absolute; expand ~ before passingCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub trodemaster/apple-mail-cli --plugin apple-mail