apple-mail-mcp 2.19.21 → 2.20.0

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
@@ -164,11 +164,11 @@ tool, and troubleshooting. Verify any time by running the **`doctor`** tool.
164
164
  | **Search Messages** | Search by sender, subject, content, date range, read/flagged status — across all accounts |
165
165
  | **Read Messages** | Get full email content (plain text or HTML) |
166
166
  | **Read Headers** | Get a message's raw RFC 5322 headers — the author's `Date:`, Message-ID, threading ids, `Received:` trace — without downloading the body |
167
- | **Send Email** | Compose and send new emails (attach by file path or inline base64 content) |
167
+ | **Send Email** | Compose and send new emails (attach by file path or inline base64 content; optional `inReplyTo`/`references` threading over SMTP) |
168
168
  | **Send Serial Email** | Mail merge — send personalized emails to a list of recipients with {{placeholder}} support |
169
- | **Create Draft** | Save emails to Drafts folder (attach by file path or inline base64 content) |
170
- | **Reply** | Reply to messages (with reply-all support) |
171
- | **Forward** | Forward messages to new recipients |
169
+ | **Create Draft** | Save emails to Drafts folder (attach by file path or inline base64 content; threaded drafts filed over IMAP) |
170
+ | **Reply** | Reply to messages (with reply-all support and attachments) |
171
+ | **Forward** | Forward messages to new recipients (with extra attachments) |
172
172
  | **Get Thread** | Group a conversation by normalized subject (across AppleScript or IMAP) |
173
173
  | **Mark Read/Unread** | Change read status (single or batch) |
174
174
  | **Flag/Unflag** | Flag or unflag messages (single or batch) |
@@ -402,16 +402,19 @@ Send a new email immediately.
402
402
 
403
403
  **⚠️ Safety:** Sends real mail immediately and cannot be unsent. Confirm the recipients, subject, and body with the user before calling.
404
404
 
405
- | Parameter | Type | Required | Description |
406
- | ------------- | --------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
407
- | `to` | string[] | Yes | Recipient addresses |
408
- | `subject` | string | Yes | Email subject |
409
- | `body` | string | Yes | Email body (plain text) |
410
- | `cc` | string[] | No | CC recipients |
411
- | `bcc` | string[] | No | BCC recipients |
412
- | `account` | string | No | Mail.app account label, or an email-form SMTP From override. An SMTP override must match `APPLE_MAIL_MCP_SMTP_USER`, `APPLE_MAIL_MCP_SMTP_FROM`, or an address in `APPLE_MAIL_MCP_SMTP_ALLOWED_FROM` |
413
- | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots (e.g., `"/Users/me/Documents/report.pdf"`) and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
414
- | `transport` | `"applescript"` \| `"smtp"` | No | Send transport. If omitted, **SMTP is used automatically when configured** (otherwise AppleScript). Pass `"smtp"` to require clean MIME, or `"applescript"` to force the Mail.app path — see [SMTP transport](#smtp-transport) |
405
+ | Parameter | Type | Required | Description |
406
+ | ------------- | --------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
407
+ | `to` | string[] | Yes | Recipient addresses |
408
+ | `subject` | string | Yes | Email subject |
409
+ | `body` | string | Yes | Email body (plain text) |
410
+ | `cc` | string[] | No | CC recipients |
411
+ | `bcc` | string[] | No | BCC recipients |
412
+ | `account` | string | No | Mail.app account label, or an email-form SMTP From override. An SMTP override must match `APPLE_MAIL_MCP_SMTP_USER`, `APPLE_MAIL_MCP_SMTP_FROM`, or an address in `APPLE_MAIL_MCP_SMTP_ALLOWED_FROM` |
413
+ | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots (e.g., `"/Users/me/Documents/report.pdf"`) and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
414
+ | `transport` | `"applescript"` \| `"smtp"` | No | Send transport. If omitted, **SMTP is used automatically when configured** (otherwise AppleScript). Pass `"smtp"` to require clean MIME, or `"applescript"` to force the Mail.app path — see [SMTP transport](#smtp-transport) |
415
+ | `replyTo` | string | No | SMTP only: `Reply-To` header, when replies should go somewhere other than the From address. Ignored on the AppleScript transport |
416
+ | `inReplyTo` | string | No | SMTP only (2.20.0): thread the message as a reply — the parent's `Message-ID` token with angle brackets, e.g. `"<abc@mail.example.com>"`. Emitted verbatim, never RFC 2047-encoded. See [Threading headers](#threading-headers-inreplyto--references) |
417
+ | `references` | string[] | No | SMTP only (2.20.0): the `References` chain, oldest first (the parent's own `References` + its `Message-ID`). Defaults to `[inReplyTo]` when omitted |
415
418
 
416
419
  **Example:**
417
420
 
@@ -425,6 +428,22 @@ Send a new email immediately.
425
428
  }
426
429
  ```
427
430
 
431
+ ##### Threading headers (`inReplyTo` / `references`)
432
+
433
+ `send-email` and `create-draft` accept caller-built threading headers (2.20.0, #267) for
434
+ callers that compose the recipients and quoted text themselves. **Prefer
435
+ `reply-to-message`** — it derives recipients, `In-Reply-To`/`References` and the quote
436
+ from the original, and (since 2.20.0) takes attachments too.
437
+
438
+ - Each value must be a single RFC 5322 msg-id token **with** angle brackets
439
+ (`<left@right>`, no whitespace); anything else is rejected by validation.
440
+ - The headers are always emitted as plain `<id>` tokens — never RFC 2047-encoded, even
441
+ for Outlook/Exchange IDs longer than 76 characters (a long header is folded at
442
+ whitespace between tokens, which is legal and does not alter the id).
443
+ - Mail.app's AppleScript cannot set these headers, so they are **never silently
444
+ dropped**: `send-email` refuses them unless the SMTP transport is in use, and
445
+ `create-draft` files a threaded draft over IMAP instead of through Mail.app (below).
446
+
428
447
  ##### SMTP transport
429
448
 
430
449
  On macOS 15+ (Sequoia/Tahoe), Mail.app wraps any AppleScript-injected body in
@@ -783,10 +802,24 @@ Save an email to Drafts without sending.
783
802
  | `body` | string | Yes | Email body (plain text) |
784
803
  | `cc` | string[] | No | CC recipients |
785
804
  | `bcc` | string[] | No | BCC recipients |
786
- | `account` | string | No | Account for draft |
805
+ | `account` | string | No | Account for draft. With `inReplyTo`/`references` it must name a configured IMAP account (label or login) |
787
806
  | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments: absolute file paths inside the configured read roots and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
788
-
789
- **Returns:** Confirmation that draft was created.
807
+ | `inReplyTo` | string | No | (2.20.0) Parent `Message-ID` token, e.g. `"<abc@mail.example.com>"` — makes this a **threaded draft** (see below) |
808
+ | `references` | string[] | No | (2.20.0) `References` chain, oldest first; defaults to `[inReplyTo]` |
809
+
810
+ **Returns:** Confirmation that draft was created, with `transport` (`applescript`, or `imap` for a threaded draft).
811
+
812
+ **Threaded drafts (2.20.0, #267):** Mail.app's `outgoing message` has no header property,
813
+ so a draft with `inReplyTo`/`references` cannot go through AppleScript. Instead the
814
+ server composes it with the same MIME builder as the SMTP send (attachments included) and
815
+ files it over IMAP into the account's Drafts mailbox (SPECIAL-USE `\Drafts`), flagged
816
+ `\Draft`. The account is `account` when given (it must be a configured IMAP account);
817
+ otherwise the IMAP account whose login is the SMTP identity, else the only configured
818
+ IMAP account. When none qualifies — IMAP unconfigured, an unknown `account`, or several
819
+ accounts and no way to choose — the call **fails and files nothing**; it never falls back
820
+ to an unthreaded Mail.app draft. The result names the Drafts `mailbox`, the `account` and
821
+ the draft's `messageId`. Without threading headers, `create-draft` is unchanged
822
+ (AppleScript).
790
823
 
791
824
  #### `get-thread`
792
825
 
@@ -832,13 +865,14 @@ Map `imap:` message IDs to their numeric Mail.app IDs, via each message's RFC 53
832
865
 
833
866
  Reply to an existing message.
834
867
 
835
- | Parameter | Type | Required | Description |
836
- | ----------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
837
- | `id` | string | Yes | Message ID to reply to |
838
- | `body` | string | Yes | Reply body (plain text; HTML tags such as `<br>` are not rendered) |
839
- | `replyAll` | boolean | No | Reply to all recipients (default: false) |
840
- | `send` | boolean | No | Send immediately (default: true, false = save as draft) |
841
- | `transport` | string | No | `smtp` or `applescript`; omitted prefers configured SMTP when sending. Drafts use AppleScript. |
868
+ | Parameter | Type | Required | Description |
869
+ | ------------- | --------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
870
+ | `id` | string | Yes | Message ID to reply to |
871
+ | `body` | string | Yes | Reply body (plain text; HTML tags such as `<br>` are not rendered) |
872
+ | `replyAll` | boolean | No | Reply to all recipients (default: false) |
873
+ | `send` | boolean | No | Send immediately (default: true, false = save as draft) |
874
+ | `transport` | string | No | `smtp` or `applescript`; omitted prefers configured SMTP when sending. Drafts use AppleScript. |
875
+ | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 attachments, same rules as `send-email`: absolute file paths inside the configured read roots and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
842
876
 
843
877
  **Example - Reply to sender only:**
844
878
 
@@ -860,6 +894,30 @@ Reply to an existing message.
860
894
  }
861
895
  ```
862
896
 
897
+ **Example - Reply all with an attachment (2.20.0):**
898
+
899
+ ```json
900
+ {
901
+ "id": "imap:eyJhIjoiV29yayIsInAiOiJJTkJPWCIsInUiOjQyfQ",
902
+ "body": "Here is the PDF you asked for.",
903
+ "replyAll": true,
904
+ "attachments": [
905
+ "/Users/me/Documents/quote.pdf",
906
+ { "filename": "notes.txt", "contentBase64": "SGVsbG8K" }
907
+ ]
908
+ }
909
+ ```
910
+
911
+ **Attachments (2.20.0, #267):** same schema, limits (20 items, 25 MiB each) and read
912
+ roots as `send-email`, validated before the original is fetched — an out-of-roots path
913
+ fails with exactly `send-email`'s error. Recipients, threading headers and the quote are
914
+ identical to the same call without attachments. Over SMTP the files ride the same
915
+ nodemailer path `send-email` uses, so the Sent-folder copy (`sentCopy`) carries them too.
916
+ On the AppleScript transport they are added with `make new attachment` **after** the
917
+ reply content is set and before `save`/`send` (inline items are written to `0600` temp
918
+ files and removed afterwards), so a `send: false` draft contains both the attachments and
919
+ the quoted original. Results report `attachmentCount`.
920
+
863
921
  **Delivery:** `imap:` IDs are read directly from their encoded account, mailbox, and UID. Numeric IDs are read through Mail.app. With SMTP configured, replies use clean MIME with the original `Message-ID` in `In-Reply-To` and the full `References` chain. Only the original plain-text body is quoted; the new text is not. Pass `transport: "smtp"` to require this path, or `transport: "applescript"` to use Mail.app explicitly.
864
922
 
865
923
  **AppleScript transport quoting (v2.19.12):** every draft (`send: false`) and any send that falls back to AppleScript (SMTP not configured) also gets the original quoted — an "On \<date\>, \<sender\> wrote:" attribution line followed by the `> `-prefixed original body, built the same way as the SMTP path. Mail's own `reply`/`forward` AppleScript commands generate this quote internally but expose no way to read it back, so it's built here instead of relying on Mail's (unreadable) copy. Unlike SMTP, this path has no sending-identity restriction — it's read-only source lookup, not sending.
@@ -868,7 +926,7 @@ Reply to an existing message.
868
926
 
869
927
  The direct IMAP source read is bounded to 25 MiB, including MIME attachments. Its account login must match the SMTP login, configured From, or an explicitly configured `APPLE_MAIL_MCP_SMTP_ALLOWED_FROM` identity; otherwise the call fails rather than sending from an unrelated account. The SMTP configuration still represents a single sending identity, not a per-account SMTP registry.
870
928
 
871
- Success includes `transport` and, for SMTP when returned by the server, the new `messageId`. SMTP submission does not add a local Sent copy; server-side Sent-folder behavior is unchanged. `send-email` is for **new conversations**: adding `Re:` to its subject does not add threading headers. Use this reply tool with the original id instead.
929
+ Success includes `transport`, `attachmentCount` and, for SMTP when returned by the server, the new `messageId`. Over SMTP a best-effort Sent-folder copy is filed over IMAP exactly as for `send-email` (`sentCopy` / `sentCopyError`, see [SMTP transport](#smtp-transport)). `send-email` is for **new conversations**: adding `Re:` to its subject does not add threading headers. Use this reply tool with the original id instead.
872
930
 
873
931
  **⚠️ Safety:** With the default `send: true`, sends real mail immediately and cannot be unsent. Confirm the recipients, subject, and body with the user before calling (or pass `send: false` to save a draft for review).
874
932
 
@@ -878,15 +936,18 @@ Success includes `transport` and, for SMTP when returned by the server, the new
878
936
 
879
937
  Forward a message to new recipients.
880
938
 
881
- | Parameter | Type | Required | Description |
882
- | ----------- | -------- | -------- | ---------------------------------------------------------------------------------------------- |
883
- | `id` | string | Yes | Message ID to forward |
884
- | `to` | string[] | Yes | Recipients to forward to |
885
- | `body` | string | No | Message to prepend (plain text) |
886
- | `send` | boolean | No | Send immediately (default: true, false = save as draft) |
887
- | `transport` | string | No | `smtp` or `applescript`; omitted prefers configured SMTP when sending. Drafts use AppleScript. |
939
+ | Parameter | Type | Required | Description |
940
+ | ------------- | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
941
+ | `id` | string | Yes | Message ID to forward |
942
+ | `to` | string[] | Yes | Recipients to forward to |
943
+ | `body` | string | No | Message to prepend (plain text) |
944
+ | `send` | boolean | No | Send immediately (default: true, false = save as draft) |
945
+ | `transport` | string | No | `smtp` or `applescript`; omitted prefers configured SMTP when sending. Drafts use AppleScript. |
946
+ | `attachments` | (string \| {filename, contentBase64})[] | No | Up to 20 additional attachments, same rules as `send-email`: absolute file paths inside the configured read roots and/or inline `{filename, contentBase64}` objects up to 25 MiB decoded each |
947
+
948
+ **Delivery:** uses the same source lookup, transport selection, 25 MiB source limit, account-identity check, and failure behavior as `reply-to-message`. A forward deliberately starts a new conversation, so it has no `In-Reply-To` or `References` headers. The existing plain-text forwarding behavior is unchanged: original attachments are not reattached. See [SMTP transport](#smtp-transport). On the AppleScript transport, a `body` is merged with the forwarded-message header block and original text the same way the SMTP path builds it (see `reply-to-message`'s AppleScript transport quoting note); with no `body`, Mail's own forward content is left untouched — unless `attachments` are given, in which case the forwarded-message block is built the same way so Mail has a paragraph to anchor the new files after.
888
949
 
889
- **Delivery:** uses the same source lookup, transport selection, 25 MiB source limit, account-identity check, and failure behavior as `reply-to-message`. A forward deliberately starts a new conversation, so it has no `In-Reply-To` or `References` headers. The existing plain-text forwarding behavior is unchanged: original attachments are not reattached. See [SMTP transport](#smtp-transport). On the AppleScript transport, a `body` is merged with the forwarded-message header block and original text the same way the SMTP path builds it (see `reply-to-message`'s AppleScript transport quoting note); with no `body`, Mail's own forward content is left untouched.
950
+ **Attachments (2.20.0, #267):** `attachments` adds new files to the forward, with or without a prepended `body`, under the same rules, validation and per-transport mechanics as `reply-to-message`'s attachments. They are independent of the original's attachments (which the SMTP path still does not reattach).
890
951
 
891
952
  SMTP forwarding requires a readable plain-text original. HTML-only IMAP messages and failed Mail.app body reads return an error before sending instead of silently omitting the original content. Explicitly select `transport: "applescript"` to forward these with Mail.app; no automatic fallback occurs. An intentionally empty plain-text message is still valid.
892
953
 
package/build/cli.js CHANGED
@@ -45149,9 +45149,9 @@ var require_util2 = __commonJS({
45149
45149
  }
45150
45150
  });
45151
45151
 
45152
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/address-error.js
45152
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/address-error.js
45153
45153
  var require_address_error = __commonJS({
45154
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/address-error.js"(exports) {
45154
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/address-error.js"(exports) {
45155
45155
  "use strict";
45156
45156
  Object.defineProperty(exports, "__esModule", { value: true });
45157
45157
  exports.AddressError = void 0;
@@ -45166,9 +45166,9 @@ var require_address_error = __commonJS({
45166
45166
  }
45167
45167
  });
45168
45168
 
45169
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/common.js
45169
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/common.js
45170
45170
  var require_common = __commonJS({
45171
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/common.js"(exports) {
45171
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/common.js"(exports) {
45172
45172
  "use strict";
45173
45173
  Object.defineProperty(exports, "__esModule", { value: true });
45174
45174
  exports.isInSubnet = isInSubnet;
@@ -45189,6 +45189,9 @@ var require_common = __commonJS({
45189
45189
  return isHostInSubnet.call(this, address);
45190
45190
  }
45191
45191
  function isHostInSubnet(address) {
45192
+ if (this.binaryZeroPad().length !== address.binaryZeroPad().length) {
45193
+ return false;
45194
+ }
45192
45195
  return this.mask(address.subnetMask) === address.mask();
45193
45196
  }
45194
45197
  function isGloballyReachable(entries) {
@@ -45266,9 +45269,9 @@ var require_common = __commonJS({
45266
45269
  }
45267
45270
  });
45268
45271
 
45269
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v4/constants.js
45272
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v4/constants.js
45270
45273
  var require_constants3 = __commonJS({
45271
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v4/constants.js"(exports) {
45274
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v4/constants.js"(exports) {
45272
45275
  "use strict";
45273
45276
  Object.defineProperty(exports, "__esModule", { value: true });
45274
45277
  exports.SPECIAL_PURPOSE = exports.RE_SUBNET_STRING = exports.RE_ADDRESS = exports.GROUPS = exports.BITS = void 0;
@@ -45307,9 +45310,9 @@ var require_constants3 = __commonJS({
45307
45310
  }
45308
45311
  });
45309
45312
 
45310
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/ipv4.js
45313
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/ipv4.js
45311
45314
  var require_ipv4 = __commonJS({
45312
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/ipv4.js"(exports) {
45315
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/ipv4.js"(exports) {
45313
45316
  "use strict";
45314
45317
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
45315
45318
  if (k2 === void 0) k2 = k;
@@ -45367,6 +45370,10 @@ var require_ipv4 = __commonJS({
45367
45370
  }
45368
45371
  address = address.replace(constants.RE_SUBNET_STRING, "");
45369
45372
  }
45373
+ const longest = constants.GROUPS * 4 - 1;
45374
+ if (address.length > longest) {
45375
+ throw new address_error_1.AddressError(`IPv4 addresses are at most ${longest} characters.`);
45376
+ }
45370
45377
  this.addressMinusSuffix = address;
45371
45378
  this.parsedAddress = this.parse(address);
45372
45379
  }
@@ -45503,15 +45510,18 @@ var require_ipv4 = __commonJS({
45503
45510
  return _Address4.fromHex(integer.toString(16).padStart(8, "0"));
45504
45511
  }
45505
45512
  /**
45506
- * Return an address from in-addr.arpa form
45513
+ * Return an address from in-addr.arpa form: the four octets reversed, with
45514
+ * or without the `.in-addr.arpa` suffix and root dot, in any case. Throws
45515
+ * `AddressError` unless the reversed labels form a valid IPv4 address, so
45516
+ * `fromArpa(x.reverseForm())` round-trips {@link reverseForm}.
45507
45517
  * @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
45508
45518
  * @returns {Adress4}
45509
45519
  * @example
45510
- * var address = Address4.fromArpa(42.2.0.192.in-addr.arpa.)
45520
+ * var address = Address4.fromArpa('42.2.0.192.in-addr.arpa.')
45511
45521
  * address.correctForm(); // '192.0.2.42'
45512
45522
  */
45513
45523
  static fromArpa(arpaFormAddress) {
45514
- const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.$/, "");
45524
+ const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.?$/i, "");
45515
45525
  const address = leader.split(".").reverse().join(".");
45516
45526
  return new _Address4(address);
45517
45527
  }
@@ -45865,9 +45875,9 @@ var require_ipv4 = __commonJS({
45865
45875
  }
45866
45876
  });
45867
45877
 
45868
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v6/constants.js
45878
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v6/constants.js
45869
45879
  var require_constants4 = __commonJS({
45870
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v6/constants.js"(exports) {
45880
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v6/constants.js"(exports) {
45871
45881
  "use strict";
45872
45882
  Object.defineProperty(exports, "__esModule", { value: true });
45873
45883
  exports.SPECIAL_PURPOSE = exports.RE_URL_WITH_PORT = exports.RE_URL = exports.RE_ZONE_STRING = exports.RE_SUBNET_STRING = exports.RE_BAD_ADDRESS = exports.RE_BAD_CHARACTERS = exports.TYPES = exports.SCOPES = exports.GROUPS = exports.BITS = void 0;
@@ -45955,9 +45965,9 @@ var require_constants4 = __commonJS({
45955
45965
  }
45956
45966
  });
45957
45967
 
45958
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v6/helpers.js
45968
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v6/helpers.js
45959
45969
  var require_helpers = __commonJS({
45960
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v6/helpers.js"(exports) {
45970
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v6/helpers.js"(exports) {
45961
45971
  "use strict";
45962
45972
  Object.defineProperty(exports, "__esModule", { value: true });
45963
45973
  exports.escapeHtml = escapeHtml;
@@ -45994,9 +46004,9 @@ var require_helpers = __commonJS({
45994
46004
  }
45995
46005
  });
45996
46006
 
45997
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v6/regular-expressions.js
46007
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v6/regular-expressions.js
45998
46008
  var require_regular_expressions = __commonJS({
45999
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/v6/regular-expressions.js"(exports) {
46009
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/v6/regular-expressions.js"(exports) {
46000
46010
  "use strict";
46001
46011
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
46002
46012
  if (k2 === void 0) k2 = k;
@@ -46086,9 +46096,9 @@ var require_regular_expressions = __commonJS({
46086
46096
  }
46087
46097
  });
46088
46098
 
46089
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/ipv6.js
46099
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/ipv6.js
46090
46100
  var require_ipv6 = __commonJS({
46091
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/ipv6.js"(exports) {
46101
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/ipv6.js"(exports) {
46092
46102
  "use strict";
46093
46103
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
46094
46104
  if (k2 === void 0) k2 = k;
@@ -46199,6 +46209,10 @@ var require_ipv6 = __commonJS({
46199
46209
  this.zone = zone[0];
46200
46210
  address = address.replace(constants6.RE_ZONE_STRING, "");
46201
46211
  }
46212
+ const longest = this.groups * 5 + 5;
46213
+ if (address.length > longest) {
46214
+ throw new address_error_1.AddressError(`IPv6 addresses are at most ${longest} characters.`);
46215
+ }
46202
46216
  this.addressMinusSuffix = address;
46203
46217
  this.parsedAddress = this.parse(this.addressMinusSuffix);
46204
46218
  }
@@ -46395,7 +46409,7 @@ var require_ipv6 = __commonJS({
46395
46409
  * Address6.fromArpa('8.b.d.0.1.0.0.2.ip6.arpa.').networkForm(); // '2001:db8::/32'
46396
46410
  */
46397
46411
  static fromArpa(arpaFormAddress) {
46398
- const nibbles = arpaFormAddress.replace(/(\.ip6\.arpa)?\.?$/, "");
46412
+ const nibbles = arpaFormAddress.replace(/(\.ip6\.arpa)?\.?$/i, "");
46399
46413
  if (!/^[0-9a-f](\.[0-9a-f]){0,31}$/i.test(nibbles)) {
46400
46414
  throw new address_error_1.AddressError("Invalid 'ip6.arpa' form.");
46401
46415
  }
@@ -47415,9 +47429,9 @@ var require_ipv6 = __commonJS({
47415
47429
  }
47416
47430
  });
47417
47431
 
47418
- // node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/ip-address.js
47432
+ // node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/ip-address.js
47419
47433
  var require_ip_address = __commonJS({
47420
- "node_modules/.pnpm/ip-address@10.7.0/node_modules/ip-address/dist/ip-address.js"(exports) {
47434
+ "node_modules/.pnpm/ip-address@10.7.2/node_modules/ip-address/dist/ip-address.js"(exports) {
47421
47435
  "use strict";
47422
47436
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
47423
47437
  if (k2 === void 0) k2 = k;
@@ -57832,6 +57846,7 @@ __export(imapClient_exports, {
57832
57846
  decodeImapId: () => decodeImapId,
57833
57847
  dropAllPools: () => dropAllPools,
57834
57848
  encodeImapId: () => encodeImapId,
57849
+ imapAppendDraft: () => imapAppendDraft,
57835
57850
  imapAppendSentCopy: () => imapAppendSentCopy,
57836
57851
  imapBatchDelete: () => imapBatchDelete,
57837
57852
  imapBatchFlag: () => imapBatchFlag,
@@ -57869,6 +57884,7 @@ __export(imapClient_exports, {
57869
57884
  matchMailbox: () => matchMailbox,
57870
57885
  normalizeMessageId: () => normalizeMessageId,
57871
57886
  omittedNote: () => omittedNote,
57887
+ resolveDraftImapAccount: () => resolveDraftImapAccount,
57872
57888
  resolveImapConfig: () => resolveImapConfig,
57873
57889
  resolveImapConfigs: () => resolveImapConfigs,
57874
57890
  resolveMailboxPath: () => resolveMailboxPath,
@@ -58926,6 +58942,40 @@ async function imapAppendSentCopy(smtpUser, raw, deps = {}) {
58926
58942
  return { attempted: true, success: false, error: errText(e) };
58927
58943
  }
58928
58944
  }
58945
+ function resolveDraftImapAccount(account, smtpUser, env = process.env) {
58946
+ const specs = listImapAccountSpecs(env);
58947
+ 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";
58948
+ if (specs.length === 0) {
58949
+ throw new Error(
58950
+ `${why}, and IMAP is not configured. Configure IMAP, omit inReplyTo/references, or use reply-to-message with send=false. ${SETUP_HINT}`
58951
+ );
58952
+ }
58953
+ let spec;
58954
+ if (account) {
58955
+ spec = specs.find((s) => specMatchesSelector(s, account));
58956
+ if (!spec) {
58957
+ throw new Error(
58958
+ `${why}, and "${account}" is not a configured IMAP account. Configured: ${specs.map((s) => s.accountLabel).join(", ")}.`
58959
+ );
58960
+ }
58961
+ } else {
58962
+ spec = (smtpUser ? specs.find((s) => specMatchesSelector(s, smtpUser)) : void 0) ?? (specs.length === 1 ? specs[0] : void 0);
58963
+ if (!spec) {
58964
+ throw new Error(
58965
+ `${why}; several IMAP accounts are configured, so pass \`account\` to choose one: ${specs.map((s) => s.accountLabel).join(", ")}.`
58966
+ );
58967
+ }
58968
+ }
58969
+ return { label: spec.accountLabel, user: spec.user };
58970
+ }
58971
+ async function imapAppendDraft(account, raw, deps = {}) {
58972
+ return withClient({ ...deps, account: deps.account ?? account }, async (client, cfg) => {
58973
+ const path3 = await resolveMailboxPath(client, "drafts", "list");
58974
+ const res = await client.append(path3, raw, ["\\Draft", "\\Seen"]);
58975
+ if (!res) throw new Error(`server rejected the APPEND to "${path3}" (IMAP NO/BAD)`);
58976
+ return { mailbox: path3, account: cfg.accountLabel };
58977
+ });
58978
+ }
58929
58979
  async function withMailbox(path3, deps, fn) {
58930
58980
  return withClient(deps, async (client) => {
58931
58981
  const lock = await client.getMailboxLock(path3);
@@ -59781,6 +59831,27 @@ function buildAttachments(attachments) {
59781
59831
  return { filename: a.filename, content: decodeInlineAttachment(a.contentBase64) };
59782
59832
  });
59783
59833
  }
59834
+ function buildMailOptions(opts, from, attachments) {
59835
+ const html = opts.htmlBody?.trim() ? opts.htmlBody : void 0;
59836
+ return {
59837
+ from,
59838
+ to: opts.to,
59839
+ cc: opts.cc,
59840
+ bcc: opts.bcc,
59841
+ subject: opts.subject,
59842
+ text: opts.body,
59843
+ // When present, nodemailer emits multipart/alternative (text + html).
59844
+ html,
59845
+ attachments,
59846
+ // RFC 5322 threading for SMTP replies/forwards (2.5.0). nodemailer treats
59847
+ // In-Reply-To / References as structured msg-id headers and never
59848
+ // RFC 2047-encodes them, however long the id (pinned by a test, #267).
59849
+ inReplyTo: opts.inReplyTo?.trim() || void 0,
59850
+ references: opts.references?.length ? opts.references : void 0,
59851
+ // Reply-To header (2.18.0, issue #220): nodemailer already supports this.
59852
+ replyTo: opts.replyTo?.trim() || void 0
59853
+ };
59854
+ }
59784
59855
  async function sendViaSmtp(opts, config, createTransport2 = nodemailer_default.createTransport, appendSentCopy = defaultAppendSentCopy) {
59785
59856
  let cfg;
59786
59857
  try {
@@ -59819,23 +59890,7 @@ async function sendViaSmtp(opts, config, createTransport2 = nodemailer_default.c
59819
59890
  requireTLS,
59820
59891
  auth: { user: cfg.user, pass: cfg.pass }
59821
59892
  });
59822
- const html = opts.htmlBody?.trim() ? opts.htmlBody : void 0;
59823
- const mailOptions = {
59824
- from: requestedFrom || cfg.from,
59825
- to: opts.to,
59826
- cc: opts.cc,
59827
- bcc: opts.bcc,
59828
- subject: opts.subject,
59829
- text: opts.body,
59830
- // When present, nodemailer emits multipart/alternative (text + html).
59831
- html,
59832
- attachments,
59833
- // RFC 5322 threading for SMTP replies/forwards (2.5.0).
59834
- inReplyTo: opts.inReplyTo?.trim() || void 0,
59835
- references: opts.references?.length ? opts.references : void 0,
59836
- // Reply-To header (2.18.0, issue #220): nodemailer already supports this.
59837
- replyTo: opts.replyTo?.trim() || void 0
59838
- };
59893
+ const mailOptions = buildMailOptions(opts, requestedFrom || cfg.from, attachments);
59839
59894
  try {
59840
59895
  const info = await transporter.sendMail(mailOptions);
59841
59896
  let copyFields = {};