mail_search
Search all mailboxes through a read-only index using optional filters for subject, sender, recipient, body text, dates, unread/flagged status, and attachments; returns citable pointers newest first.
Instructions
Indexed search across ALL mailboxes via Mail's Envelope Index — fast and
read-only. All filters optional and ANDed:
subject/from_/to substrings, mailbox a mailbox NAME exactly as mail_overview
reports it ("Junk E-mail" — case-insensitive substring; the encoded spelling also
works; a name that matches nothing RAISES — it is a typo, not an empty mailbox —
while a stale folder url just returns no results), since/until (epoch seconds on
received date),
unread/flagged. body searches message TEXT via the FTS index and is BEST-EFFORT —
it only sees messages already indexed by mail_index_bodies (run that first;
incomplete coverage is normal). At least one filter required. Returns citable
Pointers, newest first. Falls back to AppleScript inbox search on missing Automation
access / schema drift.
has_attachments means a real DOCUMENT — inline signature/newsletter images are
excluded, so it will not match a mail whose only attachment is a logo. account
takes a display name ("Personal") or a raw account UUID; the UUID form stays pure
sqlite, while a NAME has to be resolved through Mail and therefore LAUNCHES Mail if
it isn't running (an unknown name raises rather than guessing). Every other filter
reads the index at rest and never launches Mail.
Read-only; needs Full Disk Access, plus Automation access for Mail on the
account-name path and the AppleScript fallback.
Each Pointer carries folder (the round-trip mailbox token) and account (the
owning account's uuid — map it to a name with one mail_overview call), so a hit
is complete on its own: no second read to work out where it lives.
Returns {results, truncated?, plane?, coverage?}. truncated means the answer came
back AT limit (25 max) and there may be more — do NOT report such a search as
exhaustive. plane = "applescript-inbox" means the sqlite index was unreachable and
this scanned the INBOX ONLY. coverage explains an empty body= answer: bodies are
only matchable once mail_index_bodies has indexed them.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | ||
| body | No | ||
| from_ | No | ||
| limit | No | ||
| since | No | ||
| until | No | ||
| unread | No | ||
| account | No | ||
| flagged | No | ||
| mailbox | No | ||
| subject | No | ||
| has_attachments | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||