apple-mail-mcp 2.20.3 → 2.20.5
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 +50 -30
- package/build/cli.js +93 -6
- package/build/index.js +497 -224
- package/docs/IMAP-SETUP.md +27 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -281,15 +281,28 @@ human reader; the same information is also returned as structured fields on
|
|
|
281
281
|
`search-messages` and `list-messages`, so a caller can tell _"nothing matched"_
|
|
282
282
|
apart from _"I did not look everywhere"_ without parsing the text:
|
|
283
283
|
|
|
284
|
-
| Field | Type | Meaning
|
|
285
|
-
| ----------------------- | -------- |
|
|
286
|
-
| `partial` | boolean | Coverage was incomplete — **the result is not a confirmed "no such mail"**. True whenever any field below is non-empty.
|
|
287
|
-
| `skippedLargeMailboxes` | string[] | Mailboxes never scanned because their message count exceeded `APPLE_MAIL_MAX_SEARCH_MAILBOX`, formatted `"Account / Mailbox (count)"` — e.g. `"iCloud / Archive (90694)"`.
|
|
288
|
-
| `notSearchedMailboxes` | string[] | Mailboxes that _were_ reached but timed out or errored mid-scan, formatted `"Account / Mailbox"`. Also carries the IMAP path's `failedMailboxes`.
|
|
289
|
-
| `timedOutAccounts` | string[] | Accounts whose whole-account AppleScript was killed by the per-account time budget — nothing from that account was searched.
|
|
290
|
-
| `failedMailboxes` | string[] | IMAP-backend mailboxes that errored. These are merged into `notSearchedMailboxes` as well; read that field unless you need to attribute the failure to the IMAP path specifically.
|
|
291
|
-
| `failedMailboxReasons` | object | The IMAP server's own error text for each entry in `failedMailboxes`, keyed the same way.
|
|
292
|
-
| `omittedMessages` | object[] | IMAP messages that belong on the page but whose `FETCH` response could not be read even with a reduced item set — `{ id, mailbox, uid, reason }`. The page is short by exactly these; the `id` still works with `get-message` / `get-message-headers`. ([#256](https://github.com/sweetrb/apple-mail-mcp/issues/256))
|
|
284
|
+
| Field | Type | Meaning |
|
|
285
|
+
| ----------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
286
|
+
| `partial` | boolean | Coverage was incomplete — **the result is not a confirmed "no such mail"**. True whenever any field below is non-empty. |
|
|
287
|
+
| `skippedLargeMailboxes` | string[] | Mailboxes never scanned because their message count exceeded `APPLE_MAIL_MAX_SEARCH_MAILBOX`, formatted `"Account / Mailbox (count)"` — e.g. `"iCloud / Archive (90694)"`. |
|
|
288
|
+
| `notSearchedMailboxes` | string[] | Mailboxes that _were_ reached but timed out or errored mid-scan, formatted `"Account / Mailbox"`. Also carries the IMAP path's `failedMailboxes`. |
|
|
289
|
+
| `timedOutAccounts` | string[] | Accounts whose whole-account AppleScript was killed by the per-account time budget — nothing from that account was searched. |
|
|
290
|
+
| `failedMailboxes` | string[] | IMAP-backend mailboxes that errored. These are merged into `notSearchedMailboxes` as well; read that field unless you need to attribute the failure to the IMAP path specifically. |
|
|
291
|
+
| `failedMailboxReasons` | object | The IMAP server's own error text for each entry in `failedMailboxes`, keyed the same way. |
|
|
292
|
+
| `omittedMessages` | object[] | IMAP messages that belong on the page but whose `FETCH` response could not be read even with a reduced item set — `{ id, mailbox, uid, reason }`. The page is short by exactly these; the `id` still works with `get-message` / `get-message-headers`. ([#256](https://github.com/sweetrb/apple-mail-mcp/issues/256)) |
|
|
293
|
+
| `timedOutMailboxes` | string[] | IMAP mailboxes the search did not finish because the call was **cancelled** (`notifications/cancelled`) or reached its **deadline** (`APPLE_MAIL_MCP_SEARCH_DEADLINE_MS`, default 45s), formatted `"Account / Mailbox"`; an account never reached is `"Account / *"`. Results from the mailboxes that did finish are still returned. ([#276](https://github.com/sweetrb/apple-mail-mcp/issues/276)) |
|
|
294
|
+
| `stoppedBy` | string | `"deadline"` or `"cancelled"` — present only with `timedOutMailboxes`. |
|
|
295
|
+
|
|
296
|
+
**Deadline and cancellation ([#276](https://github.com/sweetrb/apple-mail-mcp/issues/276)).** Tool
|
|
297
|
+
calls run one at a time (so they cannot race into Mail.app), which means a long search holds every
|
|
298
|
+
later call behind it. An IMAP `search-messages` therefore stops at
|
|
299
|
+
`APPLE_MAIL_MCP_SEARCH_DEADLINE_MS` (default `45000`, minimum `2000`, measured from when the request
|
|
300
|
+
arrived — time queued behind other calls counts) and returns what it found plus `timedOutMailboxes`,
|
|
301
|
+
and it stops the same way when the client cancels the request. The mailbox being searched at that
|
|
302
|
+
moment is abandoned by closing its IMAP connection (the next call reconnects), so the queue is
|
|
303
|
+
released promptly rather than after a server-side `SEARCH` that can take a minute and a half on a
|
|
304
|
+
very large mailbox. A request cancelled while still queued is skipped. Keep the deadline below your
|
|
305
|
+
client's own request timeout.
|
|
293
306
|
|
|
294
307
|
Treat a non-empty `skippedLargeMailboxes` as actionable rather than
|
|
295
308
|
informational: re-run scoped to the named mailbox with a `dateFrom`/`dateTo`
|
|
@@ -309,15 +322,17 @@ inferred from the top-level `Content-Type`.
|
|
|
309
322
|
|
|
310
323
|
Get the full content of a message.
|
|
311
324
|
|
|
312
|
-
| Parameter | Type | Required | Description
|
|
313
|
-
| ------------ | ------- | -------- |
|
|
314
|
-
| `id` | string | Yes | Message ID
|
|
315
|
-
| `preferHtml` | boolean | No | Return HTML source instead of plain text
|
|
316
|
-
| `mailbox` | string | No | Mailbox holding the message (e.g. `"Sent Items"`). With `account`, opens that mailbox directly instead of scanning every mailbox — this is the fix for timeouts on large folders |
|
|
317
|
-
| `account` | string | No | Account holding the message. Pair with `mailbox` to skip the cross-mailbox scan
|
|
325
|
+
| Parameter | Type | Required | Description |
|
|
326
|
+
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
327
|
+
| `id` | string | Yes | Message ID |
|
|
328
|
+
| `preferHtml` | boolean | No | Return HTML source instead of plain text |
|
|
329
|
+
| `mailbox` | string | No | Mailbox holding the message (e.g. `"Sent Items"`). With `account`, opens that mailbox directly instead of scanning every mailbox — this is the fix for timeouts on large folders. A miss there is reported as "not found in <account> / <mailbox>"; it never falls back to the cross-mailbox scan |
|
|
330
|
+
| `account` | string | No | Account holding the message. Pair with `mailbox` to skip the cross-mailbox scan |
|
|
318
331
|
|
|
319
332
|
**Returns:** Subject line and message body (plain text by default, HTML if `preferHtml` is true and HTML content is available). `structuredContent` also carries `rfcMessageId` and, since 2.19.0, two dates: `dateSent` (the message's `Date:` header — Mail's `date sent`) and `dateReceived` (arrival in the mailbox — Mail's `date received` / IMAP `INTERNALDATE`). They differ legitimately by transit time; when they differ by **years**, the mailbox was migrated or re-imported and the arrival timestamp was reset — trust `dateSent` for chronology ([#224](https://github.com/sweetrb/apple-mail-mcp/issues/224)). Since 2.19.6 `dateSent` is **omitted** when it is more than 7 days later than `dateReceived`: a message cannot be sent after it arrived, and Mail.app substitutes a timestamp of its own for a `Date:` header it cannot parse ([#234](https://github.com/sweetrb/apple-mail-mcp/issues/234)). `isHtml` reports what was actually returned — a message with no `text/plain` part returns its HTML part with `isHtml: true`. Bodies are decoded by each part's declared `charset`, falling back to windows-1252 for bytes that are not valid UTF-8.
|
|
320
333
|
|
|
334
|
+
**Numeric ids — how the message is found ([#270](https://github.com/sweetrb/apple-mail-mcp/issues/270)):** with `account` + `mailbox` the read opens that one mailbox and stops there. Otherwise it opens the mailbox the id was last listed or searched from (a remembered location that turns out stale — the message was moved, e.g. by another client — is forgotten), and only then scans every mailbox. That cross-mailbox scan skips any mailbox holding more than `APPLE_MAIL_MAX_BYID_SCAN_MAILBOX` messages (default `50000`; `0` disables the guard) and stops after ~9s, because Mail's `whose id is` probe costs seconds per hundred thousand messages; a miss then names the mailboxes it did not scan. Pass `account` + `mailbox` to read from one of those, or use the message's `imap:` id, which never scans. The same resolution backs `get-message-headers`, `get-thread`'s seed lookup, and the original-message read of `reply-to-message` / `forward-message` and the attachment tools.
|
|
335
|
+
|
|
321
336
|
> **Large messages / attachments:** reading a full message routes through
|
|
322
337
|
> `osascript`, whose captured output buffer defaults to **64 MB**. Override it
|
|
323
338
|
> with the `APPLE_MAIL_MCP_MAX_BUFFER` environment variable (in **bytes**) if you
|
|
@@ -618,21 +633,22 @@ If IMAP is **not** configured at all, every read behaves exactly as before
|
|
|
618
633
|
`delete-mailbox`, `rename-mailbox`) remain conservative — they route to IMAP only
|
|
619
634
|
for an explicitly-named IMAP account, never on an omitted account.
|
|
620
635
|
|
|
621
|
-
| Variable | Required | Default | Description
|
|
622
|
-
| -------------------------------------- | -------- | ---------------- |
|
|
623
|
-
| `APPLE_MAIL_MCP_IMAP_USER` | Yes | — | Login address; setting it enables IMAP
|
|
624
|
-
| `APPLE_MAIL_MCP_IMAP_ACCOUNT` | No | = user | Mail account name to match for routing
|
|
625
|
-
| `APPLE_MAIL_MCP_IMAP_HOST` | No | `imap.gmail.com` | IMAP server hostname
|
|
626
|
-
| `APPLE_MAIL_MCP_IMAP_PORT` | No | `993` | IMAP port (993 = implicit TLS)
|
|
627
|
-
| `APPLE_MAIL_MCP_IMAP_ALLOW_PLAINTEXT` | No | `0` | Set `1` only for an explicitly trusted plaintext test/server; otherwise STARTTLS is required
|
|
628
|
-
| `APPLE_MAIL_MCP_IMAP_PASSWORD` | No | — | Password (if set, used instead of the Keychain)
|
|
629
|
-
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE` | No | — | Keychain item service/server name
|
|
630
|
-
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT` | No | = user | Keychain item account
|
|
631
|
-
| `APPLE_MAIL_MCP_IMAP_ACCOUNTS` | No | — | JSON array of **additional** IMAP accounts for multi-account setups (see below)
|
|
632
|
-
| `APPLE_MAIL_MCP_IMAP_IDLE` | No | `0` | Set `1` to enable IMAP IDLE push notifications (new-mail alerts) for every configured account
|
|
633
|
-
| `APPLE_MAIL_MCP_IMAP_IDLE_MS` | No | `30000` | Idle timeout (ms) before a pooled IMAP connection is closed (`0` = never close)
|
|
634
|
-
| `APPLE_MAIL_MCP_STATS_BUDGET_MS` | No | `25000` | Per-account wall-clock budget for `get-mail-stats` (minimum `1000`). Raise it for very large accounts
|
|
635
|
-
| `APPLE_MAIL_MCP_STATS_DEADLINE_MS` | No | `50000` | Overall wall-clock deadline for one `get-mail-stats` call (minimum `2000`), measured from when the request arrived and covering time queued behind other tool calls, account enumeration **and** every per-account read. Keep it below your client's request timeout
|
|
636
|
+
| Variable | Required | Default | Description |
|
|
637
|
+
| -------------------------------------- | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
638
|
+
| `APPLE_MAIL_MCP_IMAP_USER` | Yes | — | Login address; setting it enables IMAP |
|
|
639
|
+
| `APPLE_MAIL_MCP_IMAP_ACCOUNT` | No | = user | Mail account name to match for routing |
|
|
640
|
+
| `APPLE_MAIL_MCP_IMAP_HOST` | No | `imap.gmail.com` | IMAP server hostname |
|
|
641
|
+
| `APPLE_MAIL_MCP_IMAP_PORT` | No | `993` | IMAP port (993 = implicit TLS) |
|
|
642
|
+
| `APPLE_MAIL_MCP_IMAP_ALLOW_PLAINTEXT` | No | `0` | Set `1` only for an explicitly trusted plaintext test/server; otherwise STARTTLS is required |
|
|
643
|
+
| `APPLE_MAIL_MCP_IMAP_PASSWORD` | No | — | Password (if set, used instead of the Keychain) |
|
|
644
|
+
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE` | No | — | Keychain item service/server name |
|
|
645
|
+
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT` | No | = user | Keychain item account |
|
|
646
|
+
| `APPLE_MAIL_MCP_IMAP_ACCOUNTS` | No | — | JSON array of **additional** IMAP accounts for multi-account setups (see below) |
|
|
647
|
+
| `APPLE_MAIL_MCP_IMAP_IDLE` | No | `0` | Set `1` to enable IMAP IDLE push notifications (new-mail alerts) for every configured account |
|
|
648
|
+
| `APPLE_MAIL_MCP_IMAP_IDLE_MS` | No | `30000` | Idle timeout (ms) before a pooled IMAP connection is closed (`0` = never close) |
|
|
649
|
+
| `APPLE_MAIL_MCP_STATS_BUDGET_MS` | No | `25000` | Per-account wall-clock budget for `get-mail-stats` (minimum `1000`). Raise it for very large accounts |
|
|
650
|
+
| `APPLE_MAIL_MCP_STATS_DEADLINE_MS` | No | `50000` | Overall wall-clock deadline for one `get-mail-stats` call (minimum `2000`), measured from when the request arrived and covering time queued behind other tool calls, account enumeration **and** every per-account read. Keep it below your client's request timeout |
|
|
651
|
+
| `APPLE_MAIL_MCP_SEARCH_DEADLINE_MS` | No | `45000` | Overall wall-clock deadline for one IMAP `search-messages` call (minimum `2000`), measured from when the request arrived. On expiry the search returns partial results plus `timedOutMailboxes` instead of holding the tool-call queue. Keep it below your client's request timeout |
|
|
636
652
|
|
|
637
653
|
**Multiple IMAP accounts (C2):** set `APPLE_MAIL_MCP_IMAP_ACCOUNTS` to a JSON array, e.g.
|
|
638
654
|
`[{"account":"Work","user":"me@co.com","host":"imap.co.com","keychainService":"imap.co.com"}]`.
|
|
@@ -2127,6 +2143,10 @@ In a JSON string literal, `\\` — two characters — denotes **one** literal ba
|
|
|
2127
2143
|
- Message may have been deleted or moved
|
|
2128
2144
|
- Message IDs change if the message is moved between mailboxes
|
|
2129
2145
|
- Use `search-messages` to find the current message ID
|
|
2146
|
+
- "**not found in the mailboxes scanned**" with a list of mailboxes means the numeric-id scan
|
|
2147
|
+
skipped those because they hold more than `APPLE_MAIL_MAX_BYID_SCAN_MAILBOX` messages (default
|
|
2148
|
+
`50000`). The message may be in one of them: pass `account` + `mailbox` to read it from there, or
|
|
2149
|
+
use its `imap:` id ([#270](https://github.com/sweetrb/apple-mail-mcp/issues/270)).
|
|
2130
2150
|
|
|
2131
2151
|
### "... is present in more than one mailbox"
|
|
2132
2152
|
|
package/build/cli.js
CHANGED
|
@@ -12259,6 +12259,51 @@ var init_docsUrls = __esm({
|
|
|
12259
12259
|
}
|
|
12260
12260
|
});
|
|
12261
12261
|
|
|
12262
|
+
// src/utils/callStop.ts
|
|
12263
|
+
function describeStop(signal) {
|
|
12264
|
+
const reason = signal?.reason;
|
|
12265
|
+
if (reason && typeof reason === "object" && reason.kind === "deadline") {
|
|
12266
|
+
return `the ${Math.round(reason.deadlineMs / 1e3)}s search deadline (${reason.envVar})`;
|
|
12267
|
+
}
|
|
12268
|
+
return "the request being cancelled";
|
|
12269
|
+
}
|
|
12270
|
+
function stoppedByDeadline(signal) {
|
|
12271
|
+
const reason = signal?.reason;
|
|
12272
|
+
return !!reason && typeof reason === "object" && reason.kind === "deadline";
|
|
12273
|
+
}
|
|
12274
|
+
function raceStop(work, signal) {
|
|
12275
|
+
if (!signal) return work;
|
|
12276
|
+
if (signal.aborted) {
|
|
12277
|
+
work.catch(() => void 0);
|
|
12278
|
+
return Promise.resolve(STOPPED);
|
|
12279
|
+
}
|
|
12280
|
+
return new Promise((resolve4, reject) => {
|
|
12281
|
+
const onAbort = () => {
|
|
12282
|
+
work.catch(() => void 0);
|
|
12283
|
+
resolve4(STOPPED);
|
|
12284
|
+
};
|
|
12285
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
12286
|
+
work.then(
|
|
12287
|
+
(value) => {
|
|
12288
|
+
signal.removeEventListener("abort", onAbort);
|
|
12289
|
+
resolve4(value);
|
|
12290
|
+
},
|
|
12291
|
+
(error2) => {
|
|
12292
|
+
signal.removeEventListener("abort", onAbort);
|
|
12293
|
+
reject(error2);
|
|
12294
|
+
}
|
|
12295
|
+
);
|
|
12296
|
+
});
|
|
12297
|
+
}
|
|
12298
|
+
var SEARCH_DEADLINE_ENV, STOPPED;
|
|
12299
|
+
var init_callStop = __esm({
|
|
12300
|
+
"src/utils/callStop.ts"() {
|
|
12301
|
+
"use strict";
|
|
12302
|
+
SEARCH_DEADLINE_ENV = "APPLE_MAIL_MCP_SEARCH_DEADLINE_MS";
|
|
12303
|
+
STOPPED = /* @__PURE__ */ Symbol("stopped");
|
|
12304
|
+
}
|
|
12305
|
+
});
|
|
12306
|
+
|
|
12262
12307
|
// node_modules/.pnpm/pino-std-serializers@7.1.0/node_modules/pino-std-serializers/lib/err-helpers.js
|
|
12263
12308
|
var require_err_helpers = __commonJS({
|
|
12264
12309
|
"node_modules/.pnpm/pino-std-serializers@7.1.0/node_modules/pino-std-serializers/lib/err-helpers.js"(exports, module) {
|
|
@@ -58037,6 +58082,7 @@ __export(imapClient_exports, {
|
|
|
58037
58082
|
resolveImapConfigs: () => resolveImapConfigs,
|
|
58038
58083
|
resolveMailboxPath: () => resolveMailboxPath,
|
|
58039
58084
|
shouldUseImap: () => shouldUseImap,
|
|
58085
|
+
stoppedNote: () => stoppedNote,
|
|
58040
58086
|
unscopedSearchOffsetError: () => unscopedSearchOffsetError
|
|
58041
58087
|
});
|
|
58042
58088
|
import { createHash } from "node:crypto";
|
|
@@ -58357,6 +58403,12 @@ function structuredRow(m, account, path3) {
|
|
|
58357
58403
|
...env.messageId ? { messageId: env.messageId } : {}
|
|
58358
58404
|
};
|
|
58359
58405
|
}
|
|
58406
|
+
function stoppedNote(timedOut, signal) {
|
|
58407
|
+
if (timedOut.length === 0) return "";
|
|
58408
|
+
return `
|
|
58409
|
+
|
|
58410
|
+
Partial result. Stopped by ${describeStop(signal)} before finishing ${timedOut.length} mailbox(es): ${timedOut.map((m) => `"${m}"`).join(", ")}. This is NOT a confirmed "no such mail" \u2014 narrow the search with \`mailbox\` and/or \`dateFrom\`, or raise ${SEARCH_DEADLINE_ENV}.`;
|
|
58411
|
+
}
|
|
58360
58412
|
function omittedNote(omitted, merged) {
|
|
58361
58413
|
if (omitted.length === 0) return "";
|
|
58362
58414
|
const list = omitted.map((o) => `UID ${o.uid} in "${o.mailbox}" (${o.id})`).join(", ");
|
|
@@ -58646,9 +58698,23 @@ async function run(args, listMode, deps) {
|
|
|
58646
58698
|
const omittedMessages = [];
|
|
58647
58699
|
let totalMatched = 0;
|
|
58648
58700
|
let totalExact = true;
|
|
58649
|
-
|
|
58701
|
+
const timedOutMailboxes = [];
|
|
58702
|
+
for (const [index, path3] of paths.entries()) {
|
|
58703
|
+
if (deps.signal?.aborted) {
|
|
58704
|
+
timedOutMailboxes.push(...paths.slice(index));
|
|
58705
|
+
break;
|
|
58706
|
+
}
|
|
58650
58707
|
try {
|
|
58651
|
-
const
|
|
58708
|
+
const outcome = await raceStop(
|
|
58709
|
+
fetchMailboxMatches(client, path3, criteria, page),
|
|
58710
|
+
deps.signal
|
|
58711
|
+
);
|
|
58712
|
+
if (outcome === STOPPED) {
|
|
58713
|
+
abandonClient(client, cfg, deps);
|
|
58714
|
+
timedOutMailboxes.push(...paths.slice(index));
|
|
58715
|
+
break;
|
|
58716
|
+
}
|
|
58717
|
+
const result = outcome;
|
|
58652
58718
|
totalMatched += result.total;
|
|
58653
58719
|
totalExact &&= result.totalExact;
|
|
58654
58720
|
fetched.push(...result.messages.map((message) => ({ message, path: path3 })));
|
|
@@ -58688,10 +58754,14 @@ async function run(args, listMode, deps) {
|
|
|
58688
58754
|
const messages = ordered.map(
|
|
58689
58755
|
({ message, path: path3 }) => structuredRow(message, cfg.accountLabel, path3)
|
|
58690
58756
|
);
|
|
58691
|
-
const partial = failedMailboxes.length > 0 || omittedMessages.length > 0;
|
|
58757
|
+
const partial = failedMailboxes.length > 0 || omittedMessages.length > 0 || timedOutMailboxes.length > 0;
|
|
58758
|
+
const stopped = timedOutMailboxes.length > 0 ? {
|
|
58759
|
+
timedOutMailboxes,
|
|
58760
|
+
stoppedBy: stoppedByDeadline(deps.signal) ? "deadline" : "cancelled"
|
|
58761
|
+
} : {};
|
|
58692
58762
|
const failureNote = (failedMailboxes.length > 0 ? `
|
|
58693
58763
|
|
|
58694
|
-
Partial result. Could not search mailbox(es): ${failedMailboxes.map((path3) => `"${path3}" (${failedMailboxReasons[path3]})`).join(", ")}.` : "") + omittedNote(omittedMessages, unscopedSearch);
|
|
58764
|
+
Partial result. Could not search mailbox(es): ${failedMailboxes.map((path3) => `"${path3}" (${failedMailboxReasons[path3]})`).join(", ")}.` : "") + omittedNote(omittedMessages, unscopedSearch) + stoppedNote(timedOutMailboxes, deps.signal);
|
|
58695
58765
|
const verb = listMode ? "listed" : "matched";
|
|
58696
58766
|
const totalText = totalExact ? `${totalMatched} total` : `at least ${totalMatched} total`;
|
|
58697
58767
|
const scope = unscopedSearch ? allMailboxCount === 1 ? `mailbox "${paths[0]}"` : `${allMailboxCount} selectable mailboxes` : `mailbox "${paths[0]}"`;
|
|
@@ -58703,7 +58773,8 @@ Partial result. Could not search mailbox(es): ${failedMailboxes.map((path3) => `
|
|
|
58703
58773
|
partial,
|
|
58704
58774
|
failedMailboxes,
|
|
58705
58775
|
failedMailboxReasons,
|
|
58706
|
-
omittedMessages
|
|
58776
|
+
omittedMessages,
|
|
58777
|
+
...stopped
|
|
58707
58778
|
};
|
|
58708
58779
|
}
|
|
58709
58780
|
const text = `Found ${rows.length} message(s) via IMAP (server-side, account ${cfg.accountLabel}, ${scope}; ${totalText} ${verb}):
|
|
@@ -58717,7 +58788,8 @@ Note: these IMAP IDs (imap:\u2026) work with get-message and the message mutatio
|
|
|
58717
58788
|
partial,
|
|
58718
58789
|
failedMailboxes,
|
|
58719
58790
|
failedMailboxReasons,
|
|
58720
|
-
omittedMessages
|
|
58791
|
+
omittedMessages,
|
|
58792
|
+
...stopped
|
|
58721
58793
|
};
|
|
58722
58794
|
},
|
|
58723
58795
|
true
|
|
@@ -58860,6 +58932,20 @@ async function dropPool(key) {
|
|
|
58860
58932
|
await e.client.logout().catch(() => void 0);
|
|
58861
58933
|
e.client.close?.();
|
|
58862
58934
|
}
|
|
58935
|
+
function abandonClient(client, cfg, deps) {
|
|
58936
|
+
if (!deps.connect) {
|
|
58937
|
+
const key = poolKey(cfg);
|
|
58938
|
+
const entry = pools.get(key);
|
|
58939
|
+
if (entry && entry.client === client) {
|
|
58940
|
+
if (entry.idle) clearTimeout(entry.idle);
|
|
58941
|
+
pools.delete(key);
|
|
58942
|
+
}
|
|
58943
|
+
}
|
|
58944
|
+
try {
|
|
58945
|
+
client.close?.();
|
|
58946
|
+
} catch {
|
|
58947
|
+
}
|
|
58948
|
+
}
|
|
58863
58949
|
async function dropAllPools() {
|
|
58864
58950
|
await Promise.all([...pools.keys()].map((k) => dropPool(k)));
|
|
58865
58951
|
}
|
|
@@ -59858,6 +59944,7 @@ var import_imapflow, IMAP_ENV, defaultConnect, SPECIAL_USE_ALIASES, NOT_DELETED,
|
|
|
59858
59944
|
var init_imapClient = __esm({
|
|
59859
59945
|
"src/services/imapClient.ts"() {
|
|
59860
59946
|
"use strict";
|
|
59947
|
+
init_callStop();
|
|
59861
59948
|
import_imapflow = __toESM(require_imap_flow(), 1);
|
|
59862
59949
|
init_smtpMailer();
|
|
59863
59950
|
init_docsUrls();
|