apple-mail-mcp 1.8.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +91 -26
  2. package/build/index.js +302 -156
  3. package/build/services/appleMailManager.d.ts +32 -7
  4. package/build/services/appleMailManager.d.ts.map +1 -1
  5. package/build/services/appleMailManager.js +256 -104
  6. package/build/services/imapClient.d.ts +72 -22
  7. package/build/services/imapClient.d.ts.map +1 -1
  8. package/build/services/imapClient.js +409 -49
  9. package/build/services/imapIdle.d.ts +58 -0
  10. package/build/services/imapIdle.d.ts.map +1 -0
  11. package/build/services/imapIdle.js +145 -0
  12. package/build/services/messageRouter.d.ts +16 -0
  13. package/build/services/messageRouter.d.ts.map +1 -0
  14. package/build/services/messageRouter.js +29 -0
  15. package/build/services/smtpMailer.d.ts +3 -2
  16. package/build/services/smtpMailer.d.ts.map +1 -1
  17. package/build/services/smtpMailer.js +11 -7
  18. package/build/services/templateStore.d.ts +18 -0
  19. package/build/services/templateStore.d.ts.map +1 -0
  20. package/build/services/templateStore.js +91 -0
  21. package/build/tools/doctor.d.ts +23 -0
  22. package/build/tools/doctor.d.ts.map +1 -0
  23. package/build/tools/doctor.js +74 -0
  24. package/build/tools/resourcesAndPrompts.d.ts +14 -0
  25. package/build/tools/resourcesAndPrompts.d.ts.map +1 -0
  26. package/build/tools/resourcesAndPrompts.js +109 -0
  27. package/build/tools/respond.d.ts +48 -0
  28. package/build/tools/respond.d.ts.map +1 -0
  29. package/build/tools/respond.js +95 -0
  30. package/build/tools/thread.d.ts +19 -0
  31. package/build/tools/thread.d.ts.map +1 -0
  32. package/build/tools/thread.js +32 -0
  33. package/build/types.d.ts +38 -0
  34. package/build/types.d.ts.map +1 -1
  35. package/build/utils/attachmentMaterialize.d.ts +9 -0
  36. package/build/utils/attachmentMaterialize.d.ts.map +1 -0
  37. package/build/utils/attachmentMaterialize.js +38 -0
  38. package/build/utils/mimeParse.d.ts +6 -0
  39. package/build/utils/mimeParse.d.ts.map +1 -1
  40. package/build/utils/mimeParse.js +30 -0
  41. package/package.json +2 -1
package/README.md CHANGED
@@ -86,17 +86,21 @@ On first use, macOS will ask for permission to automate Mail.app. Click "OK" to
86
86
  | **List Messages** | List messages with pagination, sender filter, date display |
87
87
  | **Search Messages** | Search by sender, subject, content, date range, read/flagged status — across all accounts |
88
88
  | **Read Messages** | Get full email content (plain text or HTML) |
89
- | **Send Email** | Compose and send new emails (with optional file attachments) |
89
+ | **Send Email** | Compose and send new emails (attach by file path or inline base64 content) |
90
90
  | **Send Serial Email** | Mail merge — send personalized emails to a list of recipients with {{placeholder}} support |
91
- | **Create Draft** | Save emails to Drafts folder (with optional file attachments) |
91
+ | **Create Draft** | Save emails to Drafts folder (attach by file path or inline base64 content) |
92
92
  | **Reply** | Reply to messages (with reply-all support) |
93
93
  | **Forward** | Forward messages to new recipients |
94
+ | **Get Thread** | Group a conversation by normalized subject (across AppleScript or IMAP) |
94
95
  | **Mark Read/Unread** | Change read status (single or batch) |
95
96
  | **Flag/Unflag** | Flag or unflag messages (single or batch) |
96
97
  | **Delete Messages** | Move messages to trash (single or batch) |
97
98
  | **Move Messages** | Organize into mailboxes (single or batch) |
98
99
  | **List Attachments** | View attachment metadata (name, type, size) |
99
100
  | **Save Attachment** | Save attachments to disk |
101
+ | **Fetch Attachment** | Get an attachment's bytes as base64 (no disk write) |
102
+
103
+ Read/list/get tools also return **structured JSON** (`structuredContent`) alongside the text, so agents can consume results without parsing prose.
100
104
 
101
105
  ### Mailbox & Account Management
102
106
 
@@ -113,17 +117,25 @@ On first use, macOS will ask for permission to automate Mail.app. Click "OK" to
113
117
  |---------|-------------|
114
118
  | **List Rules** | View all mail rules and their enabled status |
115
119
  | **Enable/Disable Rules** | Toggle mail rules on or off |
120
+ | **Create/Delete Rules** | Create rules with conditions + actions, or delete by name |
116
121
  | **Search Contacts** | Look up contacts from Contacts.app by name |
117
- | **Email Templates** | Save, list, use, and delete reusable email templates |
122
+ | **Email Templates** | Save, list, use, and delete reusable email templates (persisted to disk across restarts) |
118
123
 
119
124
  ### Diagnostics
120
125
 
121
126
  | Feature | Description |
122
127
  |---------|-------------|
123
128
  | **Health Check** | Verify Mail.app connectivity |
129
+ | **Doctor** | Diagnose Mail permission, account state, and each IMAP/SMTP backend with actionable messages |
124
130
  | **Statistics** | Message and unread counts per account, recently received stats |
125
131
  | **Sync Status** | Check if Mail.app is actively syncing |
126
132
 
133
+ ### MCP resources & prompts
134
+
135
+ Resources expose read-only context the client can attach without a tool call:
136
+ `mail://accounts`, `mail://templates`, and `mail://mailboxes/{account}`. Prompts
137
+ package common workflows: `triage-inbox`, `compose-reply`, `weekly-summary`.
138
+
127
139
  ---
128
140
 
129
141
  ## Tool Reference
@@ -214,7 +226,7 @@ Send a new email immediately.
214
226
  | `cc` | string[] | No | CC recipients |
215
227
  | `bcc` | string[] | No | BCC recipients |
216
228
  | `account` | string | No | Send from specific account (with `transport: "smtp"`, overrides the From address) |
217
- | `attachments` | string[] | No | Absolute file paths to attach, max 20 files (e.g., `["/Users/me/report.pdf"]`) |
229
+ | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths (e.g., `"/Users/me/report.pdf"`) and/or inline `{filename, contentBase64}` objects for content not on disk |
218
230
  | `transport` | `"applescript"` \| `"smtp"` | No | Send transport (default `"applescript"`). Use `"smtp"` to send clean MIME directly, avoiding the macOS 15+ Mail.app `<blockquote>` wrapping — see [SMTP transport](#smtp-transport) |
219
231
 
220
232
  **Example:**
@@ -270,24 +282,31 @@ Then send:
270
282
 
271
283
  The default `applescript` transport is unchanged; SMTP is opt-in per call.
272
284
 
273
- ##### IMAP backend (read/search) — opt-in, Phase 1
285
+ ##### IMAP backend — opt-in
274
286
 
275
287
  AppleScript runs `search`/`list` predicates client-side over the Apple Event
276
288
  bridge, which is slow and can time out (false-empty) on large Gmail/IMAP
277
- mailboxes (see [#24](https://github.com/sweetrb/apple-mail-mcp/issues/24)). When
278
- an account is configured for IMAP, `search-messages` and `list-messages` instead
279
- run a **server-side IMAP search** ([#43](https://github.com/sweetrb/apple-mail-mcp/issues/43))
280
- typically sub-second and correct on the same mailbox where AppleScript times out.
281
- This is **opt-in and additive**: any account without IMAP configured behaves
282
- exactly as before (AppleScript). When an account is IMAP-configured,
283
- `search-messages`/`list-messages` (read) and `create-mailbox`/`rename-mailbox`/
284
- `delete-mailbox` (folder ops) route to IMAP. The folder ops are the key win for
285
- server accounts: IMAP's `CREATE`/`RENAME`/`DELETE` succeed on exactly the
286
- iCloud/Gmail/Workspace/Exchange mailboxes where Mail.app's AppleScript bridge
287
- can't (#42). `get-message` and message-level mutations (mark/flag/move/delete-
288
- message) stay on AppleScript for nowthey key off a message id, and the IMAP
289
- read rows report **UIDs** (a different, per-mailbox namespace), so routing them
290
- safely needs a UID-aware design (tracked on #43).
289
+ mailboxes (see [#24](https://github.com/sweetrb/apple-mail-mcp/issues/24)), and
290
+ its `delete`/`rename mailbox` and draft handlers don't work on server-side
291
+ accounts at all (#42). When an account is configured for IMAP, the MCP routes to
292
+ a server-side IMAP backend ([#43](https://github.com/sweetrb/apple-mail-mcp/issues/43))
293
+ that is fast and correct on exactly those mailboxes. This is **opt-in and
294
+ additive**: any account without IMAP configured behaves exactly as before
295
+ (AppleScript).
296
+
297
+ What routes to IMAP when an account is IMAP-configured:
298
+
299
+ - **Read:** `search-messages`, `list-messages` (server-side `SEARCH`, typically sub-second), and `get-message`.
300
+ - **Folder ops:** `create-mailbox`, `rename-mailbox`, `delete-mailbox`IMAP's `CREATE`/`RENAME`/`DELETE` succeed on the iCloud/Gmail/Workspace/Exchange mailboxes Mail.app's AppleScript bridge can't touch (#42).
301
+ - **Message mutations:** `mark-as-read`/`unread`, `flag-message`/`unflag-message`, `move-message`, `delete-message`.
302
+
303
+ **Message ids are backend-tagged.** The IMAP read path emits self-describing ids
304
+ of the form `imap:<token>` (the token encodes the account, mailbox path, and
305
+ UID). Pass that id back to `get-message` or any message mutation and it routes to
306
+ IMAP automatically; bare numeric ids continue to use AppleScript. So an agent
307
+ never has to know which backend a message came from — the id carries it. (Batch
308
+ operations remain AppleScript-only and accept numeric ids; use the single-message
309
+ tools for IMAP ids.)
291
310
 
292
311
  Routing is conservative: only a call whose explicit `account` matches the
293
312
  configured IMAP account goes to IMAP; everything else falls through to
@@ -302,6 +321,20 @@ AppleScript.
302
321
  | `APPLE_MAIL_MCP_IMAP_PASSWORD` | No | — | Password (if set, used instead of the Keychain) |
303
322
  | `APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE` | No | — | Keychain item service/server name |
304
323
  | `APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT` | No | = user | Keychain item account |
324
+ | `APPLE_MAIL_MCP_IMAP_ACCOUNTS` | No | — | JSON array of **additional** IMAP accounts for multi-account setups (see below) |
325
+ | `APPLE_MAIL_MCP_IMAP_IDLE` | No | `0` | Set `1` to enable IMAP IDLE push notifications (new-mail alerts) for every configured account |
326
+ | `APPLE_MAIL_MCP_IMAP_IDLE_MS` | No | `60000` | Idle timeout (ms) before a pooled IMAP connection is closed |
327
+
328
+ **Multiple IMAP accounts (C2):** set `APPLE_MAIL_MCP_IMAP_ACCOUNTS` to a JSON array, e.g.
329
+ `[{"account":"Work","user":"me@co.com","host":"imap.co.com","keychainService":"imap.co.com"}]`.
330
+ Each entry accepts `account`, `user`, `host`, `port`, `password`, `keychainService`,
331
+ `keychainAccount`. Calls route to the account matching their `account` argument (or the
332
+ decoded `imap:` id), and each account keeps its own pooled connection.
333
+
334
+ **Push notifications (B5):** with `APPLE_MAIL_MCP_IMAP_IDLE=1`, the server watches each
335
+ account's INBOX and emits an MCP logging message + `notifications/resources/updated` for
336
+ `mail://mailboxes/{account}` when new mail arrives (real-time IDLE where the server
337
+ supports it, polling fallback otherwise).
305
338
 
306
339
  As with SMTP, the password is read from the macOS **Keychain** by default (use
307
340
  an app-specific password for Gmail/Workspace/iCloud), so no secret goes in
@@ -309,10 +342,8 @@ config. Gmail label semantics: common names (`All Mail`, `Sent`, `Trash`,
309
342
  `Spam`, `Important`, …) map to their `[Gmail]/…` IMAP paths automatically.
310
343
 
311
344
  > Note: each call currently opens its own IMAP connection (no pooling yet), so
312
- > expect a few seconds of connection overhead per call. Phase 2 added the folder
313
- > ops (create/rename/delete-mailbox) — resolving the IMAP slice of
314
- > [#42](https://github.com/sweetrb/apple-mail-mcp/issues/42). IMAP-backed
315
- > message-level mutations are still future work (see #43).
345
+ > expect a few seconds of connection overhead per call the one remaining
346
+ > follow-up on [#43](https://github.com/sweetrb/apple-mail-mcp/issues/43).
316
347
  >
317
348
  > **iCloud:** set `APPLE_MAIL_MCP_IMAP_HOST=imap.mail.me.com`, `APPLE_MAIL_MCP_IMAP_USER`
318
349
  > to your iCloud address, `APPLE_MAIL_MCP_IMAP_ACCOUNT` to the Mail account name
@@ -368,10 +399,44 @@ Save an email to Drafts without sending.
368
399
  | `cc` | string[] | No | CC recipients |
369
400
  | `bcc` | string[] | No | BCC recipients |
370
401
  | `account` | string | No | Account for draft |
371
- | `attachments` | string[] | No | Absolute file paths to attach, max 20 files |
402
+ | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths and/or inline `{filename, contentBase64}` objects |
372
403
 
373
404
  **Returns:** Confirmation that draft was created.
374
405
 
406
+ #### `get-thread`
407
+
408
+ Group a conversation by normalized subject (across the AppleScript or IMAP backend).
409
+
410
+ | Parameter | Type | Required | Description |
411
+ |-----------|------|----------|-------------|
412
+ | `id` | string | Yes | A message ID in the conversation (numeric or `imap:…`) |
413
+ | `account` | string | No | Account to search (omit to search all) |
414
+ | `mailbox` | string | No | Mailbox to search (omit to search all) |
415
+ | `limit` | number | No | Max messages in the thread (default 50) |
416
+
417
+ **Returns:** The conversation's messages, oldest-first.
418
+
419
+ #### `fetch-attachment`
420
+
421
+ Return an attachment's bytes as base64 (the read counterpart to inline-base64 send).
422
+
423
+ | Parameter | Type | Required | Description |
424
+ |-----------|------|----------|-------------|
425
+ | `id` | string | Yes | Numeric message ID |
426
+ | `attachmentName` | string | Yes | Attachment filename (from `list-attachments`) |
427
+
428
+ **Returns:** The attachment bytes, base64-encoded (also in `structuredContent.contentBase64`).
429
+
430
+ #### `create-rule` / `delete-rule`
431
+
432
+ Create a Mail rule with conditions and actions, or delete a rule by name.
433
+
434
+ `create-rule` parameters: `name` (string), `conditions` (array of `{field: from|to|cc|subject|content, operator: contains|notContains|equals|beginsWith|endsWith, value}`), `actions` (`{markRead?, markFlagged?, delete?, moveTo?, moveToAccount?}`), `matchAll` (default true), `enabled` (default true). `delete-rule` parameters: `name`.
435
+
436
+ #### `doctor`
437
+
438
+ Run a full setup diagnostic: Mail.app automation permission, account state (flags disabled accounts), and each configured IMAP/SMTP backend, each reported as ok / warn / fail with an actionable message. No parameters.
439
+
375
440
  ---
376
441
 
377
442
  #### `reply-to-message`
@@ -848,8 +913,8 @@ The entrypoint is written as:
848
913
  | No sending HTML email | Emails are sent as plain text; reading HTML content is supported |
849
914
  | Attachments require absolute paths | File attachments must use full absolute paths (e.g., `/Users/me/file.pdf`) |
850
915
  | No smart mailboxes | Cannot access Smart Mailboxes via AppleScript |
851
- | Very large mailboxes not searchable | Apple Mail's AppleScript bridge times out on mailboxes with tens of thousands of messages, so unscoped `search-messages` skips mailboxes above `APPLE_MAIL_MAX_SEARCH_MAILBOX` (default 5000) and reports them as a partial result. Scope with `mailbox` + a date window to search inside one. ([#24](https://github.com/sweetrb/apple-mail-mcp/issues/24)) |
852
- | Can't delete/rename server-side mailboxes or mutate drafts | Mail.app's AppleScript bridge can only `delete`/`rename` **local "On My Mac"** mailboxes and cannot delete/move drafts — it throws `AppleEvent handler failed` for IMAP/Gmail/Workspace/iCloud/Exchange mailboxes and drafts (the GUI can do it). `delete-mailbox`/`rename-mailbox`/`delete-message`/`move-message` now return a clear "do it in Mail.app directly" error in that case instead of a generic failure. ([#42](https://github.com/sweetrb/apple-mail-mcp/issues/42)) |
916
+ | Very large mailboxes not searchable *via AppleScript* | Apple Mail's AppleScript bridge times out on mailboxes with tens of thousands of messages, so unscoped `search-messages` skips mailboxes above `APPLE_MAIL_MAX_SEARCH_MAILBOX` (default 5000) and reports them as a partial result. Scope with `mailbox` + a date window or configure the [IMAP backend](#imap-backend--opt-in), which searches these server-side in well under a second. ([#24](https://github.com/sweetrb/apple-mail-mcp/issues/24)) |
917
+ | Can't delete/rename server-side mailboxes or mutate drafts *via AppleScript* | Mail.app's AppleScript bridge can only `delete`/`rename` **local "On My Mac"** mailboxes and cannot delete/move drafts — it throws `AppleEvent handler failed` for IMAP/Gmail/Workspace/iCloud/Exchange mailboxes (the GUI can do it). Without IMAP configured, `delete-mailbox`/`rename-mailbox`/`delete-message`/`move-message` return a clear "do it in Mail.app directly" error instead of a generic failure. With the [IMAP backend](#imap-backend--opt-in) configured for the account, these operations run via IMAP and succeed. ([#42](https://github.com/sweetrb/apple-mail-mcp/issues/42)) |
853
918
  | In-memory templates | Email templates are not persisted across server restarts |
854
919
  | Numeric-only message IDs | Message IDs must contain only digits (validated by schema) |
855
920
  | Batch size cap | Batch operations are limited to 100 messages per request |