apple-mail-mcp 2.19.1 → 2.19.3

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
@@ -331,6 +331,16 @@ List messages in a mailbox.
331
331
 
332
332
  **Returns:** List of messages with ID, date, subject, and sender.
333
333
 
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
+ On the **AppleScript** path rows carry only `dateReceived` (Mail's `date
341
+ received`); `dateSent` is not yet emitted there. Sort order keys on the header
342
+ date on both backends, which is the stable one.
343
+
334
344
  ---
335
345
 
336
346
  #### `send-email`
package/build/cli.js CHANGED
@@ -58093,13 +58093,25 @@ function formatRow(m, account, path) {
58093
58093
  const read = m.flags?.has("\\Seen") ? "read" : "unread";
58094
58094
  return ` - ID: ${encodeImapId(account, path, m.uid)} | ${date} | ${subject} (from: ${from}) [${read}]`;
58095
58095
  }
58096
+ function isoOrEmpty(d) {
58097
+ if (!d) return "";
58098
+ const parsed = d instanceof Date ? d : new Date(d);
58099
+ return Number.isNaN(parsed.getTime()) ? "" : parsed.toISOString();
58100
+ }
58096
58101
  function structuredRow(m, account, path) {
58097
58102
  const env = m.envelope ?? {};
58098
58103
  return {
58099
58104
  id: encodeImapId(account, path, m.uid),
58100
58105
  subject: env.subject || "(no subject)",
58101
58106
  sender: senderName(env.from),
58102
- dateReceived: env.date ? new Date(env.date).toISOString() : "",
58107
+ // ⚠️ `env.date` is the `Date:` HEADER — imapflow builds ENVELOPE from the
58108
+ // header block — so emitting it as `dateReceived` made the same field name
58109
+ // mean "sent" here and "arrived" on the AppleScript path. Both are now
58110
+ // emitted under the name that is true of them, matching `messageSummary`.
58111
+ // `dateReceived` falls back to the header date when the server withheld
58112
+ // INTERNALDATE, which is the old behaviour and never invents a value.
58113
+ dateSent: isoOrEmpty(env.date),
58114
+ dateReceived: isoOrEmpty(m.internalDate ?? env.date),
58103
58115
  isRead: m.flags?.has("\\Seen") ?? false,
58104
58116
  isFlagged: m.flags?.has("\\Flagged") ?? false,
58105
58117
  flagColorIndex: mailFlagColorIndex(m.flags),
@@ -58145,7 +58157,11 @@ async function fetchMailboxMatches(client, path, criteria, newestCount) {
58145
58157
  // BODYSTRUCTURE rides along so `hasAttachments` is computed rather
58146
58158
  // than assumed. Measured on 50 real messages: ~390ms -> ~465ms for
58147
58159
  // the fetch (~17%), same single round trip, no extra request.
58148
- { envelope: true, flags: true, bodyStructure: true },
58160
+ //
58161
+ // INTERNALDATE rides along for the same reason, and is why `dateReceived`
58162
+ // can finally mean what it says: imapflow's `envelope.date` is built from
58163
+ // the header block, so it IS the `Date:` header, not arrival time.
58164
+ { envelope: true, flags: true, bodyStructure: true, internalDate: true },
58149
58165
  { uid: true }
58150
58166
  )) {
58151
58167
  byUid.set(msg.uid, msg);
package/build/index.js CHANGED
@@ -65503,13 +65503,25 @@ function formatRow(m, account, path) {
65503
65503
  const read = m.flags?.has("\\Seen") ? "read" : "unread";
65504
65504
  return ` - ID: ${encodeImapId(account, path, m.uid)} | ${date3} | ${subject} (from: ${from}) [${read}]`;
65505
65505
  }
65506
+ function isoOrEmpty(d) {
65507
+ if (!d) return "";
65508
+ const parsed = d instanceof Date ? d : new Date(d);
65509
+ return Number.isNaN(parsed.getTime()) ? "" : parsed.toISOString();
65510
+ }
65506
65511
  function structuredRow(m, account, path) {
65507
65512
  const env = m.envelope ?? {};
65508
65513
  return {
65509
65514
  id: encodeImapId(account, path, m.uid),
65510
65515
  subject: env.subject || "(no subject)",
65511
65516
  sender: senderName(env.from),
65512
- dateReceived: env.date ? new Date(env.date).toISOString() : "",
65517
+ // ⚠️ `env.date` is the `Date:` HEADER — imapflow builds ENVELOPE from the
65518
+ // header block — so emitting it as `dateReceived` made the same field name
65519
+ // mean "sent" here and "arrived" on the AppleScript path. Both are now
65520
+ // emitted under the name that is true of them, matching `messageSummary`.
65521
+ // `dateReceived` falls back to the header date when the server withheld
65522
+ // INTERNALDATE, which is the old behaviour and never invents a value.
65523
+ dateSent: isoOrEmpty(env.date),
65524
+ dateReceived: isoOrEmpty(m.internalDate ?? env.date),
65513
65525
  isRead: m.flags?.has("\\Seen") ?? false,
65514
65526
  isFlagged: m.flags?.has("\\Flagged") ?? false,
65515
65527
  flagColorIndex: mailFlagColorIndex(m.flags),
@@ -65555,7 +65567,11 @@ async function fetchMailboxMatches(client, path, criteria, newestCount) {
65555
65567
  // BODYSTRUCTURE rides along so `hasAttachments` is computed rather
65556
65568
  // than assumed. Measured on 50 real messages: ~390ms -> ~465ms for
65557
65569
  // the fetch (~17%), same single round trip, no extra request.
65558
- { envelope: true, flags: true, bodyStructure: true },
65570
+ //
65571
+ // INTERNALDATE rides along for the same reason, and is why `dateReceived`
65572
+ // can finally mean what it says: imapflow's `envelope.date` is built from
65573
+ // the header block, so it IS the `Date:` header, not arrival time.
65574
+ { envelope: true, flags: true, bodyStructure: true, internalDate: true },
65559
65575
  { uid: true }
65560
65576
  )) {
65561
65577
  byUid.set(msg.uid, msg);
@@ -82083,7 +82099,7 @@ function parseAppleScriptDate(dateStr) {
82083
82099
  const withoutPrefix = dateStr.replace(/^date\s+/, "");
82084
82100
  const normalized = withoutPrefix.replace(" at ", " ");
82085
82101
  const parsed = new Date(normalized);
82086
- return isNaN(parsed.getTime()) ? /* @__PURE__ */ new Date() : parsed;
82102
+ return isNaN(parsed.getTime()) ? /* @__PURE__ */ new Date(NaN) : parsed;
82087
82103
  }
82088
82104
  function buildAppleScriptDate(varName, d) {
82089
82105
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.19.1",
3
+ "version": "2.19.3",
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",