apple-mail-mcp 1.2.1 → 1.4.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 +16 -6
- package/build/index.js +11 -2
- package/build/services/appleMailManager.d.ts.map +1 -1
- package/build/services/appleMailManager.js +105 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ Search for messages matching criteria. Searches all accounts by default.
|
|
|
139
139
|
| `query` | string | No | Text to search in subject/sender |
|
|
140
140
|
| `from` | string | No | Filter by sender email address |
|
|
141
141
|
| `subject` | string | No | Filter by subject line |
|
|
142
|
-
| `mailbox` | string | No | Mailbox to search in (
|
|
142
|
+
| `mailbox` | string | No | Mailbox to search in (omit to search all mailboxes) |
|
|
143
143
|
| `account` | string | No | Account to search in (omit to search all accounts) |
|
|
144
144
|
| `isRead` | boolean | No | Filter by read status |
|
|
145
145
|
| `isFlagged` | boolean | No | Filter by flagged status |
|
|
@@ -168,7 +168,7 @@ List messages in a mailbox.
|
|
|
168
168
|
|
|
169
169
|
| Parameter | Type | Required | Description |
|
|
170
170
|
|-----------|------|----------|-------------|
|
|
171
|
-
| `mailbox` | string | No | Mailbox name (
|
|
171
|
+
| `mailbox` | string | No | Mailbox name (omit to list from all mailboxes) |
|
|
172
172
|
| `account` | string | No | Account name |
|
|
173
173
|
| `limit` | number | No | Max messages (default: 50) |
|
|
174
174
|
| `offset` | number | No | Number of messages to skip (for pagination) |
|
|
@@ -608,12 +608,12 @@ Check Mail.app sync activity.
|
|
|
608
608
|
|
|
609
609
|
```
|
|
610
610
|
User: "Check my inbox for new emails"
|
|
611
|
-
AI: [calls list-messages
|
|
612
|
-
"You have 12 messages
|
|
611
|
+
AI: [calls list-messages]
|
|
612
|
+
"You have 12 messages. Here are the most recent..."
|
|
613
613
|
|
|
614
614
|
User: "Show me emails from Sarah"
|
|
615
615
|
AI: [calls search-messages with query="Sarah"]
|
|
616
|
-
"Found 3 emails from Sarah..."
|
|
616
|
+
"Found 3 emails from Sarah across all mailboxes..."
|
|
617
617
|
|
|
618
618
|
User: "Read the first one"
|
|
619
619
|
AI: [calls get-message with id="..."]
|
|
@@ -720,10 +720,20 @@ If installed from source, use this configuration:
|
|
|
720
720
|
| In-memory templates | Email templates are not persisted across server restarts |
|
|
721
721
|
| Numeric-only message IDs | Message IDs must contain only digits (validated by schema) |
|
|
722
722
|
| Batch size cap | Batch operations are limited to 100 messages per request |
|
|
723
|
-
| Date filter format | Date filters
|
|
723
|
+
| Date filter format | Date filters must be valid parseable dates (e.g., "January 1, 2026" or "2026-03-15"); bare numbers or non-date strings are rejected |
|
|
724
724
|
| Attachment save path restrictions | `save-attachment` only allows saving to home directory, `/tmp`, `/private/tmp`, and `/Volumes`; path traversal is blocked |
|
|
725
725
|
| Attachment count limit | `send-email` and `create-draft` accept a maximum of 20 file attachments |
|
|
726
726
|
|
|
727
|
+
### Reply / Forward from Background Processes (Fixed in v1.4.0)
|
|
728
|
+
|
|
729
|
+
Prior to v1.4.0, `reply-to-message` and `forward-message` would send messages with **empty body text** when the MCP server ran as a background process (e.g., spawned via `execSync` from Node.js, which is how Claude Code invokes it).
|
|
730
|
+
|
|
731
|
+
**Root cause:** The AppleScript `reply msg with opening window` command creates a GUI compose window asynchronously. When `set content` runs immediately after, the window may not be ready, and the content assignment is silently ignored. Delays (`delay 1`, `delay 2`) were unreliable — the compose window's readiness depends on system load, Mail.app state, and whether the process has GUI access.
|
|
732
|
+
|
|
733
|
+
**Fix:** Replaced `with opening window` with `without opening window` for both `reply` and `forward` commands. With this approach, `set content` works immediately and reliably from background processes. `In-Reply-To` and `References` headers are still set correctly by Mail.app, and no GUI compose window is opened.
|
|
734
|
+
|
|
735
|
+
See [#7](https://github.com/sweetrb/apple-mail-mcp/issues/7) for full details and the list of approaches that were tested.
|
|
736
|
+
|
|
727
737
|
### Backslash Escaping (Important for AI Agents)
|
|
728
738
|
|
|
729
739
|
When sending content containing backslashes (`\`) to this MCP server, **you must escape them as `\\`** in the JSON parameters.
|
package/build/index.js
CHANGED
|
@@ -40,6 +40,9 @@ const BATCH_IDS_SCHEMA = z
|
|
|
40
40
|
const DATE_FILTER_SCHEMA = z
|
|
41
41
|
.string()
|
|
42
42
|
.regex(/^[a-zA-Z0-9 ,/\-:]+$/, "Date must contain only alphanumeric characters, spaces, commas, slashes, hyphens, and colons")
|
|
43
|
+
.refine((val) => !isNaN(new Date(val).getTime()), {
|
|
44
|
+
message: "Date string must be a valid date (e.g., 'January 1, 2026' or '2026-03-15')",
|
|
45
|
+
})
|
|
43
46
|
.optional();
|
|
44
47
|
// Read version from package.json to keep it in sync
|
|
45
48
|
const require = createRequire(import.meta.url);
|
|
@@ -102,7 +105,10 @@ server.tool("search-messages", {
|
|
|
102
105
|
query: z.string().optional().describe("Text to search for in subject, sender, or content"),
|
|
103
106
|
from: z.string().optional().describe("Filter by sender email address"),
|
|
104
107
|
subject: z.string().optional().describe("Filter by subject line"),
|
|
105
|
-
mailbox: z
|
|
108
|
+
mailbox: z
|
|
109
|
+
.string()
|
|
110
|
+
.optional()
|
|
111
|
+
.describe("Mailbox to search in (e.g., 'INBOX'). Omit to search all mailboxes."),
|
|
106
112
|
account: z.string().optional().describe("Account to search in (omit to search all accounts)"),
|
|
107
113
|
isRead: z.boolean().optional().describe("Filter by read status"),
|
|
108
114
|
isFlagged: z.boolean().optional().describe("Filter by flagged status"),
|
|
@@ -135,7 +141,10 @@ server.tool("get-message", {
|
|
|
135
141
|
}, "Error retrieving message"));
|
|
136
142
|
// --- list-messages ---
|
|
137
143
|
server.tool("list-messages", {
|
|
138
|
-
mailbox: z
|
|
144
|
+
mailbox: z
|
|
145
|
+
.string()
|
|
146
|
+
.optional()
|
|
147
|
+
.describe("Mailbox to list messages from. Omit to list from all mailboxes."),
|
|
139
148
|
account: z.string().optional().describe("Account to list messages from"),
|
|
140
149
|
limit: z.number().optional().describe("Maximum number of messages (default: 50)"),
|
|
141
150
|
offset: z.number().optional().describe("Number of messages to skip (for pagination)"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,OAAO,EACP,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,SAAS,EAET,oBAAoB,EACpB,UAAU,EACV,qBAAqB,EACrB,QAAQ,EACR,OAAO,EACP,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AA6HpB;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,OAAO,CAAC,cAAc,CAAuB;IAE7C;;;;OAIG;IACH,OAAO,CAAC,KAAK,CAGX;IAEF,8CAA8C;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IAEvC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAW7B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAKvB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAwCtB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,cAAc;IAyCtB;;;;;;;;OAQG;IACH,cAAc,CACZ,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,SAAK,EACV,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,EAAE;
|
|
1
|
+
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -303,8 +303,6 @@ export class AppleMailManager {
|
|
|
303
303
|
return allMessages.slice(0, limit);
|
|
304
304
|
}
|
|
305
305
|
const targetAccount = this.resolveAccount(account);
|
|
306
|
-
const requestedMailbox = mailbox || "INBOX";
|
|
307
|
-
const targetMailbox = this.resolveMailbox(requestedMailbox, targetAccount);
|
|
308
306
|
// Build the search condition
|
|
309
307
|
let searchCondition = "";
|
|
310
308
|
if (query) {
|
|
@@ -326,7 +324,11 @@ export class AppleMailManager {
|
|
|
326
324
|
}
|
|
327
325
|
dateFilter = dateChecks.join(" and ");
|
|
328
326
|
}
|
|
329
|
-
|
|
327
|
+
let searchCommand;
|
|
328
|
+
if (mailbox) {
|
|
329
|
+
// Search a specific mailbox
|
|
330
|
+
const targetMailbox = this.resolveMailbox(mailbox, targetAccount);
|
|
331
|
+
searchCommand = `
|
|
330
332
|
set outputText to ""
|
|
331
333
|
set theMailbox to mailbox "${escapeForAppleScript(targetMailbox)}"
|
|
332
334
|
set allMessages to messages of theMailbox ${searchCondition}
|
|
@@ -350,6 +352,42 @@ export class AppleMailManager {
|
|
|
350
352
|
end repeat
|
|
351
353
|
return outputText
|
|
352
354
|
`;
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
// Search ALL mailboxes — iterate every mailbox in the account, dedup by message ID
|
|
358
|
+
searchCommand = `
|
|
359
|
+
set outputText to ""
|
|
360
|
+
set msgCount to 0
|
|
361
|
+
set seenIds to {}
|
|
362
|
+
repeat with mb in mailboxes
|
|
363
|
+
if msgCount >= ${limit} then exit repeat
|
|
364
|
+
try
|
|
365
|
+
set allMessages to messages of mb ${searchCondition}
|
|
366
|
+
repeat with msg in allMessages
|
|
367
|
+
if msgCount >= ${limit} then exit repeat
|
|
368
|
+
try
|
|
369
|
+
set msgId to id of msg as string
|
|
370
|
+
if seenIds does not contain msgId then
|
|
371
|
+
set end of seenIds to msgId
|
|
372
|
+
${dateFilter ? `set msgDate to date received of msg\n if not (${dateFilter}) then\n -- skip message outside date range\n else` : ""}
|
|
373
|
+
set msgSubject to subject of msg
|
|
374
|
+
set msgSender to sender of msg
|
|
375
|
+
set d to date received of msg
|
|
376
|
+
set msgDateStr to ${AS_DATE_TO_STRING}
|
|
377
|
+
set msgRead to read status of msg as string
|
|
378
|
+
set msgFlagged to flagged status of msg as string
|
|
379
|
+
if msgCount > 0 then set outputText to outputText & "|||ITEM|||"
|
|
380
|
+
set outputText to outputText & msgId & "|||" & msgSubject & "|||" & msgSender & "|||" & msgDateStr & "|||" & msgRead & "|||" & msgFlagged & "|||" & name of mb
|
|
381
|
+
set msgCount to msgCount + 1
|
|
382
|
+
${dateFilter ? "end if" : ""}
|
|
383
|
+
end if
|
|
384
|
+
end try
|
|
385
|
+
end repeat
|
|
386
|
+
end try
|
|
387
|
+
end repeat
|
|
388
|
+
return outputText
|
|
389
|
+
`;
|
|
390
|
+
}
|
|
353
391
|
const script = buildAccountScopedScript(targetAccount, searchCommand);
|
|
354
392
|
const result = executeAppleScript(script, { timeoutMs: 60000 });
|
|
355
393
|
if (!result.success) {
|
|
@@ -358,7 +396,7 @@ export class AppleMailManager {
|
|
|
358
396
|
}
|
|
359
397
|
if (!result.output.trim())
|
|
360
398
|
return [];
|
|
361
|
-
return this.parseMessageList(result.output,
|
|
399
|
+
return this.parseMessageList(result.output, mailbox || "INBOX", targetAccount);
|
|
362
400
|
}
|
|
363
401
|
/**
|
|
364
402
|
* Get a message by ID.
|
|
@@ -473,12 +511,27 @@ export class AppleMailManager {
|
|
|
473
511
|
* @returns Array of messages
|
|
474
512
|
*/
|
|
475
513
|
listMessages(mailbox, account, limit = 50, from, offset = 0) {
|
|
514
|
+
// If no account specified, list across all accounts
|
|
515
|
+
if (!account) {
|
|
516
|
+
const accounts = this.listAccounts();
|
|
517
|
+
const allMessages = [];
|
|
518
|
+
for (const acct of accounts) {
|
|
519
|
+
if (allMessages.length >= limit)
|
|
520
|
+
break;
|
|
521
|
+
const remaining = limit - allMessages.length;
|
|
522
|
+
const msgs = this.listMessages(mailbox, acct.name, remaining, from, offset);
|
|
523
|
+
allMessages.push(...msgs);
|
|
524
|
+
}
|
|
525
|
+
return allMessages.slice(0, limit);
|
|
526
|
+
}
|
|
476
527
|
const targetAccount = this.resolveAccount(account);
|
|
477
|
-
const requestedMailbox = mailbox || "INBOX";
|
|
478
|
-
const targetMailbox = this.resolveMailbox(requestedMailbox, targetAccount);
|
|
479
528
|
const safeFrom = from ? escapeForAppleScript(from) : "";
|
|
480
529
|
const fromFilter = from ? `whose sender contains "${safeFrom}"` : "";
|
|
481
|
-
|
|
530
|
+
let listCommand;
|
|
531
|
+
if (mailbox) {
|
|
532
|
+
// List from a specific mailbox
|
|
533
|
+
const targetMailbox = this.resolveMailbox(mailbox, targetAccount);
|
|
534
|
+
listCommand = `
|
|
482
535
|
set outputText to ""
|
|
483
536
|
set theMailbox to mailbox "${escapeForAppleScript(targetMailbox)}"
|
|
484
537
|
set msgCount to 0
|
|
@@ -504,15 +557,53 @@ export class AppleMailManager {
|
|
|
504
557
|
end repeat
|
|
505
558
|
return outputText
|
|
506
559
|
`;
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
// List from ALL mailboxes — iterate every mailbox in the account, dedup by message ID
|
|
563
|
+
listCommand = `
|
|
564
|
+
set outputText to ""
|
|
565
|
+
set msgCount to 0
|
|
566
|
+
set skipped to 0
|
|
567
|
+
set seenIds to {}
|
|
568
|
+
repeat with mb in mailboxes
|
|
569
|
+
if msgCount >= ${limit} then exit repeat
|
|
570
|
+
try
|
|
571
|
+
repeat with msg in messages of mb ${fromFilter}
|
|
572
|
+
if msgCount >= ${limit} then exit repeat
|
|
573
|
+
try
|
|
574
|
+
set msgId to id of msg as string
|
|
575
|
+
if seenIds does not contain msgId then
|
|
576
|
+
set end of seenIds to msgId
|
|
577
|
+
if skipped < ${offset} then
|
|
578
|
+
set skipped to skipped + 1
|
|
579
|
+
else
|
|
580
|
+
set msgSubject to subject of msg
|
|
581
|
+
set msgSender to sender of msg
|
|
582
|
+
set d to date received of msg
|
|
583
|
+
set msgDate to ${AS_DATE_TO_STRING}
|
|
584
|
+
set msgRead to read status of msg as string
|
|
585
|
+
set msgFlagged to flagged status of msg as string
|
|
586
|
+
if msgCount > 0 then set outputText to outputText & "|||ITEM|||"
|
|
587
|
+
set outputText to outputText & msgId & "|||" & msgSubject & "|||" & msgSender & "|||" & msgDate & "|||" & msgRead & "|||" & msgFlagged & "|||" & name of mb
|
|
588
|
+
set msgCount to msgCount + 1
|
|
589
|
+
end if
|
|
590
|
+
end if
|
|
591
|
+
end try
|
|
592
|
+
end repeat
|
|
593
|
+
end try
|
|
594
|
+
end repeat
|
|
595
|
+
return outputText
|
|
596
|
+
`;
|
|
597
|
+
}
|
|
507
598
|
const script = buildAccountScopedScript(targetAccount, listCommand);
|
|
508
|
-
const result = executeAppleScript(script);
|
|
599
|
+
const result = executeAppleScript(script, { timeoutMs: 60000 });
|
|
509
600
|
if (!result.success) {
|
|
510
601
|
console.error(`Failed to list messages: ${result.error}`);
|
|
511
602
|
return [];
|
|
512
603
|
}
|
|
513
604
|
if (!result.output.trim())
|
|
514
605
|
return [];
|
|
515
|
-
return this.parseMessageList(result.output,
|
|
606
|
+
return this.parseMessageList(result.output, mailbox || "INBOX", targetAccount);
|
|
516
607
|
}
|
|
517
608
|
/**
|
|
518
609
|
* Parse message list output from AppleScript.
|
|
@@ -534,7 +625,7 @@ export class AppleMailManager {
|
|
|
534
625
|
isFlagged: parts[5] === "true",
|
|
535
626
|
isJunk: false,
|
|
536
627
|
isDeleted: false,
|
|
537
|
-
mailbox,
|
|
628
|
+
mailbox: parts.length >= 7 ? parts[6] : mailbox,
|
|
538
629
|
account,
|
|
539
630
|
hasAttachments: false,
|
|
540
631
|
});
|
|
@@ -735,8 +826,8 @@ export class AppleMailManager {
|
|
|
735
826
|
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
736
827
|
if (count of matchingMsgs) > 0 then
|
|
737
828
|
set msg to item 1 of matchingMsgs
|
|
738
|
-
set theReply to reply msg
|
|
739
|
-
set content of theReply to "${safeBody}"
|
|
829
|
+
set theReply to reply msg without opening window${replyAllClause}
|
|
830
|
+
set content of theReply to "${safeBody}"
|
|
740
831
|
${sendAction}
|
|
741
832
|
return "ok"
|
|
742
833
|
end if
|
|
@@ -780,9 +871,9 @@ export class AppleMailManager {
|
|
|
780
871
|
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
781
872
|
if (count of matchingMsgs) > 0 then
|
|
782
873
|
set msg to item 1 of matchingMsgs
|
|
783
|
-
set theForward to forward msg
|
|
874
|
+
set theForward to forward msg without opening window
|
|
784
875
|
${recipientCommands}
|
|
785
|
-
${safeBody ? `set content of theForward to "${safeBody}"
|
|
876
|
+
${safeBody ? `set content of theForward to "${safeBody}"` : ""}
|
|
786
877
|
${sendAction}
|
|
787
878
|
return "ok"
|
|
788
879
|
end if
|