apple-mail-mcp 2.10.17 → 2.10.22
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 +1 -0
- package/build/index.js +55 -35
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1597,6 +1597,7 @@ The entrypoint is written as:
|
|
|
1597
1597
|
| 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 |
|
|
1598
1598
|
| Attachment save path restrictions | `save-attachment` only allows saving to home directory, `/tmp`, `/private/tmp`, and `/Volumes`; path traversal is blocked |
|
|
1599
1599
|
| Attachment count limit | `send-email` and `create-draft` accept a maximum of 20 file attachments |
|
|
1600
|
+
| IMAP attachment fetch size | `fetch-attachment` / `save-attachment` over IMAP refuse a part larger than 25 MiB — rejected before download when the server declares the size, and the stream is cut off at the limit when it does not |
|
|
1600
1601
|
|
|
1601
1602
|
### Mail.app `<blockquote>` wrapping on macOS 15+ (workaround in v1.6.0)
|
|
1602
1603
|
|
package/build/index.js
CHANGED
|
@@ -78057,6 +78057,7 @@ import { tmpdir } from "os";
|
|
|
78057
78057
|
|
|
78058
78058
|
// src/utils/attachmentLimits.ts
|
|
78059
78059
|
var MAX_INLINE_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
78060
|
+
var MAX_IMAP_ATTACHMENT_BYTES = MAX_INLINE_ATTACHMENT_BYTES;
|
|
78060
78061
|
var MAX_INLINE_ATTACHMENT_BASE64_CHARS = Math.ceil(MAX_INLINE_ATTACHMENT_BYTES / 3) * 4;
|
|
78061
78062
|
var MAX_INLINE_ATTACHMENT_BASE64_INPUT_CHARS = MAX_INLINE_ATTACHMENT_BASE64_CHARS * 2;
|
|
78062
78063
|
function isInlineAttachmentBase64WithinLimit(contentBase64) {
|
|
@@ -83454,9 +83455,16 @@ function collectAttachments(node, out = []) {
|
|
|
83454
83455
|
for (const child of node.childNodes ?? []) collectAttachments(child, out);
|
|
83455
83456
|
return out;
|
|
83456
83457
|
}
|
|
83457
|
-
async function streamToBuffer(content) {
|
|
83458
|
+
async function streamToBuffer(content, maxBytes) {
|
|
83458
83459
|
const chunks = [];
|
|
83459
|
-
|
|
83460
|
+
let total = 0;
|
|
83461
|
+
for await (const chunk of content) {
|
|
83462
|
+
total += chunk.byteLength;
|
|
83463
|
+
if (total > maxBytes) {
|
|
83464
|
+
throw new Error(`IMAP attachment exceeds the ${maxBytes / 1024 / 1024} MiB size limit.`);
|
|
83465
|
+
}
|
|
83466
|
+
chunks.push(Buffer.from(chunk));
|
|
83467
|
+
}
|
|
83460
83468
|
return Buffer.concat(chunks);
|
|
83461
83469
|
}
|
|
83462
83470
|
async function imapListAttachments(id, deps = {}) {
|
|
@@ -83493,14 +83501,24 @@ async function imapFetchAttachment(id, attachmentName, deps = {}) {
|
|
|
83493
83501
|
error: `Attachment "${attachmentName}" not found on UID ${ref.uid}. Available: ${names}.`
|
|
83494
83502
|
};
|
|
83495
83503
|
}
|
|
83496
|
-
|
|
83497
|
-
|
|
83498
|
-
|
|
83499
|
-
|
|
83500
|
-
|
|
83501
|
-
|
|
83502
|
-
|
|
83503
|
-
|
|
83504
|
+
if (match.size > MAX_IMAP_ATTACHMENT_BYTES) {
|
|
83505
|
+
return {
|
|
83506
|
+
success: false,
|
|
83507
|
+
error: `IMAP attachment "${attachmentName}" is ${match.size} bytes; the maximum is ${MAX_IMAP_ATTACHMENT_BYTES} bytes (25 MiB).`
|
|
83508
|
+
};
|
|
83509
|
+
}
|
|
83510
|
+
try {
|
|
83511
|
+
const dl = await client.download(String(ref.uid), match.part, { uid: true });
|
|
83512
|
+
const buf = await streamToBuffer(dl.content, MAX_IMAP_ATTACHMENT_BYTES);
|
|
83513
|
+
return {
|
|
83514
|
+
success: true,
|
|
83515
|
+
base64: buf.toString("base64"),
|
|
83516
|
+
bytes: buf.length,
|
|
83517
|
+
mimeType: match.mimeType
|
|
83518
|
+
};
|
|
83519
|
+
} catch (e) {
|
|
83520
|
+
return { success: false, error: `IMAP attachment fetch failed: ${errText(e)}` };
|
|
83521
|
+
}
|
|
83504
83522
|
});
|
|
83505
83523
|
}
|
|
83506
83524
|
async function imapBatch(ids, deps, op) {
|
|
@@ -84092,6 +84110,33 @@ function registerResourcesAndPrompts(server2, mailManager2) {
|
|
|
84092
84110
|
);
|
|
84093
84111
|
}
|
|
84094
84112
|
|
|
84113
|
+
// src/schemas.ts
|
|
84114
|
+
var MESSAGE_ID_SCHEMA = external_exports.string().regex(/^(\d+|imap:[A-Za-z0-9_-]+)$/, "Message ID must be numeric or an IMAP id (imap:\u2026)");
|
|
84115
|
+
var BATCH_IDS_SCHEMA = external_exports.array(MESSAGE_ID_SCHEMA).min(1, "At least one message ID is required").max(100, "Cannot process more than 100 messages in a single batch");
|
|
84116
|
+
var DATE_FILTER_SCHEMA = external_exports.string().regex(
|
|
84117
|
+
/^[a-zA-Z0-9 ,/\-:]+$/,
|
|
84118
|
+
"Date must contain only alphanumeric characters, spaces, commas, slashes, hyphens, and colons"
|
|
84119
|
+
).refine((val) => !isNaN(new Date(val).getTime()), {
|
|
84120
|
+
message: "Date string must be a valid date (e.g., 'January 1, 2026' or '2026-03-15')"
|
|
84121
|
+
}).optional();
|
|
84122
|
+
var ATTACHMENTS_SCHEMA = external_exports.array(
|
|
84123
|
+
external_exports.union([
|
|
84124
|
+
external_exports.string().describe("Absolute path to an existing file"),
|
|
84125
|
+
external_exports.object({
|
|
84126
|
+
filename: external_exports.string().min(1).max(255).describe("Filename to give the attachment"),
|
|
84127
|
+
contentBase64: external_exports.string().min(1).max(
|
|
84128
|
+
MAX_INLINE_ATTACHMENT_BASE64_INPUT_CHARS,
|
|
84129
|
+
"Inline attachment exceeds the 25 MiB decoded size limit"
|
|
84130
|
+
).refine(
|
|
84131
|
+
isInlineAttachmentBase64WithinLimit,
|
|
84132
|
+
"Inline attachment exceeds the 25 MiB decoded size limit"
|
|
84133
|
+
).describe("Base64-encoded file content (maximum 25 MiB decoded)")
|
|
84134
|
+
})
|
|
84135
|
+
])
|
|
84136
|
+
).max(20, "Cannot attach more than 20 files").optional().describe(
|
|
84137
|
+
"Files to attach: absolute paths (e.g. '/Users/me/report.pdf') and/or inline {filename, contentBase64} objects up to 25 MiB decoded each."
|
|
84138
|
+
);
|
|
84139
|
+
|
|
84095
84140
|
// src/tools/thread.ts
|
|
84096
84141
|
function normalizeSubject(subject) {
|
|
84097
84142
|
const prefix = /^\s*(?:(?:re|fwd?|fw|aw|wg|sv|vs|antw|antwort|enc|rif)\s*(?:\[\d+\])?\s*:\s*)+/i;
|
|
@@ -84374,8 +84419,6 @@ function withJsonSchema2020_12(transport2) {
|
|
|
84374
84419
|
|
|
84375
84420
|
// src/index.ts
|
|
84376
84421
|
loadFileConfig();
|
|
84377
|
-
var MESSAGE_ID_SCHEMA = external_exports.string().regex(/^(\d+|imap:[A-Za-z0-9_-]+)$/, "Message ID must be numeric or an IMAP id (imap:\u2026)");
|
|
84378
|
-
var BATCH_IDS_SCHEMA = external_exports.array(MESSAGE_ID_SCHEMA).min(1, "At least one message ID is required").max(100, "Cannot process more than 100 messages in a single batch");
|
|
84379
84422
|
var BATCH_SOURCE_MAILBOX_SCHEMA = external_exports.string().optional().describe(
|
|
84380
84423
|
"Mailbox the numeric ids were listed from (e.g. 'INBOX'). Pins each id to that mailbox \u2014 strongly recommended, since one numeric id can match in several mailboxes. Works on its own: without sourceAccount it means that mailbox in the default account. Ignored for imap: ids."
|
|
84381
84424
|
);
|
|
@@ -84395,29 +84438,6 @@ var FLAG_COLOR_INDEX = {
|
|
|
84395
84438
|
var FLAG_COLOR_SCHEMA = external_exports.enum(["red", "orange", "yellow", "green", "blue", "purple", "gray", "grey"]).optional().describe(
|
|
84396
84439
|
"Optional flag color (Apple Mail palette: red, orange, yellow, green, blue, purple, gray \u2014 'grey' accepted). Omit for Mail's default flag. The color is applied on both routes: AppleScript sets the flag index, and IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads \u2014 so a smart mailbox keyed on flag color matches either way."
|
|
84397
84440
|
);
|
|
84398
|
-
var DATE_FILTER_SCHEMA = external_exports.string().regex(
|
|
84399
|
-
/^[a-zA-Z0-9 ,/\-:]+$/,
|
|
84400
|
-
"Date must contain only alphanumeric characters, spaces, commas, slashes, hyphens, and colons"
|
|
84401
|
-
).refine((val) => !isNaN(new Date(val).getTime()), {
|
|
84402
|
-
message: "Date string must be a valid date (e.g., 'January 1, 2026' or '2026-03-15')"
|
|
84403
|
-
}).optional();
|
|
84404
|
-
var ATTACHMENTS_SCHEMA = external_exports.array(
|
|
84405
|
-
external_exports.union([
|
|
84406
|
-
external_exports.string().describe("Absolute path to an existing file"),
|
|
84407
|
-
external_exports.object({
|
|
84408
|
-
filename: external_exports.string().min(1).max(255).describe("Filename to give the attachment"),
|
|
84409
|
-
contentBase64: external_exports.string().min(1).max(
|
|
84410
|
-
MAX_INLINE_ATTACHMENT_BASE64_INPUT_CHARS,
|
|
84411
|
-
"Inline attachment exceeds the 25 MiB decoded size limit"
|
|
84412
|
-
).refine(
|
|
84413
|
-
isInlineAttachmentBase64WithinLimit,
|
|
84414
|
-
"Inline attachment exceeds the 25 MiB decoded size limit"
|
|
84415
|
-
).describe("Base64-encoded file content (maximum 25 MiB decoded)")
|
|
84416
|
-
})
|
|
84417
|
-
])
|
|
84418
|
-
).max(20, "Cannot attach more than 20 files").optional().describe(
|
|
84419
|
-
"Files to attach: absolute paths (e.g. '/Users/me/report.pdf') and/or inline {filename, contentBase64} objects up to 25 MiB decoded each."
|
|
84420
|
-
);
|
|
84421
84441
|
var MESSAGE_ROW_SCHEMA = external_exports.object({}).passthrough();
|
|
84422
84442
|
var LIST_OUTPUT_SCHEMA = {
|
|
84423
84443
|
messages: external_exports.array(MESSAGE_ROW_SCHEMA).optional(),
|
package/package.json
CHANGED