apple-mail-mcp 2.8.3 → 2.8.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 CHANGED
@@ -98,6 +98,25 @@ npm install -g github:sweetrb/apple-mail-mcp
98
98
 
99
99
  On first use, macOS will ask for permission to automate Mail.app. Click "OK" to allow.
100
100
 
101
+ ## Configuring email (IMAP & SMTP)
102
+
103
+ The server works out of the box over AppleScript with **no configuration**. Two
104
+ **opt-in** power features take a one-time setup:
105
+
106
+ - **Fast IMAP reads** — server-side search, counts, and large-mailbox handling
107
+ that AppleScript is too slow for (it times out on big Gmail mailboxes).
108
+ - **Clean SMTP sending** — `send-email` submits clean MIME directly, avoiding the
109
+ macOS 15+ Mail.app `<blockquote>` wrapping that otherwise makes sent mail look
110
+ quoted/indented like a reply.
111
+
112
+ Both are driven by non-secret `APPLE_MAIL_MCP_*` settings — supplied via an `env`
113
+ block **or** a `config.json` file (for hosts like Claude Desktop that strip `env`)
114
+ — with passwords kept in the macOS **Keychain**, never in config.
115
+
116
+ 👉 **[IMAP / SMTP Setup Guide](docs/IMAP-SETUP.md)** — step-by-step: app passwords,
117
+ Keychain, both config methods, multi-account, SMTP, verification with the `doctor`
118
+ tool, and troubleshooting. Verify any time by running the **`doctor`** tool.
119
+
101
120
  ## Requirements
102
121
 
103
122
  - **macOS** - Apple Mail and AppleScript are macOS-only
package/build/index.js CHANGED
@@ -80308,6 +80308,28 @@ async function imapMoveMessageById(id, destMailbox, deps = {}) {
80308
80308
  }
80309
80309
  });
80310
80310
  }
80311
+ async function resolveTrashPath(client) {
80312
+ try {
80313
+ const boxes = await client.list();
80314
+ const special = boxes.find((b) => b.specialUse === "\\Trash");
80315
+ if (special) return special.path;
80316
+ const named = boxes.find(
80317
+ (b) => /^(trash|deleted messages|deleted items|bin)$/i.test(b.name) || /(^|\/)trash$/i.test(b.path)
80318
+ );
80319
+ if (named) return named.path;
80320
+ } catch {
80321
+ }
80322
+ return resolveMailboxPath("trash", "list");
80323
+ }
80324
+ async function trashUids(client, uids, srcPath) {
80325
+ const dest = await resolveTrashPath(client);
80326
+ if (srcPath.trim().toLowerCase() === dest.trim().toLowerCase()) {
80327
+ await client.messageDelete(uids, { uid: true });
80328
+ return { dest, expunged: true };
80329
+ }
80330
+ await client.messageMove(uids, dest, { uid: true });
80331
+ return { dest, expunged: false };
80332
+ }
80311
80333
  async function imapDeleteMessageById(id, deps = {}) {
80312
80334
  const ref = decodeImapId(id);
80313
80335
  if (!ref) return { success: false, error: `Not an IMAP message id: "${id}".` };
@@ -80316,9 +80338,11 @@ async function imapDeleteMessageById(id, deps = {}) {
80316
80338
  { ...deps, account: deps.account ?? ref.account },
80317
80339
  async (client) => {
80318
80340
  try {
80319
- const ok = await client.messageDelete([ref.uid], { uid: true });
80320
- if (!ok) return { success: false, error: `IMAP delete returned false for UID ${ref.uid}.` };
80321
- return { success: true, info: `Deleted UID ${ref.uid} from "${ref.path}" via IMAP.` };
80341
+ const { dest, expunged } = await trashUids(client, [ref.uid], ref.path);
80342
+ return {
80343
+ success: true,
80344
+ info: expunged ? `Permanently deleted UID ${ref.uid} from Trash ("${ref.path}") via IMAP.` : `Moved UID ${ref.uid} to Trash ("${dest}") via IMAP.`
80345
+ };
80322
80346
  } catch (e) {
80323
80347
  return { success: false, error: `IMAP delete failed for UID ${ref.uid}: ${errText(e)}` };
80324
80348
  }
@@ -80445,8 +80469,8 @@ var imapBatchFlag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) =>
80445
80469
  var imapBatchUnflag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
80446
80470
  await c.messageFlagsRemove(uids, ["\\Flagged"], { uid: true });
80447
80471
  });
80448
- var imapBatchDelete = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
80449
- await c.messageDelete(uids, { uid: true });
80472
+ var imapBatchDelete = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids, path) => {
80473
+ await trashUids(c, uids, path);
80450
80474
  });
80451
80475
  function imapBatchMove(ids, destMailbox, deps = {}) {
80452
80476
  return imapBatch(ids, deps, async (c, uids) => {
@@ -80733,6 +80757,8 @@ async function routeMessage(id, opts) {
80733
80757
  }
80734
80758
 
80735
80759
  // src/tools/doctor.ts
80760
+ var SETUP_GUIDE = "https://github.com/sweetrb/apple-mail-mcp/blob/main/docs/IMAP-SETUP.md";
80761
+ var CONFIG_FILE_HINT = "If your MCP host ignores the server 'env' block (e.g. Claude Desktop), put these in ~/Library/Application Support/apple-mail-mcp/config.json instead";
80736
80762
  async function runDoctor(mailManager2) {
80737
80763
  const checks = [];
80738
80764
  const hc = mailManager2.healthCheck();
@@ -80764,7 +80790,7 @@ async function runDoctor(mailManager2) {
80764
80790
  checks.push({
80765
80791
  name: "IMAP backend",
80766
80792
  status: "warn",
80767
- detail: `not configured \u2014 AppleScript is used for all accounts. Set ${IMAP_ENV.user} (+ Keychain/password), or ${IMAP_ENV.accounts} for multiple accounts, to enable server-side search and server-mailbox ops.`
80793
+ detail: `not configured \u2014 AppleScript is used for all accounts. Set ${IMAP_ENV.user} (+ Keychain/password), or ${IMAP_ENV.accounts} for multiple accounts, to enable server-side search and server-mailbox ops. ${CONFIG_FILE_HINT}. Setup guide: ${SETUP_GUIDE}`
80768
80794
  });
80769
80795
  } else {
80770
80796
  for (const label of imapAccounts) {
@@ -80780,7 +80806,7 @@ async function runDoctor(mailManager2) {
80780
80806
  checks.push({
80781
80807
  name: "SMTP transport",
80782
80808
  status: isSmtpConfigured() ? "ok" : "warn",
80783
- detail: isSmtpConfigured() ? `configured (${smtpHost}); send-email auto-prefers clean SMTP (no Mail.app Sent-folder copy; a non-email "account" label still routes to AppleScript). Pass transport:"applescript" to force Mail.app. The apple-mail-send CLI is also available.` : `not configured \u2014 send-email uses AppleScript (subject to macOS 15+ blockquote wrapping). Set ${SMTP_ENV.host} and ${SMTP_ENV.user} (+ password via Keychain) to enable.`
80809
+ detail: isSmtpConfigured() ? `configured (${smtpHost}); send-email auto-prefers clean SMTP (no Mail.app Sent-folder copy; a non-email "account" label still routes to AppleScript). Pass transport:"applescript" to force Mail.app. The apple-mail-send CLI is also available.` : `not configured \u2014 send-email uses AppleScript (subject to macOS 15+ blockquote wrapping). Set ${SMTP_ENV.host} and ${SMTP_ENV.user} (+ password via Keychain) to enable. ${CONFIG_FILE_HINT}. Setup guide: ${SETUP_GUIDE}`
80784
80810
  });
80785
80811
  const healthy = !checks.some((c) => c.status === "fail");
80786
80812
  return { healthy, checks };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.8.3",
3
+ "version": "2.8.5",
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",