apple-mail-mcp 2.20.20 → 2.20.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 +11 -0
- package/build/index.js +79 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1075,6 +1075,12 @@ List attachments on a message.
|
|
|
1075
1075
|
**Returns:** List of attachments with name, MIME type, and `size` — the **decoded** byte count,
|
|
1076
1076
|
i.e. what `fetch-attachment` returns.
|
|
1077
1077
|
|
|
1078
|
+
**A numeric `id` resolves the same way the read tools resolve one** (2.20.21): the mailbox the id
|
|
1079
|
+
was listed from when that is known, else a bounded cross-mailbox scan that skips very large
|
|
1080
|
+
mailboxes and stops at its time budget. An id that several mailboxes hold is **refused**, with the
|
|
1081
|
+
candidates named, rather than answered for whichever copy came first — so list or search the
|
|
1082
|
+
mailbox you mean immediately before calling this. `imap:…` ids are never ambiguous.
|
|
1083
|
+
|
|
1078
1084
|
**Sizes over IMAP.** `BODYSTRUCTURE` reports a part's size in its transfer encoding, so a
|
|
1079
1085
|
base64 attachment's raw figure is ~4/3 of the file. `list-attachments` converts it: a
|
|
1080
1086
|
`Content-Disposition` `size=` parameter wins when present; 7bit/8bit/binary parts are exact
|
|
@@ -1096,6 +1102,11 @@ of overwriting an existing file. AppleScript and MIME fallback paths stage the
|
|
|
1096
1102
|
bytes privately, commit with an exclusive create, and leave the saved file
|
|
1097
1103
|
owner-readable/writable (`0600`).
|
|
1098
1104
|
|
|
1105
|
+
**A numeric `id` resolves the same way the read tools resolve one** (2.20.21): the mailbox the id
|
|
1106
|
+
was listed from when that is known, else the bounded cross-mailbox scan. An id that several
|
|
1107
|
+
mailboxes hold **saves nothing** rather than writing some other message's attachment under the
|
|
1108
|
+
name you asked for.
|
|
1109
|
+
|
|
1099
1110
|
| Parameter | Type | Required | Description |
|
|
1100
1111
|
| ---------------- | ------ | -------- | -------------------------- |
|
|
1101
1112
|
| `id` | string | Yes | Message ID |
|
package/build/index.js
CHANGED
|
@@ -83314,6 +83314,7 @@ var DATES_MARKER = "DATES";
|
|
|
83314
83314
|
var HTML_MARKER = "HTML";
|
|
83315
83315
|
var LOOKUP_ERROR_MARKER = "ERR";
|
|
83316
83316
|
var BATCH_FATAL = "FATAL";
|
|
83317
|
+
var ATTACHMENTS_MARKER = "ATT";
|
|
83317
83318
|
var RECON_TAG = "RECON";
|
|
83318
83319
|
var SNAP_TAG = "SNAP";
|
|
83319
83320
|
var SNAP_PAIR = "P";
|
|
@@ -83780,19 +83781,32 @@ function mailboxPathFragment(mailboxVar, outputVar) {
|
|
|
83780
83781
|
set _pathParent to _pathNext
|
|
83781
83782
|
end repeat`;
|
|
83782
83783
|
}
|
|
83783
|
-
function mailboxLookupFragment(collExpr, path3, outputVar) {
|
|
83784
|
-
|
|
83785
|
-
|
|
83784
|
+
function mailboxLookupFragment(collExpr, path3, outputVar, hintIndex) {
|
|
83785
|
+
const safePath = escapeForAppleScript(path3);
|
|
83786
|
+
const hint = hintIndex === void 0 ? "" : `
|
|
83787
|
+
try
|
|
83788
|
+
set _mbc to item ${hintIndex} of (${collExpr})
|
|
83789
|
+
set _mbcPath to ""
|
|
83790
|
+
${mailboxPathFragment("_mbc", "_mbcPath")}
|
|
83791
|
+
ignoring case
|
|
83792
|
+
if _mbcPath is "${safePath}" then set ${outputVar} to _mbc
|
|
83793
|
+
end ignoring
|
|
83794
|
+
end try`;
|
|
83795
|
+
const walk = `
|
|
83786
83796
|
repeat with _mbc in (${collExpr})
|
|
83787
83797
|
set _mbcPath to ""
|
|
83788
83798
|
${mailboxPathFragment("_mbc", "_mbcPath")}
|
|
83789
83799
|
ignoring case
|
|
83790
|
-
if _mbcPath is "${
|
|
83800
|
+
if _mbcPath is "${safePath}" then
|
|
83791
83801
|
set ${outputVar} to _mbc
|
|
83792
83802
|
exit repeat
|
|
83793
83803
|
end if
|
|
83794
83804
|
end ignoring
|
|
83795
83805
|
end repeat`;
|
|
83806
|
+
return `
|
|
83807
|
+
set ${outputVar} to missing value${hint}${hintIndex === void 0 ? walk : `
|
|
83808
|
+
if ${outputVar} is missing value then${walk}
|
|
83809
|
+
end if`}`;
|
|
83796
83810
|
}
|
|
83797
83811
|
var MAILBOX_ALIASES = {
|
|
83798
83812
|
inbox: ["INBOX", "Inbox", "inbox"],
|
|
@@ -84788,6 +84802,17 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84788
84802
|
resolveMailbox(mailbox, account) {
|
|
84789
84803
|
return resolveAppleMailboxPath(mailbox, this.getCachedMailboxNames(account));
|
|
84790
84804
|
}
|
|
84805
|
+
/**
|
|
84806
|
+
* The 1-based position of `path` in the account's cached mailbox list, which is
|
|
84807
|
+
* built by walking the account's `mailboxes` in order. `mailboxLookupFragment`
|
|
84808
|
+
* checks that one mailbox first instead of working out the path of every one.
|
|
84809
|
+
* Undefined when the path is not in the list; a stale position is harmless, the
|
|
84810
|
+
* fragment verifies the path and falls back to the full walk.
|
|
84811
|
+
*/
|
|
84812
|
+
mailboxIndexHint(account, path3) {
|
|
84813
|
+
const index = this.getCachedMailboxNames(account).indexOf(path3);
|
|
84814
|
+
return index >= 0 ? index + 1 : void 0;
|
|
84815
|
+
}
|
|
84791
84816
|
/**
|
|
84792
84817
|
* Non-throwing `resolveMailbox`, for callers comparing mailbox names AFTER
|
|
84793
84818
|
* a destructive op already ran (the forensics `sameMailbox` closures). An
|
|
@@ -84954,7 +84979,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84954
84979
|
${dateSetup}set outputText to ""
|
|
84955
84980
|
set _timedOut to false
|
|
84956
84981
|
set _notSearched to ""
|
|
84957
|
-
${mailboxLookupFragment(mbIter, targetMailbox, "theMailbox")}
|
|
84982
|
+
${mailboxLookupFragment(mbIter, targetMailbox, "theMailbox", this.mailboxIndexHint(targetAccount, targetMailbox))}
|
|
84958
84983
|
set msgCount to 0
|
|
84959
84984
|
if theMailbox is missing value then
|
|
84960
84985
|
set _timedOut to true
|
|
@@ -85686,7 +85711,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
85686
85711
|
set outputText to ""
|
|
85687
85712
|
set _timedOut to false
|
|
85688
85713
|
set _notSearched to ""
|
|
85689
|
-
${mailboxLookupFragment(mbIter, targetMailbox, "theMailbox")}
|
|
85714
|
+
${mailboxLookupFragment(mbIter, targetMailbox, "theMailbox", this.mailboxIndexHint(targetAccount, targetMailbox))}
|
|
85690
85715
|
set msgCount to 0
|
|
85691
85716
|
set skipped to 0
|
|
85692
85717
|
if theMailbox is missing value then
|
|
@@ -86903,14 +86928,7 @@ ${this.errorEmit(" ")}
|
|
|
86903
86928
|
* when AppleScript returns empty (known issue across all account types).
|
|
86904
86929
|
*/
|
|
86905
86930
|
listAttachments(id) {
|
|
86906
|
-
const
|
|
86907
|
-
try
|
|
86908
|
-
repeat with acct in accounts
|
|
86909
|
-
repeat with mb in mailboxes of acct
|
|
86910
|
-
try
|
|
86911
|
-
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
86912
|
-
if (count of matchingMsgs) > 0 then
|
|
86913
|
-
set msg to item 1 of matchingMsgs
|
|
86931
|
+
const attachmentLoop = `
|
|
86914
86932
|
set outputText to ""
|
|
86915
86933
|
set attCount to 0
|
|
86916
86934
|
-- Each property is read inside its own try: \`MIME type of att\` throws
|
|
@@ -86936,20 +86954,20 @@ ${this.errorEmit(" ")}
|
|
|
86936
86954
|
set outputText to outputText & attName & "${FIELD_SEP}" & attType & "${FIELD_SEP}" & attSize
|
|
86937
86955
|
set attCount to attCount + 1
|
|
86938
86956
|
end if
|
|
86939
|
-
end repeat
|
|
86940
|
-
|
|
86941
|
-
|
|
86942
|
-
|
|
86943
|
-
|
|
86944
|
-
|
|
86945
|
-
|
|
86946
|
-
|
|
86947
|
-
|
|
86948
|
-
|
|
86949
|
-
|
|
86950
|
-
|
|
86951
|
-
if (
|
|
86952
|
-
const items =
|
|
86957
|
+
end repeat`;
|
|
86958
|
+
this.lastMessageLookupError = void 0;
|
|
86959
|
+
const output = this.resolveById(
|
|
86960
|
+
id,
|
|
86961
|
+
`${attachmentLoop}
|
|
86962
|
+
return "${ATTACHMENTS_MARKER}" & outputText`,
|
|
86963
|
+
void 0
|
|
86964
|
+
);
|
|
86965
|
+
if (output === null) {
|
|
86966
|
+
const refusal = this.consumeLastMessageLookupError();
|
|
86967
|
+
if (refusal) throw new Error(refusal);
|
|
86968
|
+
}
|
|
86969
|
+
if (output?.startsWith(ATTACHMENTS_MARKER) && output.length > ATTACHMENTS_MARKER.length) {
|
|
86970
|
+
const items = output.slice(ATTACHMENTS_MARKER.length).split(RECORD_SEP);
|
|
86953
86971
|
const attachments = [];
|
|
86954
86972
|
for (const item of items) {
|
|
86955
86973
|
const parts = item.split(FIELD_SEP);
|
|
@@ -87007,14 +87025,28 @@ ${this.errorEmit(" ")}
|
|
|
87007
87025
|
}
|
|
87008
87026
|
};
|
|
87009
87027
|
const numericId = Number(id);
|
|
87010
|
-
|
|
87011
|
-
|
|
87012
|
-
|
|
87013
|
-
|
|
87014
|
-
|
|
87015
|
-
|
|
87016
|
-
|
|
87017
|
-
|
|
87028
|
+
this.lastMessageLookupError = void 0;
|
|
87029
|
+
const located = this.resolveById(
|
|
87030
|
+
id,
|
|
87031
|
+
`set _where to ""
|
|
87032
|
+
try
|
|
87033
|
+
${mailboxPathFragment("_hitMb", "_where")}
|
|
87034
|
+
end try
|
|
87035
|
+
return _hitAcct & "${FIELD_SEP}" & _where`,
|
|
87036
|
+
void 0
|
|
87037
|
+
);
|
|
87038
|
+
if (located === null) {
|
|
87039
|
+
const why = this.consumeLastMessageLookupError();
|
|
87040
|
+
if (why) {
|
|
87041
|
+
cleanupTemporaryDirectory();
|
|
87042
|
+
console.error(`Failed to save attachment: ${why}`);
|
|
87043
|
+
return false;
|
|
87044
|
+
}
|
|
87045
|
+
}
|
|
87046
|
+
const [holderAccount, holderMailbox] = (located ?? "").split(FIELD_SEP);
|
|
87047
|
+
if (holderAccount && holderMailbox)
|
|
87048
|
+
this.rememberLocation(String(id), holderAccount, holderMailbox);
|
|
87049
|
+
const saveAction = `
|
|
87018
87050
|
repeat with att in mail attachments of msg
|
|
87019
87051
|
if name of att is "${safeName}" then
|
|
87020
87052
|
set savePath to POSIX file "${safeTemporaryPath}"
|
|
@@ -87022,7 +87054,16 @@ ${this.errorEmit(" ")}
|
|
|
87022
87054
|
return "ok"
|
|
87023
87055
|
end if
|
|
87024
87056
|
end repeat
|
|
87025
|
-
return "error:Attachment not found"
|
|
87057
|
+
return "error:Attachment not found"`;
|
|
87058
|
+
const script = holderAccount && holderMailbox ? this.scopedByIdScript(holderAccount, holderMailbox, id, saveAction) : buildAppLevelScript(`
|
|
87059
|
+
try
|
|
87060
|
+
repeat with acct in accounts
|
|
87061
|
+
repeat with mb in mailboxes of acct
|
|
87062
|
+
try
|
|
87063
|
+
set matchingMsgs to (messages of mb whose id is ${numericId})
|
|
87064
|
+
if (count of matchingMsgs) > 0 then
|
|
87065
|
+
set msg to item 1 of matchingMsgs
|
|
87066
|
+
${saveAction}
|
|
87026
87067
|
end if
|
|
87027
87068
|
end try
|
|
87028
87069
|
end repeat
|
|
@@ -87166,7 +87207,7 @@ ${this.errorEmit(" ")}
|
|
|
87166
87207
|
const targetAccount = this.resolveAccount(account);
|
|
87167
87208
|
const targetMailbox = this.resolveMailbox(mailbox || "INBOX", targetAccount);
|
|
87168
87209
|
const command = `
|
|
87169
|
-
${mailboxLookupFragment("mailboxes", targetMailbox, "theMailbox")}
|
|
87210
|
+
${mailboxLookupFragment("mailboxes", targetMailbox, "theMailbox", this.mailboxIndexHint(targetAccount, targetMailbox))}
|
|
87170
87211
|
if theMailbox is missing value then error "Mailbox \\"${escapeForAppleScript(targetMailbox)}\\" not found"
|
|
87171
87212
|
return unread count of theMailbox`;
|
|
87172
87213
|
const script = buildAccountScopedScript(targetAccount, command);
|
package/package.json
CHANGED