apple-mail-mcp 2.19.6 → 2.19.8
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 +27 -13
- package/build/index.js +46 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -236,6 +236,19 @@ Search for messages matching criteria. Searches all accounts by default.
|
|
|
236
236
|
| `dateTo` | string | No | End date filter (e.g., "March 1, 2026") |
|
|
237
237
|
| `limit` | number | No | Max results, 1–500 (default: 50) |
|
|
238
238
|
|
|
239
|
+
**Returns:** List of matching messages with ID, date, subject, sender, and read state.
|
|
240
|
+
|
|
241
|
+
⚠️ **Row dates.** Since 2.19.7 every row — on both the IMAP and AppleScript
|
|
242
|
+
backends — carries both `dateSent` (the message's `Date:` header) and
|
|
243
|
+
`dateReceived` (mailbox arrival — IMAP `INTERNALDATE` or Mail's `date received`).
|
|
244
|
+
They differ legitimately by transit time; when they differ by **years**, the
|
|
245
|
+
mailbox was migrated or re-imported and the arrival timestamp was reset — trust
|
|
246
|
+
`dateSent` for chronology ([#224](https://github.com/sweetrb/apple-mail-mcp/issues/224)).
|
|
247
|
+
`dateSent` is omitted (not invented) when the message carries no parseable
|
|
248
|
+
`Date:` header, or when it is more than 7 days later than `dateReceived` — Mail
|
|
249
|
+
substitutes a timestamp of its own for a `Date:` header it cannot parse
|
|
250
|
+
([#234](https://github.com/sweetrb/apple-mail-mcp/issues/234)).
|
|
251
|
+
|
|
239
252
|
**Large mailboxes & partial results.** Apple Mail's AppleScript bridge cannot
|
|
240
253
|
search very large IMAP/Gmail mailboxes (tens of thousands of messages) before
|
|
241
254
|
the Apple Event times out — empirically even reading the newest 20 messages of
|
|
@@ -331,19 +344,20 @@ List messages in a mailbox.
|
|
|
331
344
|
|
|
332
345
|
**Returns:** List of messages with ID, date, subject, and sender.
|
|
333
346
|
|
|
334
|
-
⚠️ **Row dates
|
|
335
|
-
`dateSent` (the message's `Date:`
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
`
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
+
⚠️ **Row dates.** Since 2.19.7 every row — on both the **IMAP** and
|
|
348
|
+
**AppleScript** backends — carries both `dateSent` (the message's `Date:`
|
|
349
|
+
header) and `dateReceived` (mailbox arrival — IMAP `INTERNALDATE`, falling back
|
|
350
|
+
to the header date if the server withholds it; Mail's `date received` on the
|
|
351
|
+
AppleScript path). They differ legitimately by transit time; when they differ
|
|
352
|
+
by **years**, the mailbox was migrated or re-imported and the arrival timestamp
|
|
353
|
+
was reset — trust `dateSent` for chronology
|
|
354
|
+
([#224](https://github.com/sweetrb/apple-mail-mcp/issues/224)). Since 2.19.6 the
|
|
355
|
+
IMAP `dateSent` is recovered even when the server's own parse of the `Date:`
|
|
356
|
+
header failed (legacy locale dates such as `jue ago 30 13:55:12 2007`); both
|
|
357
|
+
backends omit `dateSent` (rather than reporting it) when it is more than 7 days
|
|
358
|
+
later than `dateReceived` ([#234](https://github.com/sweetrb/apple-mail-mcp/issues/234)).
|
|
359
|
+
Before 2.19.7 the AppleScript path carried only `dateReceived`. Sort order keys
|
|
360
|
+
on the header date on both backends, which is the stable one.
|
|
347
361
|
|
|
348
362
|
---
|
|
349
363
|
|
package/build/index.js
CHANGED
|
@@ -82203,7 +82203,10 @@ function buildAttachmentCommands(attachments) {
|
|
|
82203
82203
|
}
|
|
82204
82204
|
return commands;
|
|
82205
82205
|
}
|
|
82206
|
-
|
|
82206
|
+
function asDateToString(varName) {
|
|
82207
|
+
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)`;
|
|
82208
|
+
}
|
|
82209
|
+
var AS_DATE_TO_STRING = asDateToString("d");
|
|
82207
82210
|
var AS_MESSAGE_DATES_FRAGMENT = `set msgDateSent to ""
|
|
82208
82211
|
try
|
|
82209
82212
|
set d to date sent of msg
|
|
@@ -82263,6 +82266,12 @@ function buildMessageRowLoop(opts) {
|
|
|
82263
82266
|
on error
|
|
82264
82267
|
set _bulkOK to false
|
|
82265
82268
|
end try
|
|
82269
|
+
set _sentBulkOK to true
|
|
82270
|
+
try
|
|
82271
|
+
set _sentDates to date sent of _msgs
|
|
82272
|
+
on error
|
|
82273
|
+
set _sentBulkOK to false
|
|
82274
|
+
end try
|
|
82266
82275
|
repeat with _i from 1 to (count of _msgs)
|
|
82267
82276
|
if msgCount >= ${limit} then exit repeat
|
|
82268
82277
|
try
|
|
@@ -82292,8 +82301,17 @@ function buildMessageRowLoop(opts) {
|
|
|
82292
82301
|
set msgFlagged to flagged status of _m as string
|
|
82293
82302
|
end if${attRow}
|
|
82294
82303
|
set msgDateStr to ${AS_DATE_TO_STRING}
|
|
82304
|
+
set msgDateSentStr to ""
|
|
82305
|
+
try
|
|
82306
|
+
if _bulkOK and _sentBulkOK then
|
|
82307
|
+
set dSent to item _i of _sentDates
|
|
82308
|
+
else
|
|
82309
|
+
set dSent to date sent of (item _i of _msgs)
|
|
82310
|
+
end if
|
|
82311
|
+
set msgDateSentStr to ${asDateToString("dSent")}
|
|
82312
|
+
end try
|
|
82295
82313
|
if msgCount > 0 then set outputText to outputText & "${RECORD_SEP}"
|
|
82296
|
-
set outputText to outputText & msgId & "${FIELD_SEP}" & msgSubject & "${FIELD_SEP}" & msgSender & "${FIELD_SEP}" & msgDateStr & "${FIELD_SEP}" & msgRead & "${FIELD_SEP}" & msgFlagged${trailing}${attField}
|
|
82314
|
+
set outputText to outputText & msgId & "${FIELD_SEP}" & msgSubject & "${FIELD_SEP}" & msgSender & "${FIELD_SEP}" & msgDateStr & "${FIELD_SEP}" & msgDateSentStr & "${FIELD_SEP}" & msgRead & "${FIELD_SEP}" & msgFlagged${trailing}${attField}
|
|
82297
82315
|
set msgCount to msgCount + 1
|
|
82298
82316
|
${dateClose}
|
|
82299
82317
|
${offsetClose}
|
|
@@ -84147,9 +84165,12 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84147
84165
|
/**
|
|
84148
84166
|
* Parse message list output from AppleScript.
|
|
84149
84167
|
*
|
|
84168
|
+
* Row shape (since the dateSent field was added — see buildMessageRowLoop):
|
|
84169
|
+
* id|subject|sender|dateReceived|dateSent|read|flagged[|mailbox][|hasAtt]
|
|
84170
|
+
*
|
|
84150
84171
|
* Two emission schemas, disambiguated by length:
|
|
84151
|
-
*
|
|
84152
|
-
*
|
|
84172
|
+
* 8 fields: single-mailbox — ...|hasAtt (mailbox from caller)
|
|
84173
|
+
* 9 fields: all-mailboxes — ...|mailbox|hasAtt
|
|
84153
84174
|
*
|
|
84154
84175
|
* `hasAttachments` here is the fast-path AppleScript count only; it will
|
|
84155
84176
|
* false-negative for MIME-embedded attachments (a known AppleScript
|
|
@@ -84160,24 +84181,27 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84160
84181
|
const messages = [];
|
|
84161
84182
|
for (const item of items) {
|
|
84162
84183
|
const parts = item.split(FIELD_SEP);
|
|
84163
|
-
if (parts.length <
|
|
84184
|
+
if (parts.length < 7) continue;
|
|
84164
84185
|
let msgMailbox = mailbox;
|
|
84165
84186
|
let hasAttachments = false;
|
|
84166
|
-
if (rowsIncludeMailbox && parts.length >=
|
|
84167
|
-
msgMailbox = parts[
|
|
84168
|
-
hasAttachments = parts.length >=
|
|
84169
|
-
} else if (parts.length ===
|
|
84170
|
-
hasAttachments = parts[
|
|
84187
|
+
if (rowsIncludeMailbox && parts.length >= 8) {
|
|
84188
|
+
msgMailbox = parts[7];
|
|
84189
|
+
hasAttachments = parts.length >= 9 ? parts[8] === "true" : false;
|
|
84190
|
+
} else if (parts.length === 8) {
|
|
84191
|
+
hasAttachments = parts[7] === "true";
|
|
84171
84192
|
}
|
|
84172
84193
|
const msgId = parts[0].trim();
|
|
84194
|
+
const dateReceived = parseAppleScriptDate(parts[3]);
|
|
84195
|
+
const dateSent = plausibleDateSent(parseAppleScriptDate(parts[4]), dateReceived);
|
|
84173
84196
|
messages.push({
|
|
84174
84197
|
id: msgId,
|
|
84175
84198
|
subject: parts[1],
|
|
84176
84199
|
sender: parts[2],
|
|
84177
84200
|
recipients: [],
|
|
84178
|
-
dateReceived
|
|
84179
|
-
|
|
84180
|
-
|
|
84201
|
+
dateReceived,
|
|
84202
|
+
...dateSent ? { dateSent } : {},
|
|
84203
|
+
isRead: parts[5] === "true",
|
|
84204
|
+
isFlagged: parts[6] === "true",
|
|
84181
84205
|
isJunk: false,
|
|
84182
84206
|
isDeleted: false,
|
|
84183
84207
|
mailbox: msgMailbox,
|
|
@@ -84280,7 +84304,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84280
84304
|
`;
|
|
84281
84305
|
}
|
|
84282
84306
|
const script = buildAppLevelScript(sendCommand);
|
|
84283
|
-
const result = executeAppleScript(script, { timeoutMs: 6e4, maxRetries:
|
|
84307
|
+
const result = executeAppleScript(script, { timeoutMs: 6e4, maxRetries: 1 });
|
|
84284
84308
|
if (!result.success) {
|
|
84285
84309
|
console.error(`Failed to send email: ${result.error}`);
|
|
84286
84310
|
return false;
|
|
@@ -84409,7 +84433,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
84409
84433
|
`;
|
|
84410
84434
|
}
|
|
84411
84435
|
const script = buildAppLevelScript(draftCommand);
|
|
84412
|
-
const result = executeAppleScript(script, { timeoutMs: 6e4, maxRetries:
|
|
84436
|
+
const result = executeAppleScript(script, { timeoutMs: 6e4, maxRetries: 1 });
|
|
84413
84437
|
if (!result.success) {
|
|
84414
84438
|
console.error(`Failed to create draft: ${result.error}`);
|
|
84415
84439
|
return false;
|
|
@@ -86826,6 +86850,13 @@ function messageSummary(m) {
|
|
|
86826
86850
|
// follow-up) — omitted-as-empty, never invented, same contract as the IMAP
|
|
86827
86851
|
// rows' `isoOrEmpty`.
|
|
86828
86852
|
dateReceived: m.dateReceived instanceof Date ? Number.isNaN(m.dateReceived.getTime()) ? "" : m.dateReceived.toISOString() : m.dateReceived,
|
|
86853
|
+
// Same omitted-as-empty-string contract as dateReceived above, and the
|
|
86854
|
+
// same shape the IMAP path's `structuredRow` already emits for
|
|
86855
|
+
// `dateSent`. `m.dateSent` is only ever set to an already-plausible, valid
|
|
86856
|
+
// Date here (appleMailManager.ts's `parseMessageList` applies the
|
|
86857
|
+
// `plausibleDateSent` guard before populating it), so this mainly covers
|
|
86858
|
+
// the "absent" case, but stays defensive against an invalid Date too.
|
|
86859
|
+
dateSent: m.dateSent instanceof Date ? Number.isNaN(m.dateSent.getTime()) ? "" : m.dateSent.toISOString() : "",
|
|
86829
86860
|
isRead: m.isRead,
|
|
86830
86861
|
isFlagged: m.isFlagged,
|
|
86831
86862
|
mailbox: m.mailbox,
|
package/package.json
CHANGED