apple-mail-mcp 1.9.0 → 2.1.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.
- package/README.md +149 -14
- package/build/index.js +421 -228
- package/build/services/appleMailManager.d.ts +32 -7
- package/build/services/appleMailManager.d.ts.map +1 -1
- package/build/services/appleMailManager.js +256 -104
- package/build/services/imapClient.d.ts +158 -34
- package/build/services/imapClient.d.ts.map +1 -1
- package/build/services/imapClient.js +567 -45
- package/build/services/imapIdle.d.ts +58 -0
- package/build/services/imapIdle.d.ts.map +1 -0
- package/build/services/imapIdle.js +145 -0
- package/build/services/messageRouter.d.ts +16 -0
- package/build/services/messageRouter.d.ts.map +1 -0
- package/build/services/messageRouter.js +29 -0
- package/build/services/smtpMailer.d.ts +3 -2
- package/build/services/smtpMailer.d.ts.map +1 -1
- package/build/services/smtpMailer.js +11 -7
- package/build/services/templateStore.d.ts +18 -0
- package/build/services/templateStore.d.ts.map +1 -0
- package/build/services/templateStore.js +91 -0
- package/build/tools/doctor.d.ts +23 -0
- package/build/tools/doctor.d.ts.map +1 -0
- package/build/tools/doctor.js +74 -0
- package/build/tools/resourcesAndPrompts.d.ts +14 -0
- package/build/tools/resourcesAndPrompts.d.ts.map +1 -0
- package/build/tools/resourcesAndPrompts.js +109 -0
- package/build/tools/respond.d.ts +48 -0
- package/build/tools/respond.d.ts.map +1 -0
- package/build/tools/respond.js +95 -0
- package/build/tools/thread.d.ts +19 -0
- package/build/tools/thread.d.ts.map +1 -0
- package/build/tools/thread.js +32 -0
- package/build/types.d.ts +38 -0
- package/build/types.d.ts.map +1 -1
- package/build/utils/attachmentMaterialize.d.ts +9 -0
- package/build/utils/attachmentMaterialize.d.ts.map +1 -0
- package/build/utils/attachmentMaterialize.js +38 -0
- 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 (
|
|
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 (
|
|
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 |
|
|
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:**
|
|
@@ -287,14 +299,17 @@ What routes to IMAP when an account is IMAP-configured:
|
|
|
287
299
|
- **Read:** `search-messages`, `list-messages` (server-side `SEARCH`, typically sub-second), and `get-message`.
|
|
288
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).
|
|
289
301
|
- **Message mutations:** `mark-as-read`/`unread`, `flag-message`/`unflag-message`, `move-message`, `delete-message`.
|
|
302
|
+
- **Batch mutations (2.1):** `batch-mark-as-read`/`unread`, `batch-flag`/`unflag-messages`, `batch-move-messages`, `batch-delete-messages` — `imap:` ids are grouped by mailbox and applied as a single `UID STORE`/`UID MOVE`; numeric ids in the same batch still use AppleScript.
|
|
303
|
+
- **Counts & stats (2.1):** `get-unread-count` and `list-mailboxes` use `STATUS`; `get-mail-stats` (with an `account`) uses `STATUS` + `SEARCH SINCE` — authoritative and fast even on huge mailboxes.
|
|
304
|
+
- **Attachments (2.1):** `list-attachments`, `save-attachment`, `fetch-attachment` use `BODYSTRUCTURE` + `FETCH BODY[part]` for `imap:` ids — faster and able to see MIME-embedded attachments AppleScript misses.
|
|
305
|
+
- **Threading (2.1):** `get-thread` links a conversation via `References`/`Message-ID` (`HEADER SEARCH`) for an `imap:` seed, falling back to subject grouping otherwise.
|
|
290
306
|
|
|
291
307
|
**Message ids are backend-tagged.** The IMAP read path emits self-describing ids
|
|
292
308
|
of the form `imap:<token>` (the token encodes the account, mailbox path, and
|
|
293
|
-
UID). Pass that id back to `get-message
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
tools for IMAP ids.)
|
|
309
|
+
UID). Pass that id back to `get-message`, a message mutation, a batch op, or the
|
|
310
|
+
attachment/thread tools and it routes to IMAP automatically; bare numeric ids
|
|
311
|
+
continue to use AppleScript. So an agent never has to know which backend a
|
|
312
|
+
message came from — the id carries it.
|
|
298
313
|
|
|
299
314
|
Routing is conservative: only a call whose explicit `account` matches the
|
|
300
315
|
configured IMAP account goes to IMAP; everything else falls through to
|
|
@@ -309,21 +324,72 @@ AppleScript.
|
|
|
309
324
|
| `APPLE_MAIL_MCP_IMAP_PASSWORD` | No | — | Password (if set, used instead of the Keychain) |
|
|
310
325
|
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE` | No | — | Keychain item service/server name |
|
|
311
326
|
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT` | No | = user | Keychain item account |
|
|
327
|
+
| `APPLE_MAIL_MCP_IMAP_ACCOUNTS` | No | — | JSON array of **additional** IMAP accounts for multi-account setups (see below) |
|
|
328
|
+
| `APPLE_MAIL_MCP_IMAP_IDLE` | No | `0` | Set `1` to enable IMAP IDLE push notifications (new-mail alerts) for every configured account |
|
|
329
|
+
| `APPLE_MAIL_MCP_IMAP_IDLE_MS` | No | `60000` | Idle timeout (ms) before a pooled IMAP connection is closed |
|
|
330
|
+
|
|
331
|
+
**Multiple IMAP accounts (C2):** set `APPLE_MAIL_MCP_IMAP_ACCOUNTS` to a JSON array, e.g.
|
|
332
|
+
`[{"account":"Work","user":"me@co.com","host":"imap.co.com","keychainService":"imap.co.com"}]`.
|
|
333
|
+
Each entry accepts `account`, `user`, `host`, `port`, `password`, `keychainService`,
|
|
334
|
+
`keychainAccount`. Calls route to the account matching their `account` argument (or the
|
|
335
|
+
decoded `imap:` id), and each account keeps its own pooled connection.
|
|
312
336
|
|
|
313
337
|
As with SMTP, the password is read from the macOS **Keychain** by default (use
|
|
314
338
|
an app-specific password for Gmail/Workspace/iCloud), so no secret goes in
|
|
315
339
|
config. Gmail label semantics: common names (`All Mail`, `Sent`, `Trash`,
|
|
316
340
|
`Spam`, `Important`, …) map to their `[Gmail]/…` IMAP paths automatically.
|
|
317
341
|
|
|
318
|
-
> Note:
|
|
319
|
-
>
|
|
320
|
-
>
|
|
342
|
+
> Note: IMAP connections are pooled — one kept-alive connection per account is
|
|
343
|
+
> reused across calls (verified with a NOOP, closed after `APPLE_MAIL_MCP_IMAP_IDLE_MS`
|
|
344
|
+
> of inactivity), so there's no per-call connection overhead ([#50](https://github.com/sweetrb/apple-mail-mcp/issues/50)).
|
|
321
345
|
>
|
|
322
346
|
> **iCloud:** set `APPLE_MAIL_MCP_IMAP_HOST=imap.mail.me.com`, `APPLE_MAIL_MCP_IMAP_USER`
|
|
323
347
|
> to your iCloud address, `APPLE_MAIL_MCP_IMAP_ACCOUNT` to the Mail account name
|
|
324
348
|
> (e.g. `iCloud`), and use an **app-specific password** (from appleid.apple.com)
|
|
325
349
|
> stored in the Keychain.
|
|
326
350
|
|
|
351
|
+
##### Push notifications (IMAP IDLE) — opt-in
|
|
352
|
+
|
|
353
|
+
When `APPLE_MAIL_MCP_IMAP_IDLE=1`, the server opens a dedicated, long-lived
|
|
354
|
+
connection to **each configured IMAP account** and watches its INBOX for new
|
|
355
|
+
mail. On arrival it pushes two MCP notifications to the client (no polling by the
|
|
356
|
+
client required):
|
|
357
|
+
|
|
358
|
+
1. **`notifications/message`** (logging) — a human-readable line, e.g.
|
|
359
|
+
`New mail in "Work": 2 new message(s) (INBOX now 1843).`
|
|
360
|
+
2. **`notifications/resources/updated`** — for the affected account's resource
|
|
361
|
+
`mail://mailboxes/{account}`, so a client subscribed to that resource knows to
|
|
362
|
+
re-read it.
|
|
363
|
+
|
|
364
|
+
This requires an IMAP account to be configured (single-account env or
|
|
365
|
+
`APPLE_MAIL_MCP_IMAP_ACCOUNTS`); accounts that only use AppleScript aren't
|
|
366
|
+
watched. Detection is **real-time** via the IMAP IDLE `EXISTS` event where the
|
|
367
|
+
server pushes it, with an automatic **polling fallback** for servers that don't.
|
|
368
|
+
Dropped connections reconnect with backoff, and the watchers shut down cleanly on
|
|
369
|
+
`SIGINT`/`SIGTERM`.
|
|
370
|
+
|
|
371
|
+
Enable it in your MCP client config alongside the IMAP settings:
|
|
372
|
+
|
|
373
|
+
```jsonc
|
|
374
|
+
{
|
|
375
|
+
"mcpServers": {
|
|
376
|
+
"apple-mail": {
|
|
377
|
+
"command": "node",
|
|
378
|
+
"args": ["/path/to/apple-mail-mcp/build/index.js"],
|
|
379
|
+
"env": {
|
|
380
|
+
"APPLE_MAIL_MCP_IMAP_USER": "you@gmail.com",
|
|
381
|
+
"APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE": "imap.gmail.com",
|
|
382
|
+
"APPLE_MAIL_MCP_IMAP_IDLE": "1"
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
> Note: this is most useful with clients that surface MCP logging messages or
|
|
390
|
+
> subscribe to resource-update notifications. Clients that ignore notifications
|
|
391
|
+
> are unaffected — the feature is opt-in and adds no behavior unless enabled.
|
|
392
|
+
|
|
327
393
|
---
|
|
328
394
|
|
|
329
395
|
#### `send-serial-email`
|
|
@@ -373,10 +439,34 @@ Save an email to Drafts without sending.
|
|
|
373
439
|
| `cc` | string[] | No | CC recipients |
|
|
374
440
|
| `bcc` | string[] | No | BCC recipients |
|
|
375
441
|
| `account` | string | No | Account for draft |
|
|
376
|
-
| `attachments` | string[] | No |
|
|
442
|
+
| `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths and/or inline `{filename, contentBase64}` objects |
|
|
377
443
|
|
|
378
444
|
**Returns:** Confirmation that draft was created.
|
|
379
445
|
|
|
446
|
+
#### `get-thread`
|
|
447
|
+
|
|
448
|
+
Group a conversation by normalized subject (across the AppleScript or IMAP backend).
|
|
449
|
+
|
|
450
|
+
| Parameter | Type | Required | Description |
|
|
451
|
+
|-----------|------|----------|-------------|
|
|
452
|
+
| `id` | string | Yes | A message ID in the conversation (numeric or `imap:…`) |
|
|
453
|
+
| `account` | string | No | Account to search (omit to search all) |
|
|
454
|
+
| `mailbox` | string | No | Mailbox to search (omit to search all) |
|
|
455
|
+
| `limit` | number | No | Max messages in the thread (default 50) |
|
|
456
|
+
|
|
457
|
+
**Returns:** The conversation's messages, oldest-first.
|
|
458
|
+
|
|
459
|
+
#### `fetch-attachment`
|
|
460
|
+
|
|
461
|
+
Return an attachment's bytes as base64 (the read counterpart to inline-base64 send).
|
|
462
|
+
|
|
463
|
+
| Parameter | Type | Required | Description |
|
|
464
|
+
|-----------|------|----------|-------------|
|
|
465
|
+
| `id` | string | Yes | Numeric message ID |
|
|
466
|
+
| `attachmentName` | string | Yes | Attachment filename (from `list-attachments`) |
|
|
467
|
+
|
|
468
|
+
**Returns:** The attachment bytes, base64-encoded (also in `structuredContent.contentBase64`).
|
|
469
|
+
|
|
380
470
|
---
|
|
381
471
|
|
|
382
472
|
#### `reply-to-message`
|
|
@@ -614,6 +704,41 @@ Enable or disable a mail rule.
|
|
|
614
704
|
|
|
615
705
|
---
|
|
616
706
|
|
|
707
|
+
#### `create-rule`
|
|
708
|
+
|
|
709
|
+
Create a Mail rule with one or more conditions and actions.
|
|
710
|
+
|
|
711
|
+
| Parameter | Type | Required | Description |
|
|
712
|
+
|-----------|------|----------|-------------|
|
|
713
|
+
| `name` | string | Yes | Rule name (must be unique) |
|
|
714
|
+
| `conditions` | object[] | Yes | One or more `{field, operator, value}` (see below) |
|
|
715
|
+
| `actions` | object | Yes | At least one of `markRead`, `markFlagged`, `delete`, `moveTo` |
|
|
716
|
+
| `matchAll` | boolean | No | `true` (default) = all conditions must match; `false` = any |
|
|
717
|
+
| `enabled` | boolean | No | Whether the rule is enabled on creation (default `true`) |
|
|
718
|
+
|
|
719
|
+
Each condition is `{ field, operator, value }` where `field` is one of `from`, `to`, `cc`, `subject`, `content` and `operator` is one of `contains`, `notContains`, `equals`, `beginsWith`, `endsWith`. Actions: `markRead` / `markFlagged` / `delete` (booleans), `moveTo` (mailbox name) with optional `moveToAccount`.
|
|
720
|
+
|
|
721
|
+
**Example:**
|
|
722
|
+
```json
|
|
723
|
+
{
|
|
724
|
+
"name": "Newsletters",
|
|
725
|
+
"conditions": [{ "field": "from", "operator": "contains", "value": "newsletter" }],
|
|
726
|
+
"actions": { "markRead": true, "moveTo": "Reading" }
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
#### `delete-rule`
|
|
733
|
+
|
|
734
|
+
Delete a mail rule by name.
|
|
735
|
+
|
|
736
|
+
| Parameter | Type | Required | Description |
|
|
737
|
+
|-----------|------|----------|-------------|
|
|
738
|
+
| `name` | string | Yes | Rule name |
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
617
742
|
### Contacts
|
|
618
743
|
|
|
619
744
|
#### `search-contacts`
|
|
@@ -631,7 +756,7 @@ Search contacts in Contacts.app.
|
|
|
631
756
|
|
|
632
757
|
### Templates
|
|
633
758
|
|
|
634
|
-
Email templates are
|
|
759
|
+
Email templates are **persisted to disk** so they survive server restarts, stored as JSON at `APPLE_MAIL_MCP_TEMPLATES_FILE` (default `~/Library/Application Support/apple-mail-mcp/templates.json`).
|
|
635
760
|
|
|
636
761
|
#### `save-template`
|
|
637
762
|
|
|
@@ -702,6 +827,16 @@ Verify Mail.app connectivity and permissions.
|
|
|
702
827
|
|
|
703
828
|
---
|
|
704
829
|
|
|
830
|
+
#### `doctor`
|
|
831
|
+
|
|
832
|
+
Run a full setup diagnostic: Mail.app automation permission, account state (flagging disabled accounts), and each configured IMAP/SMTP backend — each reported as ok / warn / fail with an actionable message.
|
|
833
|
+
|
|
834
|
+
**Parameters:** None
|
|
835
|
+
|
|
836
|
+
**Returns:** A per-check report (`structuredContent` carries the raw `{healthy, checks[]}`).
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
705
840
|
#### `get-mail-stats`
|
|
706
841
|
|
|
707
842
|
Get mail statistics.
|