apple-mail-mcp 2.19.6 → 2.19.7

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 +27 -13
  2. package/build/index.js +44 -13
  3. 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 differ by backend.** On the **IMAP** path each row carries both
335
- `dateSent` (the message's `Date:` header) and `dateReceived` (mailbox arrival —
336
- `INTERNALDATE`, falling back to the header date if the server withholds it).
337
- They differ legitimately by transit time; when they differ by **years**, the
338
- mailbox was migrated or re-imported and the arrival timestamp was reset — trust
339
- `dateSent` for chronology ([#224](https://github.com/sweetrb/apple-mail-mcp/issues/224)).
340
- Since 2.19.6 the IMAP `dateSent` is recovered even when the server's own parse of
341
- the `Date:` header failed (legacy locale dates such as `jue ago 30 13:55:12 2007`),
342
- and is omitted rather than reported when it is more than 7 days later than
343
- `dateReceived` ([#234](https://github.com/sweetrb/apple-mail-mcp/issues/234)).
344
- On the **AppleScript** path rows carry only `dateReceived` (Mail's `date
345
- received`); `dateSent` is not yet emitted there. Sort order keys on the header
346
- date on both backends, which is the stable one.
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
- var AS_DATE_TO_STRING = `((year of d) as string) & "-" & ((month of d as integer) as string) & "-" & ((day of d) as string) & "-" & ((hours of d) as string) & "-" & ((minutes of d) as string) & "-" & ((seconds of d) as string)`;
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
- * 7 fields: single-mailbox — ...|hasAtt (mailbox from caller)
84152
- * 8 fields: all-mailboxes — ...|mailbox|hasAtt
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 < 6) continue;
84184
+ if (parts.length < 7) continue;
84164
84185
  let msgMailbox = mailbox;
84165
84186
  let hasAttachments = false;
84166
- if (rowsIncludeMailbox && parts.length >= 7) {
84167
- msgMailbox = parts[6];
84168
- hasAttachments = parts.length >= 8 ? parts[7] === "true" : false;
84169
- } else if (parts.length === 7) {
84170
- hasAttachments = parts[6] === "true";
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: parseAppleScriptDate(parts[3]),
84179
- isRead: parts[4] === "true",
84180
- isFlagged: parts[5] === "true",
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,
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.19.6",
3
+ "version": "2.19.7",
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",