apple-mail
read, write, search, and manage emails in macos mail.app via cli scripts. use when the user wants to send, read, search, draft, or organise emails.
apple mail skill
read, write, search, and manage emails in macos mail.app via cli.
quick start
# verify setup (mail.app running, full disk access, dependencies)
.cursor/skills/apple-mail/scripts/check-setup.sh
# build the search index (required for search and content previews)
.cursor/skills/apple-mail/scripts/mail.sh build-index
# list recent emails with content previews
.cursor/skills/apple-mail/scripts/mail.sh list-recent --include-content
important: symlink path
this skill lives under .cursor/skills/apple-mail/ which may be a symlink. all script invocations should use the resolved path from this skill directory. run .cursor/skills/apple-mail/scripts/check-setup.sh to see resolved paths.
tool reference
all commands are invoked via .cursor/skills/apple-mail/scripts/mail.sh <command> [args].
all output is json with this contract:
{"success": bool, "data": ..., "error": ..., "warnings": [], "meta": {...}}
| command | what it does | speed |
|---|---|---|
server-info | skill version and metadata | instant |
check-health | verify mail.app is responding | ~1 s |
list-accounts | list all mail accounts | ~0.15 s |
list-folders --account EMAIL | list folders with email counts | ~1-2 s |
list-recent [--limit N] [--include-content] | recent emails from all inboxes | ~0.3 s |
list-emails --account EMAIL --folder NAME [--limit N] [--include-content] | emails in a folder | ~0.3 s |
list-drafts [--limit N] [--include-content] | drafts across all accounts | ~0.25 s |
read-email --message-id MID or --id ID | full email content, recipients, attachments | ~1-2 s |
search --query TEXT [--scope all|subject|sender] [--limit N] | search emails | ~1 ms (all) / ~200 ms (subject/sender) |
compose-draft --account EMAIL --subject TEXT --body TEXT --to ADDR... | create a new draft | ~1 s |
amend-draft --id ID [--subject TEXT] [--body TEXT] | modify an existing draft | ~2 s |
send-draft --id ID | send a draft | ~2 s |
reply-draft --message-id MID --body TEXT [--reply-all] or --id ID | create a reply draft | ~2 s |
forward-draft --message-id MID --account EMAIL --body TEXT --to ADDR... | forward as draft | ~2 s |
delete-email --message-ids MID [MID...] or --ids ID [ID...] | delete email(s) (single or batch) | ~1-3 s |
delete-draft --id ID | delete a draft | ~1 s |
move-email --message-id MID --to FOLDER or --id ID | move email to folder | ~3-5 s |
build-index | build/rebuild fts5 search index | ~30-120 s |
index-status | check background indexing progress | instant |
index-cancel | cancel background indexing | instant |
array arguments use space separation: --to [email protected] [email protected] --cc [email protected]
for detailed parameter docs and return shapes, see references/tool-reference.md.
workflows
triage inbox
list-recent --include-content-- scan recent emails with previews (note themessage_idfield in output)read-email --message-id MID-- open specific email for full content (prefer--message-idover--id)move-email --message-id MID --to Archiveordelete-email --message-ids MID-- act on it
reply to an email
read-email --message-id MID-- read the emailreply-draft --message-id MID --body "..." [--reply-all]-- create reply draftlist-drafts-- confirm draft and get stable idsend-draft --id DRAFT_ID-- send
search and act
search --query "invoice" --scope all-- find matching emailsread-email --message-id MID-- read full content- take action (reply, forward, move, delete)
compose and send
compose-draft --account [email protected] --subject "Hello" --body "..." --to [email protected]list-drafts— get stable draft idamend-draft --id ID --body "revised text"— (optional) revisesend-draft --id ID— send
safety rules
- always draft first -- never send without creating and confirming a draft
- never delete without confirmation -- always confirm with the user before deletion
- prefer
--message-idover--id-- the RFC 2822 message-id (themessage_idfield from list commands) is stable across exchange syncs; integer ids can shift - verify draft ids -- draft ids may change after creation; always re-list drafts for stable ids
- content previews are partial -- previews are the first ~5000 chars, not full content. use
read-emailfor the complete message - exchange sync delay -- move operations on exchange accounts need ~3 s for server sync
id shift recovery
mail.app integer ids can change after exchange sync. use --message-id (the stable RFC 2822 header) to avoid this problem entirely:
- list commands (list-emails, list-recent, list-drafts) return both
id(integer) andmessage_id(stable string) for each email - read, delete, move, reply, and forward commands all accept
--message-idas the preferred identifier --id(integer) still works as a fallback for backward compatibility
if a --message-id lookup fails (edge case), re-list the folder:
.cursor/skills/apple-mail/scripts/mail.sh list-emails --account EMAIL --folder FOLDER
background indexing
when --include-content is used and some emails aren't in the index, the system:
- tries to find
.emlxfiles on disk (instant) - falls back to jxa content fetch (up to 60 s)
- if time runs out, spawns a background worker and returns partial results
check background progress: .cursor/skills/apple-mail/scripts/mail.sh index-status
cancel if needed: .cursor/skills/apple-mail/scripts/mail.sh index-cancel
writing style
see references/writing-style.md for email composition guidelines.