apple-mail-mcp 2.20.15 → 2.20.17

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
@@ -954,7 +954,10 @@ nodemailer path `send-email` uses, so the Sent-folder copy (`sentCopy`) carries
954
954
  On the AppleScript transport they are added with `make new attachment` **after** the
955
955
  reply content is set and before `save`/`send` (inline items are written to `0600` temp
956
956
  files and removed afterwards), so a `send: false` draft contains both the attachments and
957
- the quoted original. Results report `attachmentCount`.
957
+ the quoted original. `make new attachment` returns before Mail has loaded the file, so the
958
+ script waits until Mail counts every file (bounded at 15 s) before saving or sending
959
+ (2.20.16, #293; the same wait applies to `send-email` and `create-draft`). Results report
960
+ `attachmentCount`.
958
961
 
959
962
  **Delivery:** `imap:` IDs are read directly from their encoded account, mailbox, and UID. Numeric IDs are read through Mail.app. With SMTP configured, replies use clean MIME with the original `Message-ID` in `In-Reply-To` and the full `References` chain. Only the original plain-text body is quoted; the new text is not. Pass `transport: "smtp"` to require this path, or `transport: "applescript"` to use Mail.app explicitly.
960
963
 
package/build/index.js CHANGED
@@ -83374,10 +83374,30 @@ function buildAttachmentCommands(attachments) {
83374
83374
  }
83375
83375
  return commands;
83376
83376
  }
83377
+ var ATTACHMENT_SETTLE_TIMEOUT_S = 15;
83378
+ var ATTACHMENT_SETTLE_GRACE_S = 1;
83379
+ function attachmentSettleBlock(msgVar, expected) {
83380
+ if (expected <= 0) return "";
83381
+ return `
83382
+ set attachDeadline to (current date) + ${ATTACHMENT_SETTLE_TIMEOUT_S}
83383
+ repeat
83384
+ set attachCount to 0
83385
+ try
83386
+ set attachCount to count of attachments of content of ${msgVar}
83387
+ end try
83388
+ if attachCount >= ${expected} then exit repeat
83389
+ if (current date) > attachDeadline then exit repeat
83390
+ delay 0.25
83391
+ end repeat
83392
+ delay ${ATTACHMENT_SETTLE_GRACE_S}`;
83393
+ }
83394
+ function countAttachmentCommands(commands) {
83395
+ return (commands.match(/make new attachment/g) || []).length;
83396
+ }
83377
83397
  function composeAttachmentBlock(msgVar, paths) {
83378
83398
  const commands = buildAttachmentCommands(paths);
83379
83399
  return commands ? `tell ${msgVar}
83380
- ${commands}end tell` : "";
83400
+ ${commands}end tell${attachmentSettleBlock(msgVar, paths.length)}` : "";
83381
83401
  }
83382
83402
  function asDateToString(varName) {
83383
83403
  return `((year of ${varName}) as string) & "-" & ((month of ${varName} as integer) as string) & "-" & ((day of ${varName}) as string) & "-" & ((hours of ${varName}) as string) & "-" & ((minutes of ${varName}) as string) & "-" & ((seconds of ${varName}) as string)`;
@@ -83417,16 +83437,10 @@ function buildMessageRowLoop(opts) {
83417
83437
  -- outside date range; skip
83418
83438
  else` : "";
83419
83439
  const dateClose = dateFilter ? `end if` : "";
83420
- const attBulk = withAttachments ? `
83421
- set _atts to mail attachments of _msgs` : "";
83422
83440
  const attRow = withAttachments ? `
83423
83441
  set msgHasAtt to "false"
83424
83442
  try
83425
- if _bulkOK then
83426
- if (count of (item _i of _atts)) > 0 then set msgHasAtt to "true"
83427
- else
83428
- if (count of mail attachments of (item _i of _msgs)) > 0 then set msgHasAtt to "true"
83429
- end if
83443
+ if (count of mail attachments of (item _i of _msgs)) > 0 then set msgHasAtt to "true"
83430
83444
  end try` : "";
83431
83445
  const attField = withAttachments ? ` & "${FIELD_SEP}" & msgHasAtt` : "";
83432
83446
  return `
@@ -83439,7 +83453,7 @@ function buildMessageRowLoop(opts) {
83439
83453
  set _dates to date received of _msgs
83440
83454
  set _reads to read status of _msgs
83441
83455
  set _flags to flagged status of _msgs
83442
- set _flagColors to flag index of _msgs${attBulk}
83456
+ set _flagColors to flag index of _msgs
83443
83457
  on error
83444
83458
  set _bulkOK to false
83445
83459
  end try
@@ -84801,7 +84815,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84801
84815
  ignoring case
84802
84816
  if _wantNames contains (name of mb) then
84803
84817
  try
84804
- ${buildMessageRowLoop({ collection: `messages of mb ${searchCondition}`, limit, dedup: true, dateFilter, trailing: ` & "${FIELD_SEP}" & mbName` })}
84818
+ ${buildMessageRowLoop({ collection: `messages of mb ${searchCondition}`, limit, dedup: true, dateFilter, withAttachments: true, trailing: ` & "${FIELD_SEP}" & mbName` })}
84805
84819
  on error _errMsg number _errNum
84806
84820
  set _timedOut to true
84807
84821
  set _notSearched to _notSearched & mbName & "${DIAG_ITEM_SEP}"
@@ -84823,7 +84837,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84823
84837
  set _notSearched to "${escapeForAppleScript(targetMailbox)}${DIAG_ITEM_SEP}"
84824
84838
  else
84825
84839
  try
84826
- ${buildMessageRowLoop({ collection: `messages of theMailbox ${searchCondition}`, limit, dateFilter })}
84840
+ ${buildMessageRowLoop({ collection: `messages of theMailbox ${searchCondition}`, limit, dateFilter, withAttachments: true })}
84827
84841
  on error _errMsg number _errNum
84828
84842
  set _timedOut to true
84829
84843
  set _notSearched to "${escapeForAppleScript(targetMailbox)}${DIAG_ITEM_SEP}"
@@ -84861,7 +84875,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84861
84875
  set _skipped to _skipped & mbName & " (" & (mbCount as string) & ")${DIAG_ITEM_SEP}"
84862
84876
  else
84863
84877
  try
84864
- ${buildMessageRowLoop({ collection: `messages of mb ${searchCondition}`, limit, dedup: true, dateFilter, trailing: ` & "${FIELD_SEP}" & mbName` })}
84878
+ ${buildMessageRowLoop({ collection: `messages of mb ${searchCondition}`, limit, dedup: true, dateFilter, withAttachments: true, trailing: ` & "${FIELD_SEP}" & mbName` })}
84865
84879
  on error _errMsg number _errNum
84866
84880
  set _timedOut to true
84867
84881
  set _notSearched to _notSearched & mbName & "${DIAG_ITEM_SEP}"
@@ -85730,12 +85744,15 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
85730
85744
  }
85731
85745
  /**
85732
85746
  * Build and run the AppleScript compose for send-email (`send`) and
85733
- * create-draft (`draft`): pin the sender when `account` is given, verify it
85734
- * before the message leaves, and report the sender Mail actually used.
85747
+ * create-draft (`draft`): pin the sender when `account` is given, wait for
85748
+ * any attachments to load (attachmentSettleBlock), verify the sender before
85749
+ * the message leaves, and report the sender Mail actually used. A draft is
85750
+ * saved and closed explicitly rather than left to Mail's autosave (#293).
85735
85751
  */
85736
85752
  composeWithCommands(mode, recipientCommands, safeSubject, safeBody, account, attachmentCommands) {
85737
85753
  const sender = this.resolveSender(account);
85738
85754
  if ("error" in sender) return { success: false, error: sender.error };
85755
+ const settle2 = attachmentSettleBlock("newMessage", countAttachmentCommands(attachmentCommands));
85739
85756
  const prefix = mode === "send" ? SENT_PREFIX : DRAFT_PREFIX;
85740
85757
  const script = buildAppLevelScript(`
85741
85758
  set newMessage to make new outgoing message with properties {subject:"${safeSubject}", content:"${safeBody}", visible:${mode === "send"}}
@@ -85743,9 +85760,9 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
85743
85760
  ${recipientCommands}
85744
85761
  ${sender.setSender}
85745
85762
  ${attachmentCommands}
85746
- end tell
85763
+ end tell${settle2}
85747
85764
  ${sender.guard}
85748
- ${mode === "send" ? "send newMessage" : ""}
85765
+ ${mode === "send" ? "send newMessage" : "save newMessage\n close newMessage saving yes"}
85749
85766
  return "${prefix}" & actualSender
85750
85767
  `);
85751
85768
  const result = executeAppleScript(script, { timeoutMs: 6e4, maxRetries: 1 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.20.15",
3
+ "version": "2.20.17",
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",