apple-mail-mcp 1.5.1 → 1.5.2
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
CHANGED
|
@@ -823,4 +823,6 @@ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for gui
|
|
|
823
823
|
|
|
824
824
|
## Related Projects
|
|
825
825
|
|
|
826
|
-
- [apple-notes-mcp](https://github.com/sweetrb/apple-notes-mcp)
|
|
826
|
+
- [apple-notes-mcp](https://github.com/sweetrb/apple-notes-mcp) — MCP server for Apple Notes
|
|
827
|
+
- [apple-numbers-mcp](https://github.com/sweetrb/apple-numbers-mcp) — MCP server for Apple Numbers spreadsheets
|
|
828
|
+
- [apple-photos-mcp](https://github.com/sweetrb/apple-photos-mcp) — MCP server for Apple Photos
|
package/build/index.js
CHANGED
|
@@ -103,8 +103,11 @@ function withErrorHandling(handler, errorPrefix) {
|
|
|
103
103
|
// --- search-messages ---
|
|
104
104
|
server.tool("search-messages", {
|
|
105
105
|
query: z.string().optional().describe("Text to search for in subject, sender, or content"),
|
|
106
|
-
from: z
|
|
107
|
-
|
|
106
|
+
from: z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe("Filter by sender (substring match against the full sender string, i.e. display name + address — not an exact address match)"),
|
|
110
|
+
subject: z.string().optional().describe("Filter by subject line (substring match)"),
|
|
108
111
|
mailbox: z
|
|
109
112
|
.string()
|
|
110
113
|
.optional()
|
|
@@ -115,8 +118,8 @@ server.tool("search-messages", {
|
|
|
115
118
|
dateFrom: DATE_FILTER_SCHEMA.describe("Start date filter (e.g., 'January 1, 2026')"),
|
|
116
119
|
dateTo: DATE_FILTER_SCHEMA.describe("End date filter (e.g., 'March 1, 2026')"),
|
|
117
120
|
limit: z.number().optional().describe("Maximum number of results (default: 50)"),
|
|
118
|
-
}, withErrorHandling(({ query, mailbox, account, limit = 50, dateFrom, dateTo }) => {
|
|
119
|
-
const messages = mailManager.searchMessages(query, mailbox, account, limit, dateFrom, dateTo);
|
|
121
|
+
}, withErrorHandling(({ query, mailbox, account, limit = 50, dateFrom, dateTo, from, subject, isRead, isFlagged, }) => {
|
|
122
|
+
const messages = mailManager.searchMessages(query, mailbox, account, limit, dateFrom, dateTo, from, subject, isRead, isFlagged);
|
|
120
123
|
if (messages.length === 0) {
|
|
121
124
|
return successResponse("No messages found matching criteria");
|
|
122
125
|
}
|
|
@@ -26,6 +26,27 @@ import type { Message, MessageContent, Mailbox, Account, Attachment, HealthCheck
|
|
|
26
26
|
* execution via osascript. Error handling is consistent: methods
|
|
27
27
|
* return null/false/empty-array on failure rather than throwing.
|
|
28
28
|
*/
|
|
29
|
+
export interface SearchConditionFilters {
|
|
30
|
+
query?: string;
|
|
31
|
+
from?: string;
|
|
32
|
+
subject?: string;
|
|
33
|
+
isRead?: boolean;
|
|
34
|
+
isFlagged?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the AppleScript `whose` clause for searchMessages from a filter set.
|
|
38
|
+
*
|
|
39
|
+
* - `query` is a subject-OR-sender substring match, parenthesized so it groups
|
|
40
|
+
* correctly when ANDed with other filters.
|
|
41
|
+
* - `from` and `subject` are substring matches (`sender`/`subject` contains).
|
|
42
|
+
* - `isRead` / `isFlagged` are boolean status checks.
|
|
43
|
+
* - Returns "" when no filters are set. Every interpolated value is escaped.
|
|
44
|
+
*
|
|
45
|
+
* Exported for unit testing: the bug this addresses (filters declared in the
|
|
46
|
+
* tool schema but silently dropped) lived in this logic, so it gets direct
|
|
47
|
+
* coverage independent of Mail.app.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildSearchCondition(filters: SearchConditionFilters): string;
|
|
29
50
|
export declare class AppleMailManager {
|
|
30
51
|
/**
|
|
31
52
|
* Default account used when no account is specified.
|
|
@@ -88,7 +109,7 @@ export declare class AppleMailManager {
|
|
|
88
109
|
* @param limit - Maximum number of results
|
|
89
110
|
* @returns Array of matching messages
|
|
90
111
|
*/
|
|
91
|
-
searchMessages(query?: string, mailbox?: string, account?: string, limit?: number, dateFrom?: string, dateTo?: string): Message[];
|
|
112
|
+
searchMessages(query?: string, mailbox?: string, account?: string, limit?: number, dateFrom?: string, dateTo?: string, from?: string, subject?: string, isRead?: boolean, isFlagged?: boolean): Message[];
|
|
92
113
|
/**
|
|
93
114
|
* Get a message by ID.
|
|
94
115
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,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,
|
|
1
|
+
{"version":3,"file":"appleMailManager.d.ts","sourceRoot":"","sources":["../../src/services/appleMailManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -123,22 +123,40 @@ const MAILBOX_ALIASES = {
|
|
|
123
123
|
junk: ["Junk", "Junk Email", "Spam", "JUNK", "junk"],
|
|
124
124
|
archive: ["Archive", "ARCHIVE", "archive", "All Mail"],
|
|
125
125
|
};
|
|
126
|
-
// =============================================================================
|
|
127
|
-
// Apple Mail Manager Class
|
|
128
|
-
// =============================================================================
|
|
129
126
|
/**
|
|
130
|
-
*
|
|
127
|
+
* Build the AppleScript `whose` clause for searchMessages from a filter set.
|
|
131
128
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* -
|
|
135
|
-
* -
|
|
136
|
-
* -
|
|
129
|
+
* - `query` is a subject-OR-sender substring match, parenthesized so it groups
|
|
130
|
+
* correctly when ANDed with other filters.
|
|
131
|
+
* - `from` and `subject` are substring matches (`sender`/`subject` contains).
|
|
132
|
+
* - `isRead` / `isFlagged` are boolean status checks.
|
|
133
|
+
* - Returns "" when no filters are set. Every interpolated value is escaped.
|
|
137
134
|
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
135
|
+
* Exported for unit testing: the bug this addresses (filters declared in the
|
|
136
|
+
* tool schema but silently dropped) lived in this logic, so it gets direct
|
|
137
|
+
* coverage independent of Mail.app.
|
|
141
138
|
*/
|
|
139
|
+
export function buildSearchCondition(filters) {
|
|
140
|
+
const { query, from, subject, isRead, isFlagged } = filters;
|
|
141
|
+
const conditions = [];
|
|
142
|
+
if (query) {
|
|
143
|
+
const safeQuery = escapeForAppleScript(query);
|
|
144
|
+
conditions.push(`(subject contains "${safeQuery}" or sender contains "${safeQuery}")`);
|
|
145
|
+
}
|
|
146
|
+
if (from) {
|
|
147
|
+
conditions.push(`sender contains "${escapeForAppleScript(from)}"`);
|
|
148
|
+
}
|
|
149
|
+
if (subject) {
|
|
150
|
+
conditions.push(`subject contains "${escapeForAppleScript(subject)}"`);
|
|
151
|
+
}
|
|
152
|
+
if (typeof isRead === "boolean") {
|
|
153
|
+
conditions.push(`read status is ${isRead ? "true" : "false"}`);
|
|
154
|
+
}
|
|
155
|
+
if (typeof isFlagged === "boolean") {
|
|
156
|
+
conditions.push(`flagged status is ${isFlagged ? "true" : "false"}`);
|
|
157
|
+
}
|
|
158
|
+
return conditions.length > 0 ? `whose ${conditions.join(" and ")}` : "";
|
|
159
|
+
}
|
|
142
160
|
export class AppleMailManager {
|
|
143
161
|
/**
|
|
144
162
|
* Default account used when no account is specified.
|
|
@@ -289,7 +307,7 @@ export class AppleMailManager {
|
|
|
289
307
|
* @param limit - Maximum number of results
|
|
290
308
|
* @returns Array of matching messages
|
|
291
309
|
*/
|
|
292
|
-
searchMessages(query, mailbox, account, limit = 50, dateFrom, dateTo) {
|
|
310
|
+
searchMessages(query, mailbox, account, limit = 50, dateFrom, dateTo, from, subject, isRead, isFlagged) {
|
|
293
311
|
// If no account specified, search across all accounts
|
|
294
312
|
if (!account) {
|
|
295
313
|
const accounts = this.listAccounts();
|
|
@@ -298,18 +316,16 @@ export class AppleMailManager {
|
|
|
298
316
|
if (allMessages.length >= limit)
|
|
299
317
|
break;
|
|
300
318
|
const remaining = limit - allMessages.length;
|
|
301
|
-
const msgs = this.searchMessages(query, mailbox, acct.name, remaining, dateFrom, dateTo);
|
|
319
|
+
const msgs = this.searchMessages(query, mailbox, acct.name, remaining, dateFrom, dateTo, from, subject, isRead, isFlagged);
|
|
302
320
|
allMessages.push(...msgs);
|
|
303
321
|
}
|
|
304
322
|
return allMessages.slice(0, limit);
|
|
305
323
|
}
|
|
306
324
|
const targetAccount = this.resolveAccount(account);
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
searchCondition = `whose subject contains "${safeQuery}" or sender contains "${safeQuery}"`;
|
|
312
|
-
}
|
|
325
|
+
// `query` is a subject-OR-sender substring match; from/subject/isRead/isFlagged
|
|
326
|
+
// are additional AND filters. Date filtering stays post-fetch below — `whose`
|
|
327
|
+
// date comparisons are unreliable in Mail.app AppleScript. See buildSearchCondition.
|
|
328
|
+
const searchCondition = buildSearchCondition({ query, from, subject, isRead, isFlagged });
|
|
313
329
|
// Build date filter AppleScript.
|
|
314
330
|
// Note: dateFrom/dateTo are already validated by DATE_FILTER_SCHEMA (alphanumeric + safe
|
|
315
331
|
// punctuation only), so escapeForAppleScript() below is belt-and-suspenders — it won't
|
|
@@ -720,6 +736,30 @@ export class AppleMailManager {
|
|
|
720
736
|
* @param account - Account to send from
|
|
721
737
|
* @returns true if sent successfully
|
|
722
738
|
*/
|
|
739
|
+
// ───────────────────────────────────────────────────────────────────
|
|
740
|
+
// KNOWN BUG: outgoing emails sent via AppleScript on macOS 15+ get wrapped
|
|
741
|
+
// in <blockquote type="cite"> under the Apple-Mail-URLShareWrapperClass
|
|
742
|
+
// template, so they render to recipients as quoted/forwarded content.
|
|
743
|
+
// Plain-text alternative gets `>` prefixes on every line.
|
|
744
|
+
//
|
|
745
|
+
// Reproduces with EVERY AppleScript message-creation pattern I tried:
|
|
746
|
+
// • make new outgoing message with properties {content: ..., ...}
|
|
747
|
+
// • make new outgoing message (no content) + `set content of newMessage`
|
|
748
|
+
// • setting `default message format` to plain format first
|
|
749
|
+
//
|
|
750
|
+
// Apple radar FB11734014 (open since Ventura, no movement).
|
|
751
|
+
// Discussion: https://forums.macrumors.com/threads/applescript-creating-a-
|
|
752
|
+
// new-message-in-mail-app-is-causing-weird-formatting-issues.2385052/
|
|
753
|
+
//
|
|
754
|
+
// Workaround for callers who need clean emails today: use SMTP directly
|
|
755
|
+
// (Python smtplib). See e.g. sweetrb/nhl-bracket-tracker's send_email.py.
|
|
756
|
+
//
|
|
757
|
+
// Proper fix is probably to abandon `make new outgoing message` and either:
|
|
758
|
+
// 1. Build the .emlx file ourselves and drop it into a Drafts mailbox.
|
|
759
|
+
// 2. Switch to smtplib-style direct send with Keychain-stored creds.
|
|
760
|
+
// 3. Use Mail.app's NSSharingService rather than AppleScript.
|
|
761
|
+
// Tracking issue: https://github.com/sweetrb/apple-mail-mcp/issues/12
|
|
762
|
+
// ───────────────────────────────────────────────────────────────────
|
|
723
763
|
sendEmail(to, subject, body, cc, bcc, account, attachments) {
|
|
724
764
|
const safeSubject = escapeForAppleScript(subject);
|
|
725
765
|
const safeBody = escapeForAppleScript(body);
|