apple-mail-mcp 2.11.1 → 2.12.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/build/index.js +118 -40
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -80955,20 +80955,15 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80955
80955
|
replyToMessage(id, body, replyAll = false, send = true) {
|
|
80956
80956
|
const safeBody = escapeForAppleScriptBody(body);
|
|
80957
80957
|
const replyAllClause = replyAll ? " with reply to all" : "";
|
|
80958
|
-
const
|
|
80958
|
+
const finalAction = send ? "send theReply" : "save theReply";
|
|
80959
80959
|
const script = this.findMessageScript(
|
|
80960
80960
|
id,
|
|
80961
80961
|
`
|
|
80962
80962
|
set theReply to reply msg without opening window${replyAllClause}
|
|
80963
80963
|
set content of theReply to "${safeBody}"
|
|
80964
|
-
${
|
|
80964
|
+
${finalAction}`
|
|
80965
80965
|
);
|
|
80966
|
-
|
|
80967
|
-
if (!result.success || result.output.startsWith("error:")) {
|
|
80968
|
-
console.error(`Failed to reply to message: ${result.error || result.output}`);
|
|
80969
|
-
return false;
|
|
80970
|
-
}
|
|
80971
|
-
return true;
|
|
80966
|
+
return this.runComposeScript(script, "reply to");
|
|
80972
80967
|
}
|
|
80973
80968
|
/**
|
|
80974
80969
|
* Forward a message.
|
|
@@ -80981,7 +80976,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80981
80976
|
*/
|
|
80982
80977
|
forwardMessage(id, to, body, send = true) {
|
|
80983
80978
|
const safeBody = body ? escapeForAppleScriptBody(body) : "";
|
|
80984
|
-
const
|
|
80979
|
+
const finalAction = send ? "send theForward" : "save theForward";
|
|
80985
80980
|
let recipientCommands = "";
|
|
80986
80981
|
for (const addr of to) {
|
|
80987
80982
|
recipientCommands += `make new to recipient at end of to recipients of theForward with properties {address:"${escapeForAppleScript(addr)}"}
|
|
@@ -80993,14 +80988,9 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80993
80988
|
set theForward to forward msg without opening window
|
|
80994
80989
|
${recipientCommands}
|
|
80995
80990
|
${safeBody ? `set content of theForward to "${safeBody}"` : ""}
|
|
80996
|
-
${
|
|
80991
|
+
${finalAction}`
|
|
80997
80992
|
);
|
|
80998
|
-
|
|
80999
|
-
if (!result.success || result.output.startsWith("error:")) {
|
|
81000
|
-
console.error(`Failed to forward message: ${result.error || result.output}`);
|
|
81001
|
-
return false;
|
|
81002
|
-
}
|
|
81003
|
-
return true;
|
|
80993
|
+
return this.runComposeScript(script, "forward");
|
|
81004
80994
|
}
|
|
81005
80995
|
/**
|
|
81006
80996
|
* Helper to find and operate on a message by ID, scoped to the mailbox the id
|
|
@@ -81025,6 +81015,25 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
81025
81015
|
* it immediately, so this is also where the previous operation's forensic
|
|
81026
81016
|
* report is invalidated — see `beginMutation()`.
|
|
81027
81017
|
*/
|
|
81018
|
+
/**
|
|
81019
|
+
* Run a reply/forward compose script and surface Mail's OWN error text.
|
|
81020
|
+
*
|
|
81021
|
+
* These used to return a bare boolean and log the reason to stderr, so the
|
|
81022
|
+
* tool layer could only say "Failed to reply to message X". That hid the two
|
|
81023
|
+
* failures a caller can actually act on — an id present in several mailboxes
|
|
81024
|
+
* (which names the candidates and tells you to re-list) and a missing id —
|
|
81025
|
+
* behind one indistinguishable message.
|
|
81026
|
+
*/
|
|
81027
|
+
runComposeScript(script, verb) {
|
|
81028
|
+
const result = executeAppleScript(script, { timeoutMs: 6e4 });
|
|
81029
|
+
if (!result.success || result.output.startsWith("error:")) {
|
|
81030
|
+
const raw = result.error || result.output;
|
|
81031
|
+
const error2 = raw.startsWith("error:") ? raw.slice("error:".length) : raw;
|
|
81032
|
+
console.error(`Failed to ${verb} message: ${error2}`);
|
|
81033
|
+
return { success: false, error: error2 };
|
|
81034
|
+
}
|
|
81035
|
+
return { success: true };
|
|
81036
|
+
}
|
|
81028
81037
|
findMessageScript(id, operation, instrument = false) {
|
|
81029
81038
|
this.beginMutation();
|
|
81030
81039
|
const loc = this.locationFor(id);
|
|
@@ -83829,6 +83838,10 @@ function imapMailStats(deps = {}) {
|
|
|
83829
83838
|
function errText(e) {
|
|
83830
83839
|
return e instanceof Error ? e.message : String(e);
|
|
83831
83840
|
}
|
|
83841
|
+
function assertMutated(result, what) {
|
|
83842
|
+
if (!result) throw new Error(`${what}: server rejected the command (IMAP NO/BAD)`);
|
|
83843
|
+
return result;
|
|
83844
|
+
}
|
|
83832
83845
|
var poolConnect = defaultConnect;
|
|
83833
83846
|
var pools = /* @__PURE__ */ new Map();
|
|
83834
83847
|
function poolKey(cfg) {
|
|
@@ -84167,7 +84180,10 @@ async function imapMoveMessageById(id, destMailbox, deps = {}) {
|
|
|
84167
84180
|
const destPath = dest.kind === "found" ? dest.path : resolveMailboxPath(destMailbox, "list");
|
|
84168
84181
|
const lock = await client.getMailboxLock(ref.path);
|
|
84169
84182
|
try {
|
|
84170
|
-
|
|
84183
|
+
assertMutated(
|
|
84184
|
+
await client.messageMove([ref.uid], destPath, { uid: true }),
|
|
84185
|
+
`IMAP move of UID ${ref.uid} to "${destPath}"`
|
|
84186
|
+
);
|
|
84171
84187
|
return { success: true, info: `Moved UID ${ref.uid} to "${destPath}" via IMAP.` };
|
|
84172
84188
|
} catch (e) {
|
|
84173
84189
|
return {
|
|
@@ -84179,9 +84195,12 @@ async function imapMoveMessageById(id, destMailbox, deps = {}) {
|
|
|
84179
84195
|
}
|
|
84180
84196
|
});
|
|
84181
84197
|
}
|
|
84198
|
+
var FALLBACK_TRASH_PATH = "Trash";
|
|
84182
84199
|
async function resolveTrashPath(client) {
|
|
84200
|
+
let listed = false;
|
|
84183
84201
|
try {
|
|
84184
84202
|
const boxes = await client.list();
|
|
84203
|
+
listed = true;
|
|
84185
84204
|
const special = boxes.find((b) => b.specialUse === "\\Trash");
|
|
84186
84205
|
if (special) return special.path;
|
|
84187
84206
|
const named = boxes.find(
|
|
@@ -84190,15 +84209,27 @@ async function resolveTrashPath(client) {
|
|
|
84190
84209
|
if (named) return named.path;
|
|
84191
84210
|
} catch {
|
|
84192
84211
|
}
|
|
84193
|
-
return resolveMailboxPath("trash", "list");
|
|
84212
|
+
if (!listed) return resolveMailboxPath("trash", "list");
|
|
84213
|
+
try {
|
|
84214
|
+
const created = await client.mailboxCreate(FALLBACK_TRASH_PATH);
|
|
84215
|
+
return created?.path || FALLBACK_TRASH_PATH;
|
|
84216
|
+
} catch {
|
|
84217
|
+
return FALLBACK_TRASH_PATH;
|
|
84218
|
+
}
|
|
84194
84219
|
}
|
|
84195
84220
|
async function trashUids(client, uids, srcPath) {
|
|
84196
84221
|
const dest = await resolveTrashPath(client);
|
|
84197
84222
|
if (srcPath.trim().toLowerCase() === dest.trim().toLowerCase()) {
|
|
84198
|
-
|
|
84223
|
+
assertMutated(
|
|
84224
|
+
await client.messageDelete(uids, { uid: true }),
|
|
84225
|
+
`IMAP expunge of ${uids.length} message(s) from "${srcPath}"`
|
|
84226
|
+
);
|
|
84199
84227
|
return { dest, expunged: true };
|
|
84200
84228
|
}
|
|
84201
|
-
|
|
84229
|
+
assertMutated(
|
|
84230
|
+
await client.messageMove(uids, dest, { uid: true }),
|
|
84231
|
+
`IMAP move of ${uids.length} message(s) from "${srcPath}" to "${dest}"`
|
|
84232
|
+
);
|
|
84202
84233
|
return { dest, expunged: false };
|
|
84203
84234
|
}
|
|
84204
84235
|
async function imapDeleteMessageById(id, deps = {}) {
|
|
@@ -84338,22 +84369,37 @@ async function imapBatch(ids, deps, op) {
|
|
|
84338
84369
|
return { success, failed, errors };
|
|
84339
84370
|
}
|
|
84340
84371
|
var imapBatchMarkRead = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
84341
|
-
|
|
84372
|
+
assertMutated(
|
|
84373
|
+
await c.messageFlagsAdd(uids, ["\\Seen"], { uid: true }),
|
|
84374
|
+
`IMAP mark-read of ${uids.length} message(s)`
|
|
84375
|
+
);
|
|
84342
84376
|
});
|
|
84343
84377
|
var imapBatchMarkUnread = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
84344
|
-
|
|
84378
|
+
assertMutated(
|
|
84379
|
+
await c.messageFlagsRemove(uids, ["\\Seen"], { uid: true }),
|
|
84380
|
+
`IMAP mark-unread of ${uids.length} message(s)`
|
|
84381
|
+
);
|
|
84345
84382
|
});
|
|
84346
84383
|
var imapBatchFlag = (ids, colorIndex, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
84347
84384
|
if (colorIndex === void 0) {
|
|
84348
|
-
|
|
84385
|
+
assertMutated(
|
|
84386
|
+
await c.messageFlagsAdd(uids, ["\\Flagged"], { uid: true }),
|
|
84387
|
+
`IMAP flag of ${uids.length} message(s)`
|
|
84388
|
+
);
|
|
84349
84389
|
return;
|
|
84350
84390
|
}
|
|
84351
84391
|
const { set, clear } = mailFlagBitsFor(colorIndex);
|
|
84352
|
-
|
|
84392
|
+
assertMutated(
|
|
84393
|
+
await c.messageFlagsAdd(uids, ["\\Flagged", ...set], { uid: true }),
|
|
84394
|
+
`IMAP flag of ${uids.length} message(s)`
|
|
84395
|
+
);
|
|
84353
84396
|
if (clear.length) await c.messageFlagsRemove(uids, clear, { uid: true });
|
|
84354
84397
|
});
|
|
84355
84398
|
var imapBatchUnflag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
84356
|
-
|
|
84399
|
+
assertMutated(
|
|
84400
|
+
await c.messageFlagsRemove(uids, ["\\Flagged", ...MAIL_FLAG_BITS], { uid: true }),
|
|
84401
|
+
`IMAP unflag of ${uids.length} message(s)`
|
|
84402
|
+
);
|
|
84357
84403
|
});
|
|
84358
84404
|
var imapBatchDelete = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids, path) => {
|
|
84359
84405
|
await trashUids(c, uids, path);
|
|
@@ -84361,7 +84407,10 @@ var imapBatchDelete = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids, p
|
|
|
84361
84407
|
function imapBatchMove(ids, destMailbox, deps = {}) {
|
|
84362
84408
|
return imapBatch(ids, deps, async (c, uids) => {
|
|
84363
84409
|
const dest = await findMailboxPathOrThrow(c, destMailbox) ?? resolveMailboxPath(destMailbox, "list");
|
|
84364
|
-
|
|
84410
|
+
assertMutated(
|
|
84411
|
+
await c.messageMove(uids, dest, { uid: true }),
|
|
84412
|
+
`IMAP move of ${uids.length} message(s) to "${dest}"`
|
|
84413
|
+
);
|
|
84365
84414
|
});
|
|
84366
84415
|
}
|
|
84367
84416
|
function senderName(from) {
|
|
@@ -85940,6 +85989,23 @@ function resolveSmtpOrFallback() {
|
|
|
85940
85989
|
return null;
|
|
85941
85990
|
}
|
|
85942
85991
|
}
|
|
85992
|
+
async function toNumericMailId(id) {
|
|
85993
|
+
const ref = decodeImapId(id);
|
|
85994
|
+
if (!ref) return { numericId: id };
|
|
85995
|
+
const messageId = await imapFetchMessageId(id);
|
|
85996
|
+
if (!messageId) {
|
|
85997
|
+
return {
|
|
85998
|
+
error: `could not read the RFC Message-ID for "${id}" over IMAP, which is what maps it to a Mail.app id. Pass the numeric id instead (see the resolve-message-id tool).`
|
|
85999
|
+
};
|
|
86000
|
+
}
|
|
86001
|
+
const numericId = mailManager.findNumericIdByMessageId(messageId, ref.account);
|
|
86002
|
+
if (!numericId) {
|
|
86003
|
+
return {
|
|
86004
|
+
error: `Mail.app has no message with Message-ID <${messageId}> in account "${ref.account}", so this IMAP message has no numeric id to reply to or forward. It may not have synced to Mail.app yet.`
|
|
86005
|
+
};
|
|
86006
|
+
}
|
|
86007
|
+
return { numericId };
|
|
86008
|
+
}
|
|
85943
86009
|
async function sendReplyViaSmtp(id, body, replyAll) {
|
|
85944
86010
|
const cfg = resolveSmtpOrFallback();
|
|
85945
86011
|
if (!cfg) return { sent: false, fallback: true };
|
|
@@ -85998,17 +86064,23 @@ registerTool(
|
|
|
85998
86064
|
},
|
|
85999
86065
|
withErrorHandling(async ({ id, body, replyAll, send }) => {
|
|
86000
86066
|
if (send && isSmtpConfigured()) {
|
|
86001
|
-
const
|
|
86002
|
-
if (
|
|
86067
|
+
const outcome2 = await sendReplyViaSmtp(id, body, replyAll);
|
|
86068
|
+
if (outcome2.sent) {
|
|
86003
86069
|
return successResponse("Reply sent", { ok: true, sent: true, id });
|
|
86004
86070
|
}
|
|
86005
|
-
if (!
|
|
86006
|
-
return errorResponse(`Failed to reply to message "${id}" via SMTP: ${
|
|
86071
|
+
if (!outcome2.fallback) {
|
|
86072
|
+
return errorResponse(`Failed to reply to message "${id}" via SMTP: ${outcome2.error}`);
|
|
86007
86073
|
}
|
|
86008
86074
|
}
|
|
86009
|
-
const
|
|
86010
|
-
if (!
|
|
86011
|
-
return errorResponse(`Failed to reply to message "${id}"`);
|
|
86075
|
+
const resolvedReply = await toNumericMailId(id);
|
|
86076
|
+
if (!resolvedReply.numericId) {
|
|
86077
|
+
return errorResponse(`Failed to reply to message "${id}": ${resolvedReply.error}`);
|
|
86078
|
+
}
|
|
86079
|
+
const outcome = mailManager.replyToMessage(resolvedReply.numericId, body, replyAll, send);
|
|
86080
|
+
if (!outcome.success) {
|
|
86081
|
+
return errorResponse(
|
|
86082
|
+
outcome.error ? `Failed to reply to message "${id}": ${outcome.error}` : `Failed to reply to message "${id}"`
|
|
86083
|
+
);
|
|
86012
86084
|
}
|
|
86013
86085
|
return successResponse(send ? "Reply sent" : "Reply saved as draft", {
|
|
86014
86086
|
ok: true,
|
|
@@ -86036,8 +86108,8 @@ registerTool(
|
|
|
86036
86108
|
},
|
|
86037
86109
|
withErrorHandling(async ({ id, to, body, send }) => {
|
|
86038
86110
|
if (send && isSmtpConfigured()) {
|
|
86039
|
-
const
|
|
86040
|
-
if (
|
|
86111
|
+
const outcome2 = await sendForwardViaSmtp(id, to, body);
|
|
86112
|
+
if (outcome2.sent) {
|
|
86041
86113
|
return successResponse(`Message forwarded to ${to.join(", ")}`, {
|
|
86042
86114
|
ok: true,
|
|
86043
86115
|
sent: true,
|
|
@@ -86045,13 +86117,19 @@ registerTool(
|
|
|
86045
86117
|
id
|
|
86046
86118
|
});
|
|
86047
86119
|
}
|
|
86048
|
-
if (!
|
|
86049
|
-
return errorResponse(`Failed to forward message "${id}" via SMTP: ${
|
|
86120
|
+
if (!outcome2.fallback) {
|
|
86121
|
+
return errorResponse(`Failed to forward message "${id}" via SMTP: ${outcome2.error}`);
|
|
86050
86122
|
}
|
|
86051
86123
|
}
|
|
86052
|
-
const
|
|
86053
|
-
if (!
|
|
86054
|
-
return errorResponse(`Failed to forward message "${id}"`);
|
|
86124
|
+
const resolvedFwd = await toNumericMailId(id);
|
|
86125
|
+
if (!resolvedFwd.numericId) {
|
|
86126
|
+
return errorResponse(`Failed to forward message "${id}": ${resolvedFwd.error}`);
|
|
86127
|
+
}
|
|
86128
|
+
const outcome = mailManager.forwardMessage(resolvedFwd.numericId, to, body, send);
|
|
86129
|
+
if (!outcome.success) {
|
|
86130
|
+
return errorResponse(
|
|
86131
|
+
outcome.error ? `Failed to forward message "${id}": ${outcome.error}` : `Failed to forward message "${id}"`
|
|
86132
|
+
);
|
|
86055
86133
|
}
|
|
86056
86134
|
return successResponse(
|
|
86057
86135
|
send ? `Message forwarded to ${to.join(", ")}` : "Forward saved as draft",
|
package/package.json
CHANGED