apple-mail-mcp 2.20.20 → 2.20.21

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.
Files changed (3) hide show
  1. package/README.md +11 -0
  2. package/build/index.js +48 -31
  3. 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";
@@ -86903,14 +86904,7 @@ ${this.errorEmit(" ")}
86903
86904
  * when AppleScript returns empty (known issue across all account types).
86904
86905
  */
86905
86906
  listAttachments(id) {
86906
- const script = buildAppLevelScript(`
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
86907
+ const attachmentLoop = `
86914
86908
  set outputText to ""
86915
86909
  set attCount to 0
86916
86910
  -- Each property is read inside its own try: \`MIME type of att\` throws
@@ -86936,20 +86930,20 @@ ${this.errorEmit(" ")}
86936
86930
  set outputText to outputText & attName & "${FIELD_SEP}" & attType & "${FIELD_SEP}" & attSize
86937
86931
  set attCount to attCount + 1
86938
86932
  end if
86939
- end repeat
86940
- return outputText
86941
- end if
86942
- end try
86943
- end repeat
86944
- end repeat
86945
- return ""
86946
- on error errMsg
86947
- return ""
86948
- end try
86949
- `);
86950
- const result = executeAppleScript(script, { timeoutMs: 6e4 });
86951
- if (result.success && result.output.trim()) {
86952
- const items = result.output.split(RECORD_SEP);
86933
+ end repeat`;
86934
+ this.lastMessageLookupError = void 0;
86935
+ const output = this.resolveById(
86936
+ id,
86937
+ `${attachmentLoop}
86938
+ return "${ATTACHMENTS_MARKER}" & outputText`,
86939
+ void 0
86940
+ );
86941
+ if (output === null) {
86942
+ const refusal = this.consumeLastMessageLookupError();
86943
+ if (refusal) throw new Error(refusal);
86944
+ }
86945
+ if (output?.startsWith(ATTACHMENTS_MARKER) && output.length > ATTACHMENTS_MARKER.length) {
86946
+ const items = output.slice(ATTACHMENTS_MARKER.length).split(RECORD_SEP);
86953
86947
  const attachments = [];
86954
86948
  for (const item of items) {
86955
86949
  const parts = item.split(FIELD_SEP);
@@ -87007,14 +87001,28 @@ ${this.errorEmit(" ")}
87007
87001
  }
87008
87002
  };
87009
87003
  const numericId = Number(id);
87010
- const script = buildAppLevelScript(`
87011
- try
87012
- repeat with acct in accounts
87013
- repeat with mb in mailboxes of acct
87014
- try
87015
- set matchingMsgs to (messages of mb whose id is ${numericId})
87016
- if (count of matchingMsgs) > 0 then
87017
- set msg to item 1 of matchingMsgs
87004
+ this.lastMessageLookupError = void 0;
87005
+ const located = this.resolveById(
87006
+ id,
87007
+ `set _where to ""
87008
+ try
87009
+ ${mailboxPathFragment("_hitMb", "_where")}
87010
+ end try
87011
+ return _hitAcct & "${FIELD_SEP}" & _where`,
87012
+ void 0
87013
+ );
87014
+ if (located === null) {
87015
+ const why = this.consumeLastMessageLookupError();
87016
+ if (why) {
87017
+ cleanupTemporaryDirectory();
87018
+ console.error(`Failed to save attachment: ${why}`);
87019
+ return false;
87020
+ }
87021
+ }
87022
+ const [holderAccount, holderMailbox] = (located ?? "").split(FIELD_SEP);
87023
+ if (holderAccount && holderMailbox)
87024
+ this.rememberLocation(String(id), holderAccount, holderMailbox);
87025
+ const saveAction = `
87018
87026
  repeat with att in mail attachments of msg
87019
87027
  if name of att is "${safeName}" then
87020
87028
  set savePath to POSIX file "${safeTemporaryPath}"
@@ -87022,7 +87030,16 @@ ${this.errorEmit(" ")}
87022
87030
  return "ok"
87023
87031
  end if
87024
87032
  end repeat
87025
- return "error:Attachment not found"
87033
+ return "error:Attachment not found"`;
87034
+ const script = holderAccount && holderMailbox ? this.scopedByIdScript(holderAccount, holderMailbox, id, saveAction) : buildAppLevelScript(`
87035
+ try
87036
+ repeat with acct in accounts
87037
+ repeat with mb in mailboxes of acct
87038
+ try
87039
+ set matchingMsgs to (messages of mb whose id is ${numericId})
87040
+ if (count of matchingMsgs) > 0 then
87041
+ set msg to item 1 of matchingMsgs
87042
+ ${saveAction}
87026
87043
  end if
87027
87044
  end try
87028
87045
  end repeat
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.20.20",
3
+ "version": "2.20.21",
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",