apple-mail-mcp 2.6.1 → 2.6.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
@@ -186,7 +186,7 @@ Search for messages matching criteria. Searches all accounts by default.
186
186
  | `isFlagged` | boolean | No | Filter by flagged status |
187
187
  | `dateFrom` | string | No | Start date filter (e.g., "January 1, 2026") |
188
188
  | `dateTo` | string | No | End date filter (e.g., "March 1, 2026") |
189
- | `limit` | number | No | Max results (default: 50) |
189
+ | `limit` | number | No | Max results, 1–500 (default: 50) |
190
190
 
191
191
  **Large mailboxes & partial results.** Apple Mail's AppleScript bridge cannot
192
192
  search very large IMAP/Gmail mailboxes (tens of thousands of messages) before
@@ -222,6 +222,13 @@ Get the full content of a message.
222
222
 
223
223
  **Returns:** Subject line and message body (plain text by default, HTML if `preferHtml` is true and HTML content is available).
224
224
 
225
+ > **Large messages / attachments:** reading a full message routes through
226
+ > `osascript`, whose captured output buffer defaults to **64 MB**. Override it
227
+ > with the `APPLE_MAIL_MCP_MAX_BUFFER` environment variable (in **bytes**) if you
228
+ > work with messages whose raw MIME (e.g. a large embedded attachment) exceeds
229
+ > that — a value below the message size makes the read fail with a buffer-overflow
230
+ > error rather than truncating ([#27](https://github.com/sweetrb/apple-mail-mcp/issues/27)).
231
+
225
232
  ---
226
233
 
227
234
  #### `list-messages`
@@ -232,8 +239,8 @@ List messages in a mailbox.
232
239
  |-----------|------|----------|-------------|
233
240
  | `mailbox` | string | No | Mailbox name (omit to list from all mailboxes) |
234
241
  | `account` | string | No | Account name |
235
- | `limit` | number | No | Max messages (default: 50) |
236
- | `offset` | number | No | Number of messages to skip (for pagination) |
242
+ | `limit` | number | No | Max messages, 1–500 (default: 50) |
243
+ | `offset` | number | No | Number of messages to skip, ≥ 0 (for pagination) |
237
244
  | `from` | string | No | Filter by sender email address or name |
238
245
  | `unreadOnly` | boolean | No | Only show unread messages |
239
246
 
@@ -1056,6 +1063,13 @@ AI: [calls list-messages with account="Work Exchange", mailbox="INBOX"]
1056
1063
  "Your Work account has 5 unread messages..."
1057
1064
  ```
1058
1065
 
1066
+ To pin which account is used when a tool call omits `account`, set the
1067
+ `APPLE_MAIL_MCP_DEFAULT_ACCOUNT` environment variable to an account **name or
1068
+ email**. When unset (the default), the server falls back to Mail.app's
1069
+ default-send account if it is enabled, otherwise the first enabled account. A
1070
+ **disabled** account is never selected implicitly — this env var (an explicit,
1071
+ deliberate pin) is one of the few ways to target one ([#47](https://github.com/sweetrb/apple-mail-mcp/issues/47)).
1072
+
1059
1073
  ### Sending Emails Safely
1060
1074
 
1061
1075
  ```
package/build/index.js CHANGED
@@ -265,7 +265,13 @@ server.registerTool("search-messages", {
265
265
  isFlagged: z.boolean().optional().describe("Filter by flagged status"),
266
266
  dateFrom: DATE_FILTER_SCHEMA.describe("Start date filter (e.g., 'January 1, 2026')"),
267
267
  dateTo: DATE_FILTER_SCHEMA.describe("End date filter (e.g., 'March 1, 2026')"),
268
- limit: z.number().optional().describe("Maximum number of results (default: 50)"),
268
+ limit: z
269
+ .number()
270
+ .int()
271
+ .min(1)
272
+ .max(500)
273
+ .optional()
274
+ .describe("Maximum number of results (default: 50, max: 500)"),
269
275
  },
270
276
  outputSchema: LIST_OUTPUT_SCHEMA,
271
277
  }, withErrorHandling(async ({ query, mailbox, account, limit = 50, dateFrom, dateTo, from, subject, isRead, isFlagged, }) => {
@@ -485,8 +491,19 @@ server.registerTool("list-messages", {
485
491
  .optional()
486
492
  .describe("Mailbox to list messages from. Omit to list from all mailboxes."),
487
493
  account: z.string().optional().describe("Account to list messages from"),
488
- limit: z.number().optional().describe("Maximum number of messages (default: 50)"),
489
- offset: z.number().optional().describe("Number of messages to skip (for pagination)"),
494
+ limit: z
495
+ .number()
496
+ .int()
497
+ .min(1)
498
+ .max(500)
499
+ .optional()
500
+ .describe("Maximum number of messages (default: 50, max: 500)"),
501
+ offset: z
502
+ .number()
503
+ .int()
504
+ .min(0)
505
+ .optional()
506
+ .describe("Number of messages to skip (for pagination)"),
490
507
  from: z.string().optional().describe("Filter by sender email address or name"),
491
508
  unreadOnly: z.boolean().optional().describe("Only show unread messages"),
492
509
  },
@@ -1 +1 @@
1
- {"version":3,"file":"mimeParse.d.ts","sourceRoot":"","sources":["../../src/utils/mimeParse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAyLD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAyBzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuB7D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuB7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,kBAAkB,GAAG,IAAI,CAwB3B"}
1
+ {"version":3,"file":"mimeParse.d.ts","sourceRoot":"","sources":["../../src/utils/mimeParse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAqMD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAyBzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuB7D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuB7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,kBAAkB,GAAG,IAAI,CAwB3B"}
@@ -107,19 +107,30 @@ function splitMimeParts(source, boundary) {
107
107
  }
108
108
  return parts;
109
109
  }
110
+ /**
111
+ * Maximum nesting depth for multipart MIME traversal. Bounds recursion so a
112
+ * pathologically (or maliciously) deeply nested multipart tree can't blow the
113
+ * stack — past this depth we stop descending and treat the container as a leaf.
114
+ * Real mail nests only a few levels (e.g. mixed → related → alternative).
115
+ */
116
+ const MAX_MIME_DEPTH = 20;
110
117
  /**
111
118
  * Walk a multipart MIME block and return all non-multipart leaf parts,
112
119
  * descending into nested multipart/* containers (alternative, related, mixed).
120
+ *
121
+ * Descent is bounded by MAX_MIME_DEPTH; once reached, deeper multipart
122
+ * containers are returned as-is (as leaf parts) rather than recursed into,
123
+ * yielding what's parsed so far instead of overflowing the stack.
113
124
  */
114
- function walkLeafParts(source, boundary) {
125
+ function walkLeafParts(source, boundary, depth = 0) {
115
126
  const result = [];
116
127
  const parts = splitMimeParts(source, boundary);
117
128
  for (const part of parts) {
118
129
  const ct = getHeader(part.headers, "Content-Type");
119
- if (ct && /^multipart\//i.test(ct)) {
130
+ if (ct && /^multipart\//i.test(ct) && depth < MAX_MIME_DEPTH) {
120
131
  const nestedBoundary = extractBoundary(ct);
121
132
  if (nestedBoundary) {
122
- result.push(...walkLeafParts(part.body, nestedBoundary));
133
+ result.push(...walkLeafParts(part.body, nestedBoundary, depth + 1));
123
134
  continue;
124
135
  }
125
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",