apple-mail-mcp 2.20.24 → 2.20.26
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 +4 -0
- package/build/cli.js +62 -8
- package/build/index.js +76 -14
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -501,6 +501,10 @@ Two differences to know when SMTP is auto-preferred:
|
|
|
501
501
|
or `sentCopy: false` with `sentCopyError`; the field is **absent** when no
|
|
502
502
|
configured IMAP account matches the SMTP identity, which is a skip, not a
|
|
503
503
|
failure. A copy that fails never fails the send — the mail has already gone.
|
|
504
|
+
Before appending, the Sent mailbox is searched for that `Message-ID`; if the
|
|
505
|
+
submission server already filed it (Gmail's SMTP always does — the server
|
|
506
|
+
waits up to ~3 s for it there), nothing is appended and the result adds
|
|
507
|
+
`sentCopyAlreadyFiled: true` alongside `sentCopy: true`.
|
|
504
508
|
Use `transport: "applescript"` if you want Mail.app itself to file the copy.
|
|
505
509
|
- **`account` is a From override, not account selection.** Over SMTP, `account`
|
|
506
510
|
is used as the From address only when it is an email address; a Mail.app
|
package/build/cli.js
CHANGED
|
@@ -58670,6 +58670,8 @@ __export(imapClient_exports, {
|
|
|
58670
58670
|
MAX_RFC822_FILE_BYTES: () => MAX_RFC822_FILE_BYTES,
|
|
58671
58671
|
MAX_RFC822_INLINE_BYTES: () => MAX_RFC822_INLINE_BYTES,
|
|
58672
58672
|
MAX_UNSCOPED_SEARCH_DEPTH: () => MAX_UNSCOPED_SEARCH_DEPTH,
|
|
58673
|
+
SENT_COPY_GMAIL_POLL_INTERVAL_MS: () => SENT_COPY_GMAIL_POLL_INTERVAL_MS,
|
|
58674
|
+
SENT_COPY_GMAIL_POLL_MS: () => SENT_COPY_GMAIL_POLL_MS,
|
|
58673
58675
|
__resetPool: () => __resetPool,
|
|
58674
58676
|
__setPoolConnect: () => __setPoolConnect,
|
|
58675
58677
|
base64DecodedLength: () => base64DecodedLength,
|
|
@@ -58680,6 +58682,7 @@ __export(imapClient_exports, {
|
|
|
58680
58682
|
decodedSizeWithoutBody: () => decodedSizeWithoutBody,
|
|
58681
58683
|
dropAllPools: () => dropAllPools,
|
|
58682
58684
|
encodeImapId: () => encodeImapId,
|
|
58685
|
+
extractRawMessageId: () => extractRawMessageId,
|
|
58683
58686
|
flagColorName: () => flagColorName,
|
|
58684
58687
|
imapAppendDraft: () => imapAppendDraft,
|
|
58685
58688
|
imapAppendSentCopy: () => imapAppendSentCopy,
|
|
@@ -58712,6 +58715,7 @@ __export(imapClient_exports, {
|
|
|
58712
58715
|
imapThread: () => imapThread,
|
|
58713
58716
|
imapUnflagMessage: () => imapUnflagMessage,
|
|
58714
58717
|
imapUnreadCount: () => imapUnreadCount,
|
|
58718
|
+
isGmailHost: () => isGmailHost,
|
|
58715
58719
|
isImapAccount: () => isImapAccount,
|
|
58716
58720
|
listImapAccountLabels: () => listImapAccountLabels,
|
|
58717
58721
|
mailFlagBitsFor: () => mailFlagBitsFor,
|
|
@@ -59840,11 +59844,32 @@ function imapRenameMailbox(oldName, newName, deps = {}) {
|
|
|
59840
59844
|
}
|
|
59841
59845
|
});
|
|
59842
59846
|
}
|
|
59843
|
-
|
|
59847
|
+
function isGmailHost(host) {
|
|
59848
|
+
return Boolean(host && GMAIL_HOST.test(host.trim()));
|
|
59849
|
+
}
|
|
59850
|
+
function extractRawMessageId(raw) {
|
|
59851
|
+
const text = typeof raw === "string" ? raw : raw.toString("latin1");
|
|
59852
|
+
const end = text.search(/\r?\n\r?\n/);
|
|
59853
|
+
const header = (end === -1 ? text : text.slice(0, end)).replace(/\r?\n[ \t]+/g, " ");
|
|
59854
|
+
const m = /^message-id:[ \t]*(<[^<>\s]+>)/im.exec(header);
|
|
59855
|
+
return m ? m[1] : null;
|
|
59856
|
+
}
|
|
59857
|
+
async function imapAppendSentCopy(smtpUser, raw, deps = {}, opts = {}) {
|
|
59844
59858
|
if (!deps.config && !isImapAccount(smtpUser)) return { attempted: false };
|
|
59859
|
+
const messageId = extractRawMessageId(raw);
|
|
59860
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
59861
|
+
const now = opts.now ?? Date.now;
|
|
59845
59862
|
try {
|
|
59846
|
-
return await withClient({ ...deps, account: deps.account ?? smtpUser }, async (client) => {
|
|
59863
|
+
return await withClient({ ...deps, account: deps.account ?? smtpUser }, async (client, cfg) => {
|
|
59847
59864
|
const path3 = await resolveMailboxPath(client, "sent", "list");
|
|
59865
|
+
if (messageId) {
|
|
59866
|
+
const gmail = isGmailHost(cfg.host) || isGmailHost(opts.smtpHost);
|
|
59867
|
+
const budget = gmail ? opts.gmailPollMs ?? SENT_COPY_GMAIL_POLL_MS : 0;
|
|
59868
|
+
const interval = Math.max(1, opts.gmailPollIntervalMs ?? SENT_COPY_GMAIL_POLL_INTERVAL_MS);
|
|
59869
|
+
if (await sentCopyPresent(client, path3, messageId, budget, interval, sleep, now)) {
|
|
59870
|
+
return { attempted: true, success: true, mailbox: path3, alreadyFiled: true };
|
|
59871
|
+
}
|
|
59872
|
+
}
|
|
59848
59873
|
const res = await client.append(path3, raw, ["\\Seen"]);
|
|
59849
59874
|
if (!res) throw new Error("server rejected the APPEND (IMAP NO/BAD)");
|
|
59850
59875
|
return { attempted: true, success: true, mailbox: path3 };
|
|
@@ -59853,6 +59878,28 @@ async function imapAppendSentCopy(smtpUser, raw, deps = {}) {
|
|
|
59853
59878
|
return { attempted: true, success: false, error: errText(e) };
|
|
59854
59879
|
}
|
|
59855
59880
|
}
|
|
59881
|
+
async function sentCopyPresent(client, path3, messageId, budget, interval, sleep, now) {
|
|
59882
|
+
const deadline = now() + budget;
|
|
59883
|
+
for (; ; ) {
|
|
59884
|
+
try {
|
|
59885
|
+
const lock = await client.getMailboxLock(path3, { readOnly: true });
|
|
59886
|
+
try {
|
|
59887
|
+
const found = await client.search(
|
|
59888
|
+
{ header: { "message-id": messageId }, ...NOT_DELETED },
|
|
59889
|
+
{ uid: true }
|
|
59890
|
+
);
|
|
59891
|
+
if (Array.isArray(found) && found.length > 0) return true;
|
|
59892
|
+
} finally {
|
|
59893
|
+
lock.release();
|
|
59894
|
+
}
|
|
59895
|
+
} catch {
|
|
59896
|
+
return false;
|
|
59897
|
+
}
|
|
59898
|
+
const left = deadline - now();
|
|
59899
|
+
if (left <= 0) return false;
|
|
59900
|
+
await sleep(Math.min(interval, left));
|
|
59901
|
+
}
|
|
59902
|
+
}
|
|
59856
59903
|
function resolveDraftImapAccount(account, smtpUser, env = process.env) {
|
|
59857
59904
|
const specs = listImapAccountSpecs(env);
|
|
59858
59905
|
const why = "Mail.app's AppleScript cannot set In-Reply-To/References on a draft, so a threaded draft is filed over IMAP into the account's Drafts mailbox";
|
|
@@ -60620,7 +60667,7 @@ async function imapThread(id, deps = {}, limit = 50) {
|
|
|
60620
60667
|
true
|
|
60621
60668
|
);
|
|
60622
60669
|
}
|
|
60623
|
-
var import_imapflow, IMAP_ENV, defaultConnect, SPECIAL_USE_ALIASES, NOT_DELETED, LARGE_MAILBOX_MESSAGES, FIRST_SEARCH_WINDOW, MAX_WINDOW, MAX_UNSCOPED_SEARCH_DEPTH, COLOR_FETCH_CHUNK, ROW_QUERY, ROW_QUERY_NO_STRUCTURE, ROW_QUERY_HEADERS_ONLY, DELETED_MARGIN, poolConnect, pools, connecting, MAX_COMPOSE_SOURCE_BYTES, MAX_RFC822_INLINE_BYTES, MAX_RFC822_FILE_BYTES, HEADER_WINDOW_BYTES, MAIL_FLAG_BITS, FLAG_COLOR_NAMES, imapMarkRead, imapMarkUnread, FALLBACK_TRASH_PATH, BASE64_TAIL_WINDOW, QP_EXACT_MAX_BYTES, imapBatchMarkRead, imapBatchMarkUnread, imapBatchFlag, imapBatchUnflag, imapBatchDelete;
|
|
60670
|
+
var import_imapflow, IMAP_ENV, defaultConnect, SPECIAL_USE_ALIASES, NOT_DELETED, LARGE_MAILBOX_MESSAGES, FIRST_SEARCH_WINDOW, MAX_WINDOW, MAX_UNSCOPED_SEARCH_DEPTH, COLOR_FETCH_CHUNK, ROW_QUERY, ROW_QUERY_NO_STRUCTURE, ROW_QUERY_HEADERS_ONLY, DELETED_MARGIN, poolConnect, pools, connecting, SENT_COPY_GMAIL_POLL_MS, SENT_COPY_GMAIL_POLL_INTERVAL_MS, GMAIL_HOST, MAX_COMPOSE_SOURCE_BYTES, MAX_RFC822_INLINE_BYTES, MAX_RFC822_FILE_BYTES, HEADER_WINDOW_BYTES, MAIL_FLAG_BITS, FLAG_COLOR_NAMES, imapMarkRead, imapMarkUnread, FALLBACK_TRASH_PATH, BASE64_TAIL_WINDOW, QP_EXACT_MAX_BYTES, imapBatchMarkRead, imapBatchMarkUnread, imapBatchFlag, imapBatchUnflag, imapBatchDelete;
|
|
60624
60671
|
var init_imapClient = __esm({
|
|
60625
60672
|
"src/services/imapClient.ts"() {
|
|
60626
60673
|
"use strict";
|
|
@@ -60719,6 +60766,9 @@ var init_imapClient = __esm({
|
|
|
60719
60766
|
poolConnect = defaultConnect;
|
|
60720
60767
|
pools = /* @__PURE__ */ new Map();
|
|
60721
60768
|
connecting = /* @__PURE__ */ new Map();
|
|
60769
|
+
SENT_COPY_GMAIL_POLL_MS = 3e3;
|
|
60770
|
+
SENT_COPY_GMAIL_POLL_INTERVAL_MS = 500;
|
|
60771
|
+
GMAIL_HOST = /(^|\.)(gmail|googlemail)\.com$/i;
|
|
60722
60772
|
MAX_COMPOSE_SOURCE_BYTES = 25 * 1024 * 1024;
|
|
60723
60773
|
MAX_RFC822_INLINE_BYTES = 6 * 1024 * 1024;
|
|
60724
60774
|
MAX_RFC822_FILE_BYTES = MAX_COMPOSE_SOURCE_BYTES;
|
|
@@ -60787,11 +60837,12 @@ import { execFileSync } from "child_process";
|
|
|
60787
60837
|
function errText2(e) {
|
|
60788
60838
|
return e instanceof Error ? e.message : String(e);
|
|
60789
60839
|
}
|
|
60790
|
-
async function defaultAppendSentCopy(smtpUser, raw) {
|
|
60840
|
+
async function defaultAppendSentCopy(smtpUser, raw, smtpHost) {
|
|
60791
60841
|
const { imapAppendSentCopy: imapAppendSentCopy2 } = await Promise.resolve().then(() => (init_imapClient(), imapClient_exports));
|
|
60792
|
-
const result = await imapAppendSentCopy2(smtpUser, raw);
|
|
60842
|
+
const result = await imapAppendSentCopy2(smtpUser, raw, {}, { smtpHost });
|
|
60793
60843
|
if (!result.attempted) return {};
|
|
60794
|
-
|
|
60844
|
+
if (!result.success) return { sentCopy: false, sentCopyError: result.error };
|
|
60845
|
+
return result.alreadyFiled ? { sentCopy: true, sentCopyAlreadyFiled: true } : { sentCopy: true };
|
|
60795
60846
|
}
|
|
60796
60847
|
function buildRawMime(mail) {
|
|
60797
60848
|
return new mail_composer_default(mail).compile().build();
|
|
@@ -60922,7 +60973,10 @@ async function sendViaSmtp(opts, config, createTransport2 = nodemailer_default.c
|
|
|
60922
60973
|
requireTLS,
|
|
60923
60974
|
auth: { user: cfg.user, pass: cfg.pass }
|
|
60924
60975
|
});
|
|
60925
|
-
const mailOptions =
|
|
60976
|
+
const mailOptions = {
|
|
60977
|
+
...buildMailOptions(opts, requestedFrom || cfg.from, attachments),
|
|
60978
|
+
date: /* @__PURE__ */ new Date()
|
|
60979
|
+
};
|
|
60926
60980
|
try {
|
|
60927
60981
|
const info = await transporter.sendMail(mailOptions);
|
|
60928
60982
|
let copyFields = {};
|
|
@@ -60932,7 +60986,7 @@ async function sendViaSmtp(opts, config, createTransport2 = nodemailer_default.c
|
|
|
60932
60986
|
keepBcc: true,
|
|
60933
60987
|
messageId: info.messageId
|
|
60934
60988
|
});
|
|
60935
|
-
copyFields = await appendSentCopy(cfg.user, raw);
|
|
60989
|
+
copyFields = await appendSentCopy(cfg.user, raw, cfg.host);
|
|
60936
60990
|
} catch (copyError) {
|
|
60937
60991
|
copyFields = { sentCopy: false, sentCopyError: errText2(copyError) };
|
|
60938
60992
|
}
|
package/build/index.js
CHANGED
|
@@ -65470,11 +65470,12 @@ import { execFileSync } from "child_process";
|
|
|
65470
65470
|
function errText(e) {
|
|
65471
65471
|
return e instanceof Error ? e.message : String(e);
|
|
65472
65472
|
}
|
|
65473
|
-
async function defaultAppendSentCopy(smtpUser, raw) {
|
|
65473
|
+
async function defaultAppendSentCopy(smtpUser, raw, smtpHost) {
|
|
65474
65474
|
const { imapAppendSentCopy: imapAppendSentCopy2 } = await Promise.resolve().then(() => (init_imapClient(), imapClient_exports));
|
|
65475
|
-
const result = await imapAppendSentCopy2(smtpUser, raw);
|
|
65475
|
+
const result = await imapAppendSentCopy2(smtpUser, raw, {}, { smtpHost });
|
|
65476
65476
|
if (!result.attempted) return {};
|
|
65477
|
-
|
|
65477
|
+
if (!result.success) return { sentCopy: false, sentCopyError: result.error };
|
|
65478
|
+
return result.alreadyFiled ? { sentCopy: true, sentCopyAlreadyFiled: true } : { sentCopy: true };
|
|
65478
65479
|
}
|
|
65479
65480
|
function buildRawMime(mail) {
|
|
65480
65481
|
return new mail_composer_default(mail).compile().build();
|
|
@@ -65622,7 +65623,10 @@ async function sendViaSmtp(opts, config2, createTransport2 = nodemailer_default.
|
|
|
65622
65623
|
requireTLS,
|
|
65623
65624
|
auth: { user: cfg.user, pass: cfg.pass }
|
|
65624
65625
|
});
|
|
65625
|
-
const mailOptions =
|
|
65626
|
+
const mailOptions = {
|
|
65627
|
+
...buildMailOptions(opts, requestedFrom || cfg.from, attachments),
|
|
65628
|
+
date: /* @__PURE__ */ new Date()
|
|
65629
|
+
};
|
|
65626
65630
|
try {
|
|
65627
65631
|
const info = await transporter.sendMail(mailOptions);
|
|
65628
65632
|
let copyFields = {};
|
|
@@ -65632,7 +65636,7 @@ async function sendViaSmtp(opts, config2, createTransport2 = nodemailer_default.
|
|
|
65632
65636
|
keepBcc: true,
|
|
65633
65637
|
messageId: info.messageId
|
|
65634
65638
|
});
|
|
65635
|
-
copyFields = await appendSentCopy(cfg.user, raw);
|
|
65639
|
+
copyFields = await appendSentCopy(cfg.user, raw, cfg.host);
|
|
65636
65640
|
} catch (copyError) {
|
|
65637
65641
|
copyFields = { sentCopy: false, sentCopyError: errText(copyError) };
|
|
65638
65642
|
}
|
|
@@ -66423,6 +66427,8 @@ __export(imapClient_exports, {
|
|
|
66423
66427
|
MAX_RFC822_FILE_BYTES: () => MAX_RFC822_FILE_BYTES,
|
|
66424
66428
|
MAX_RFC822_INLINE_BYTES: () => MAX_RFC822_INLINE_BYTES,
|
|
66425
66429
|
MAX_UNSCOPED_SEARCH_DEPTH: () => MAX_UNSCOPED_SEARCH_DEPTH,
|
|
66430
|
+
SENT_COPY_GMAIL_POLL_INTERVAL_MS: () => SENT_COPY_GMAIL_POLL_INTERVAL_MS,
|
|
66431
|
+
SENT_COPY_GMAIL_POLL_MS: () => SENT_COPY_GMAIL_POLL_MS,
|
|
66426
66432
|
__resetPool: () => __resetPool,
|
|
66427
66433
|
__setPoolConnect: () => __setPoolConnect,
|
|
66428
66434
|
base64DecodedLength: () => base64DecodedLength,
|
|
@@ -66433,6 +66439,7 @@ __export(imapClient_exports, {
|
|
|
66433
66439
|
decodedSizeWithoutBody: () => decodedSizeWithoutBody,
|
|
66434
66440
|
dropAllPools: () => dropAllPools,
|
|
66435
66441
|
encodeImapId: () => encodeImapId,
|
|
66442
|
+
extractRawMessageId: () => extractRawMessageId,
|
|
66436
66443
|
flagColorName: () => flagColorName,
|
|
66437
66444
|
imapAppendDraft: () => imapAppendDraft,
|
|
66438
66445
|
imapAppendSentCopy: () => imapAppendSentCopy,
|
|
@@ -66465,6 +66472,7 @@ __export(imapClient_exports, {
|
|
|
66465
66472
|
imapThread: () => imapThread,
|
|
66466
66473
|
imapUnflagMessage: () => imapUnflagMessage,
|
|
66467
66474
|
imapUnreadCount: () => imapUnreadCount,
|
|
66475
|
+
isGmailHost: () => isGmailHost,
|
|
66468
66476
|
isImapAccount: () => isImapAccount,
|
|
66469
66477
|
listImapAccountLabels: () => listImapAccountLabels,
|
|
66470
66478
|
mailFlagBitsFor: () => mailFlagBitsFor,
|
|
@@ -67593,11 +67601,32 @@ function imapRenameMailbox(oldName, newName, deps = {}) {
|
|
|
67593
67601
|
}
|
|
67594
67602
|
});
|
|
67595
67603
|
}
|
|
67596
|
-
|
|
67604
|
+
function isGmailHost(host) {
|
|
67605
|
+
return Boolean(host && GMAIL_HOST.test(host.trim()));
|
|
67606
|
+
}
|
|
67607
|
+
function extractRawMessageId(raw) {
|
|
67608
|
+
const text = typeof raw === "string" ? raw : raw.toString("latin1");
|
|
67609
|
+
const end = text.search(/\r?\n\r?\n/);
|
|
67610
|
+
const header = (end === -1 ? text : text.slice(0, end)).replace(/\r?\n[ \t]+/g, " ");
|
|
67611
|
+
const m = /^message-id:[ \t]*(<[^<>\s]+>)/im.exec(header);
|
|
67612
|
+
return m ? m[1] : null;
|
|
67613
|
+
}
|
|
67614
|
+
async function imapAppendSentCopy(smtpUser, raw, deps = {}, opts = {}) {
|
|
67597
67615
|
if (!deps.config && !isImapAccount(smtpUser)) return { attempted: false };
|
|
67616
|
+
const messageId = extractRawMessageId(raw);
|
|
67617
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
67618
|
+
const now = opts.now ?? Date.now;
|
|
67598
67619
|
try {
|
|
67599
|
-
return await withClient({ ...deps, account: deps.account ?? smtpUser }, async (client) => {
|
|
67620
|
+
return await withClient({ ...deps, account: deps.account ?? smtpUser }, async (client, cfg) => {
|
|
67600
67621
|
const path3 = await resolveMailboxPath(client, "sent", "list");
|
|
67622
|
+
if (messageId) {
|
|
67623
|
+
const gmail = isGmailHost(cfg.host) || isGmailHost(opts.smtpHost);
|
|
67624
|
+
const budget = gmail ? opts.gmailPollMs ?? SENT_COPY_GMAIL_POLL_MS : 0;
|
|
67625
|
+
const interval = Math.max(1, opts.gmailPollIntervalMs ?? SENT_COPY_GMAIL_POLL_INTERVAL_MS);
|
|
67626
|
+
if (await sentCopyPresent(client, path3, messageId, budget, interval, sleep2, now)) {
|
|
67627
|
+
return { attempted: true, success: true, mailbox: path3, alreadyFiled: true };
|
|
67628
|
+
}
|
|
67629
|
+
}
|
|
67601
67630
|
const res = await client.append(path3, raw, ["\\Seen"]);
|
|
67602
67631
|
if (!res) throw new Error("server rejected the APPEND (IMAP NO/BAD)");
|
|
67603
67632
|
return { attempted: true, success: true, mailbox: path3 };
|
|
@@ -67606,6 +67635,28 @@ async function imapAppendSentCopy(smtpUser, raw, deps = {}) {
|
|
|
67606
67635
|
return { attempted: true, success: false, error: errText2(e) };
|
|
67607
67636
|
}
|
|
67608
67637
|
}
|
|
67638
|
+
async function sentCopyPresent(client, path3, messageId, budget, interval, sleep2, now) {
|
|
67639
|
+
const deadline = now() + budget;
|
|
67640
|
+
for (; ; ) {
|
|
67641
|
+
try {
|
|
67642
|
+
const lock = await client.getMailboxLock(path3, { readOnly: true });
|
|
67643
|
+
try {
|
|
67644
|
+
const found = await client.search(
|
|
67645
|
+
{ header: { "message-id": messageId }, ...NOT_DELETED },
|
|
67646
|
+
{ uid: true }
|
|
67647
|
+
);
|
|
67648
|
+
if (Array.isArray(found) && found.length > 0) return true;
|
|
67649
|
+
} finally {
|
|
67650
|
+
lock.release();
|
|
67651
|
+
}
|
|
67652
|
+
} catch {
|
|
67653
|
+
return false;
|
|
67654
|
+
}
|
|
67655
|
+
const left = deadline - now();
|
|
67656
|
+
if (left <= 0) return false;
|
|
67657
|
+
await sleep2(Math.min(interval, left));
|
|
67658
|
+
}
|
|
67659
|
+
}
|
|
67609
67660
|
function resolveDraftImapAccount(account, smtpUser, env = process.env) {
|
|
67610
67661
|
const specs = listImapAccountSpecs(env);
|
|
67611
67662
|
const why = "Mail.app's AppleScript cannot set In-Reply-To/References on a draft, so a threaded draft is filed over IMAP into the account's Drafts mailbox";
|
|
@@ -68373,7 +68424,7 @@ async function imapThread(id, deps = {}, limit = 50) {
|
|
|
68373
68424
|
true
|
|
68374
68425
|
);
|
|
68375
68426
|
}
|
|
68376
|
-
var import_imapflow, IMAP_ENV, defaultConnect, SPECIAL_USE_ALIASES, NOT_DELETED, LARGE_MAILBOX_MESSAGES, FIRST_SEARCH_WINDOW, MAX_WINDOW, MAX_UNSCOPED_SEARCH_DEPTH, COLOR_FETCH_CHUNK, ROW_QUERY, ROW_QUERY_NO_STRUCTURE, ROW_QUERY_HEADERS_ONLY, DELETED_MARGIN, poolConnect, pools, connecting, MAX_COMPOSE_SOURCE_BYTES, MAX_RFC822_INLINE_BYTES, MAX_RFC822_FILE_BYTES, HEADER_WINDOW_BYTES, MAIL_FLAG_BITS, FLAG_COLOR_NAMES, imapMarkRead, imapMarkUnread, FALLBACK_TRASH_PATH, BASE64_TAIL_WINDOW, QP_EXACT_MAX_BYTES, imapBatchMarkRead, imapBatchMarkUnread, imapBatchFlag, imapBatchUnflag, imapBatchDelete;
|
|
68427
|
+
var import_imapflow, IMAP_ENV, defaultConnect, SPECIAL_USE_ALIASES, NOT_DELETED, LARGE_MAILBOX_MESSAGES, FIRST_SEARCH_WINDOW, MAX_WINDOW, MAX_UNSCOPED_SEARCH_DEPTH, COLOR_FETCH_CHUNK, ROW_QUERY, ROW_QUERY_NO_STRUCTURE, ROW_QUERY_HEADERS_ONLY, DELETED_MARGIN, poolConnect, pools, connecting, SENT_COPY_GMAIL_POLL_MS, SENT_COPY_GMAIL_POLL_INTERVAL_MS, GMAIL_HOST, MAX_COMPOSE_SOURCE_BYTES, MAX_RFC822_INLINE_BYTES, MAX_RFC822_FILE_BYTES, HEADER_WINDOW_BYTES, MAIL_FLAG_BITS, FLAG_COLOR_NAMES, imapMarkRead, imapMarkUnread, FALLBACK_TRASH_PATH, BASE64_TAIL_WINDOW, QP_EXACT_MAX_BYTES, imapBatchMarkRead, imapBatchMarkUnread, imapBatchFlag, imapBatchUnflag, imapBatchDelete;
|
|
68377
68428
|
var init_imapClient = __esm({
|
|
68378
68429
|
"src/services/imapClient.ts"() {
|
|
68379
68430
|
"use strict";
|
|
@@ -68472,6 +68523,9 @@ var init_imapClient = __esm({
|
|
|
68472
68523
|
poolConnect = defaultConnect;
|
|
68473
68524
|
pools = /* @__PURE__ */ new Map();
|
|
68474
68525
|
connecting = /* @__PURE__ */ new Map();
|
|
68526
|
+
SENT_COPY_GMAIL_POLL_MS = 3e3;
|
|
68527
|
+
SENT_COPY_GMAIL_POLL_INTERVAL_MS = 500;
|
|
68528
|
+
GMAIL_HOST = /(^|\.)(gmail|googlemail)\.com$/i;
|
|
68475
68529
|
MAX_COMPOSE_SOURCE_BYTES = 25 * 1024 * 1024;
|
|
68476
68530
|
MAX_RFC822_INLINE_BYTES = 6 * 1024 * 1024;
|
|
68477
68531
|
MAX_RFC822_FILE_BYTES = MAX_COMPOSE_SOURCE_BYTES;
|
|
@@ -89276,7 +89330,8 @@ async function runCompose(deps, args) {
|
|
|
89276
89330
|
// Best-effort Sent-folder copy (issue #220) — same field shape as
|
|
89277
89331
|
// send-email, since it's the same sendViaSmtp underneath.
|
|
89278
89332
|
...result.sentCopy !== void 0 ? { sentCopy: result.sentCopy } : {},
|
|
89279
|
-
...result.sentCopyError !== void 0 ? { sentCopyError: result.sentCopyError } : {}
|
|
89333
|
+
...result.sentCopyError !== void 0 ? { sentCopyError: result.sentCopyError } : {},
|
|
89334
|
+
...result.sentCopyAlreadyFiled ? { sentCopyAlreadyFiled: true } : {}
|
|
89280
89335
|
}
|
|
89281
89336
|
);
|
|
89282
89337
|
} catch (error3) {
|
|
@@ -91046,6 +91101,9 @@ var SENT_COPY_SCHEMA = external_exports.boolean().optional().describe(
|
|
|
91046
91101
|
"SMTP only: whether a best-effort copy was filed to the account's Sent mailbox over IMAP (issue #220). Absent when no configured IMAP account matches the SMTP identity \u2014 not a failure, the feature simply wasn't engaged."
|
|
91047
91102
|
);
|
|
91048
91103
|
var SENT_COPY_ERROR_SCHEMA = external_exports.string().optional().describe("Present only when sentCopy is false: why the Sent-folder copy failed.");
|
|
91104
|
+
var SENT_COPY_ALREADY_FILED_SCHEMA = external_exports.boolean().optional().describe(
|
|
91105
|
+
"Present (true) only when sentCopy is true because the Sent mailbox already held this Message-ID (e.g. Gmail's SMTP files its own copy), so none was appended."
|
|
91106
|
+
);
|
|
91049
91107
|
var SEND_ACCOUNT_SCHEMA = external_exports.string().optional().describe(
|
|
91050
91108
|
"Account to send from. AppleScript transport: a Mail account name or an exact sender address, resolved to one address and verified before sending; if it matches no enabled account, or Mail would use a different sender, nothing is sent and an error is returned. Omitted \u2192 Mail's default sender (reported back in `from`). SMTP transport: an email-form From override (see README)."
|
|
91051
91109
|
);
|
|
@@ -91078,7 +91136,8 @@ registerTool(
|
|
|
91078
91136
|
from: external_exports.string().optional().describe("AppleScript transport: the sender Mail.app used"),
|
|
91079
91137
|
messageId: external_exports.string().optional(),
|
|
91080
91138
|
sentCopy: SENT_COPY_SCHEMA,
|
|
91081
|
-
sentCopyError: SENT_COPY_ERROR_SCHEMA
|
|
91139
|
+
sentCopyError: SENT_COPY_ERROR_SCHEMA,
|
|
91140
|
+
sentCopyAlreadyFiled: SENT_COPY_ALREADY_FILED_SCHEMA
|
|
91082
91141
|
}
|
|
91083
91142
|
},
|
|
91084
91143
|
withErrorHandling(
|
|
@@ -91116,7 +91175,7 @@ registerTool(
|
|
|
91116
91175
|
if (!result.success) {
|
|
91117
91176
|
return errorResponse(result.error ?? "Failed to send email via SMTP.");
|
|
91118
91177
|
}
|
|
91119
|
-
const copyNote = result.sentCopy === true ? " (Sent-folder copy filed)" : result.sentCopy === false ? ` (Sent-folder copy NOT filed: ${result.sentCopyError ?? "unknown error"})` : "";
|
|
91178
|
+
const copyNote = result.sentCopy === true ? result.sentCopyAlreadyFiled ? " (Sent-folder copy already filed by the server)" : " (Sent-folder copy filed)" : result.sentCopy === false ? ` (Sent-folder copy NOT filed: ${result.sentCopyError ?? "unknown error"})` : "";
|
|
91120
91179
|
return successResponse(`Email sent via SMTP to ${to.join(", ")}${attachInfo}${copyNote}`, {
|
|
91121
91180
|
ok: true,
|
|
91122
91181
|
recipients: to,
|
|
@@ -91124,7 +91183,8 @@ registerTool(
|
|
|
91124
91183
|
transport: "smtp",
|
|
91125
91184
|
...result.messageId ? { messageId: result.messageId } : {},
|
|
91126
91185
|
...result.sentCopy !== void 0 ? { sentCopy: result.sentCopy } : {},
|
|
91127
|
-
...result.sentCopyError !== void 0 ? { sentCopyError: result.sentCopyError } : {}
|
|
91186
|
+
...result.sentCopyError !== void 0 ? { sentCopyError: result.sentCopyError } : {},
|
|
91187
|
+
...result.sentCopyAlreadyFiled ? { sentCopyAlreadyFiled: true } : {}
|
|
91128
91188
|
});
|
|
91129
91189
|
}
|
|
91130
91190
|
const sent = mailManager.sendEmail(to, subject, body, cc, bcc, account, attachments);
|
|
@@ -91333,7 +91393,8 @@ registerTool(
|
|
|
91333
91393
|
id: external_exports.string().optional(),
|
|
91334
91394
|
attachmentCount: external_exports.number().optional(),
|
|
91335
91395
|
sentCopy: SENT_COPY_SCHEMA,
|
|
91336
|
-
sentCopyError: SENT_COPY_ERROR_SCHEMA
|
|
91396
|
+
sentCopyError: SENT_COPY_ERROR_SCHEMA,
|
|
91397
|
+
sentCopyAlreadyFiled: SENT_COPY_ALREADY_FILED_SCHEMA
|
|
91337
91398
|
}
|
|
91338
91399
|
},
|
|
91339
91400
|
withErrorHandling((args) => runReply(composeDeps, args), "Error replying to message")
|
|
@@ -91359,7 +91420,8 @@ registerTool(
|
|
|
91359
91420
|
id: external_exports.string().optional(),
|
|
91360
91421
|
attachmentCount: external_exports.number().optional(),
|
|
91361
91422
|
sentCopy: SENT_COPY_SCHEMA,
|
|
91362
|
-
sentCopyError: SENT_COPY_ERROR_SCHEMA
|
|
91423
|
+
sentCopyError: SENT_COPY_ERROR_SCHEMA,
|
|
91424
|
+
sentCopyAlreadyFiled: SENT_COPY_ALREADY_FILED_SCHEMA
|
|
91363
91425
|
}
|
|
91364
91426
|
},
|
|
91365
91427
|
withErrorHandling((args) => runForward(composeDeps, args), "Error forwarding message")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-mail-mcp",
|
|
3
|
-
"version": "2.20.
|
|
3
|
+
"version": "2.20.26",
|
|
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",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"tsconfig-paths": "^4.2.0",
|
|
65
65
|
"typescript": "^5.0.0",
|
|
66
66
|
"typescript-eslint": "^8.51.0",
|
|
67
|
+
"vite": ">=8.2.4 <9",
|
|
67
68
|
"vitest": "^4.1.9"
|
|
68
69
|
},
|
|
69
70
|
"volta": {
|