@marlinjai/email-mcp 1.2.0 → 1.2.1

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/dist/index.js CHANGED
@@ -7680,11 +7680,16 @@ var init_adapter2 = __esm({
7680
7680
  }
7681
7681
  this.accountId = credentials.id;
7682
7682
  this.accessToken = credentials.oauth.access_token;
7683
- this.client = Client.init({
7683
+ const client = Client.init({
7684
7684
  authProvider: (done) => {
7685
7685
  done(null, this.accessToken);
7686
7686
  }
7687
7687
  });
7688
+ const originalApi = client.api.bind(client);
7689
+ client.api = (path3) => {
7690
+ return originalApi(path3).header("Prefer", 'IdType="ImmutableId"');
7691
+ };
7692
+ this.client = client;
7688
7693
  }
7689
7694
  async disconnect() {
7690
7695
  this.client = null;
@@ -8389,60 +8394,96 @@ var init_adapter3 = __esm({
8389
8394
  throw formatImapError(error48, `Failed to open folder "${folder}"`);
8390
8395
  }
8391
8396
  try {
8397
+ const mailboxExists = this.client.mailbox?.exists ?? -1;
8398
+ if (mailboxExists === 0) {
8399
+ return [];
8400
+ }
8392
8401
  const criteria = this.buildSearchCriteria(query);
8393
- const searchResult = await this.client.search(
8394
- Object.keys(criteria).length > 0 ? criteria : { all: true },
8395
- { uid: true }
8396
- );
8397
- const allUids = Array.isArray(searchResult) ? searchResult : [];
8402
+ const hasCriteria = Object.keys(criteria).length > 0;
8403
+ let allUids;
8404
+ try {
8405
+ const searchResult = await this.client.search(
8406
+ hasCriteria ? criteria : { all: true },
8407
+ { uid: true }
8408
+ );
8409
+ allUids = Array.isArray(searchResult) ? searchResult : [];
8410
+ } catch (searchError) {
8411
+ if (!hasCriteria) {
8412
+ allUids = await this.collectUidsViaFetch(query);
8413
+ } else {
8414
+ throw searchError;
8415
+ }
8416
+ }
8398
8417
  const offset = query.offset || 0;
8399
8418
  const slicedUids = query.limit ? allUids.slice(offset, offset + query.limit) : allUids.slice(offset);
8400
8419
  if (slicedUids.length === 0) return [];
8401
- const emails = [];
8402
- if (query.returnBody) {
8403
- for await (const msg of this.client.fetch(slicedUids, { source: true, uid: true, flags: true })) {
8404
- const parsed = await simpleParser(msg.source);
8405
- parsed.flags = msg.flags;
8406
- emails.push(mapParsedEmail(parsed, folder, this.accountId, msg.uid));
8407
- }
8408
- } else {
8409
- for await (const msg of this.client.fetch(slicedUids, {
8410
- envelope: true,
8411
- uid: true,
8412
- flags: true,
8413
- bodyStructure: true
8414
- })) {
8415
- const env = msg.envelope;
8416
- emails.push({
8417
- id: String(msg.uid),
8418
- accountId: this.accountId,
8419
- threadId: env.messageId || void 0,
8420
- folder,
8421
- from: env.from?.[0] ? { name: env.from[0].name || void 0, email: env.from[0].address || "" } : { email: "" },
8422
- to: (env.to || []).map((a) => ({ name: a.name || void 0, email: a.address || "" })),
8423
- cc: env.cc?.length ? env.cc.map((a) => ({ name: a.name || void 0, email: a.address || "" })) : void 0,
8424
- bcc: env.bcc?.length ? env.bcc.map((a) => ({ name: a.name || void 0, email: a.address || "" })) : void 0,
8425
- subject: env.subject || "(no subject)",
8426
- date: env.date ? new Date(env.date).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
8427
- body: { text: void 0, html: void 0 },
8428
- snippet: env.subject || "",
8429
- attachments: [],
8430
- flags: {
8431
- read: msg.flags?.has("\\Seen") ?? false,
8432
- starred: msg.flags?.has("\\Flagged") ?? false,
8433
- flagged: msg.flags?.has("\\Flagged") ?? false,
8434
- draft: msg.flags?.has("\\Draft") ?? false
8435
- }
8436
- });
8437
- }
8438
- }
8439
- return emails;
8420
+ return await this.fetchEmails(slicedUids, folder, query.returnBody);
8440
8421
  } catch (error48) {
8441
8422
  throw formatImapError(error48, `Search failed in folder "${folder}"`);
8442
8423
  } finally {
8443
8424
  lock.release();
8444
8425
  }
8445
8426
  }
8427
+ /**
8428
+ * Fallback UID collection when UID SEARCH fails (e.g. iCloud "Invalid message number").
8429
+ * Uses FETCH 1:* with sequence numbers to collect UIDs directly, optionally filtering
8430
+ * by flag-based criteria (unread, starred).
8431
+ */
8432
+ async collectUidsViaFetch(query) {
8433
+ if (!this.client) return [];
8434
+ const uids = [];
8435
+ for await (const msg of this.client.fetch("1:*", { uid: true, flags: true })) {
8436
+ if (query.unreadOnly && msg.flags?.has("\\Seen")) continue;
8437
+ if (query.starredOnly && !msg.flags?.has("\\Flagged")) continue;
8438
+ uids.push(msg.uid);
8439
+ }
8440
+ return uids;
8441
+ }
8442
+ /**
8443
+ * Fetches email data for a set of UIDs, either with full body or lightweight headers.
8444
+ */
8445
+ async fetchEmails(uids, folder, returnBody) {
8446
+ if (!this.client) return [];
8447
+ const emails = [];
8448
+ if (returnBody) {
8449
+ for await (const msg of this.client.fetch(uids, { source: true, uid: true, flags: true })) {
8450
+ const parsed = await simpleParser(msg.source);
8451
+ parsed.flags = msg.flags;
8452
+ emails.push(mapParsedEmail(parsed, folder, this.accountId, msg.uid));
8453
+ }
8454
+ } else {
8455
+ for await (const msg of this.client.fetch(uids, {
8456
+ envelope: true,
8457
+ uid: true,
8458
+ flags: true,
8459
+ bodyStructure: true
8460
+ })) {
8461
+ const env = msg.envelope;
8462
+ emails.push({
8463
+ id: String(msg.uid),
8464
+ accountId: this.accountId,
8465
+ threadId: env.messageId || void 0,
8466
+ folder,
8467
+ from: env.from?.[0] ? { name: env.from[0].name || void 0, email: env.from[0].address || "" } : { email: "" },
8468
+ to: (env.to || []).map((a) => ({ name: a.name || void 0, email: a.address || "" })),
8469
+ cc: env.cc?.length ? env.cc.map((a) => ({ name: a.name || void 0, email: a.address || "" })) : void 0,
8470
+ bcc: env.bcc?.length ? env.bcc.map((a) => ({ name: a.name || void 0, email: a.address || "" })) : void 0,
8471
+ subject: env.subject || "(no subject)",
8472
+ date: env.date ? new Date(env.date).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
8473
+ body: { text: void 0, html: void 0 },
8474
+ snippet: env.subject || "",
8475
+ attachments: [],
8476
+ flags: {
8477
+ read: msg.flags?.has("\\Seen") ?? false,
8478
+ starred: msg.flags?.has("\\Flagged") ?? false,
8479
+ flagged: msg.flags?.has("\\Flagged") ?? false,
8480
+ draft: msg.flags?.has("\\Draft") ?? false
8481
+ }
8482
+ });
8483
+ }
8484
+ }
8485
+ return emails;
8486
+ }
8446
8487
  async getEmail(id, folder) {
8447
8488
  if (!this.client) throw new Error("Not connected");
8448
8489
  const targetFolder = folder || "INBOX";