hypermail-mcp 0.7.2 → 0.7.4

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
@@ -3,6 +3,16 @@
3
3
  A **Model Context Protocol** server that lets an agent operate any of the user's
4
4
  inboxes through a single, unified tool surface.
5
5
 
6
+ > **v0.7.4** — `inReplyTo` is now a required parameter on `send_email` and
7
+ > `draft_email` (was optional). Set it to `false` for a new email, or pass a
8
+ > message ID to thread a reply. This forces the agent to make an explicit choice
9
+ > instead of silently treating replies as new conversations.
10
+ >
11
+ > **v0.7.3** — `edit_draft` now preserves the quoted thread history when editing
12
+ > Outlook reply/forward drafts. Previously, editing a draft body would overwrite
13
+ > the entire content — including the quoted thread. Now only the answer part
14
+ > (above the spacer delimiter) is replaced.
15
+ >
6
16
  > **v0.7.2** — `add_attachment_to_draft` now accepts `filePath` (absolute path to
7
17
  a local file) as an alternative to `contentBytes`. The file is read from disk and
8
18
  base64-encoded automatically, the MIME type is inferred from the extension, and
@@ -227,11 +237,11 @@ account store.
227
237
  | `archive_email` | `account`, `id` | Move a message to the Archive folder. Disabled under `--read-only`. |
228
238
  | `trash_email` | `account`, `id` | Move a message to Deleted Items (trash). Disabled under `--read-only`. |
229
239
  | `move_email` | `account`, `id`, `destination` | Move to any folder by well-known name (`inbox`, `drafts`, etc.) or custom folder ID. Disabled under `--read-only`. |
230
- | `send_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `format`, `include_signature?`, `inReplyTo?`, `replyAll?`, `forwardMessageId?` | Send an email. `format` (`"html"` or `"markdown"`) controls body format — Markdown is converted to HTML via `marked`. Appends signature when `include_signature` is true. `inReplyTo` sends as threaded reply; `forwardMessageId` sends as forward. Disabled under `--read-only`. |
231
- | `draft_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `format`, `include_signature?`, `inReplyTo?`, `replyAll?`, `forwardMessageId?` | Save as draft instead of sending. `format` (`"html"` or `"markdown"`) controls body format — Markdown is converted to HTML via `marked`. Returns the draft message ID and HTML body (`draftHtml`). Disabled under `--read-only`. |
240
+ | `send_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `format`, `include_signature`, `inReplyTo`, `replyAll?`, `forwardMessageId?` | Send an email. `format` (`"html"` or `"markdown"`) controls body format — Markdown is converted to HTML via `marked`. Appends signature when `include_signature` is true. `inReplyTo` sends as threaded reply; `forwardMessageId` sends as forward. `inReplyTo` is required — set to `false` for new emails. Disabled under `--read-only`. |
241
+ | `draft_email` | `account`, `to[]`, `cc?`, `bcc?`, `subject`, `body`, `format`, `include_signature`, `inReplyTo`, `replyAll?`, `forwardMessageId?` | Save as draft instead of sending. `format` (`"html"` or `"markdown"`) controls body format — Markdown is converted to HTML via `marked`. Returns the draft message ID and HTML body (`draftHtml`). `inReplyTo` is required — set to `false` for new emails. Disabled under `--read-only`. |
232
242
  | `edit_draft` | `account`, `id`, `to?`, `cc?`, `bcc?`, `subject?`, `body?`, `format?`, `include_signature?` | Edit an existing draft by ID. Only provided fields are updated. `format` only meaningful when `body` is provided. Returns the updated draft ID and HTML body (`draftHtml`). Disabled under `--read-only`. |
233
243
  | `send_draft` | `account`, `id` | Send an existing draft email by ID. Use with draft IDs returned by `draft_email` or `edit_draft`. Disabled under `--read-only`. |
234
- | `add_attachment_to_draft` | `account`, `id`, `name`, `contentBytes`, `contentType?` | Attach a base64-encoded file to an existing draft email by ID. Disabled under `--read-only`. |
244
+ | `add_attachment_to_draft` | `account`, `id`, `name?`, `contentBytes?`, `filePath?`, `contentType?` | Attach a file to an existing draft by ID. Provide `contentBytes` (base64) or `filePath` (absolute path — auto-encodes). Disabled under `--read-only`. |
235
245
  | `list_folders` | `account`, `parentFolderId?` | List available mail folders. Returns top-level folders by default, or children of `parentFolderId`. |
236
246
  | `create_folder` | `account`, `displayName`, `parentFolderId?` | Create a new mail folder under root (default) or the given parent. Disabled under `--read-only`. |
237
247
  | `delete_folder` | `account`, `folderId` | Delete a mail folder by ID. Disabled under `--read-only`. |
package/dist/cli.js CHANGED
@@ -2191,6 +2191,7 @@ async function updateDraft2(clients, account, id, update) {
2191
2191
  subject: update.subject ?? origSubject,
2192
2192
  body: update.body ?? "",
2193
2193
  isHtml: update.isHtml,
2194
+ inReplyTo: false,
2194
2195
  cc: existingCc.length > 0 ? existingCc : void 0,
2195
2196
  bcc: existingBcc.length > 0 ? existingBcc : void 0
2196
2197
  });
@@ -3318,8 +3319,8 @@ function registerComposeTools(server, ctx) {
3318
3319
  include_signature: z6.boolean().describe(
3319
3320
  "Whether to append the account's saved HTML signature to the email. If true, don't include a signature in the body param to avoid double signature. Returns an error if true but no signature is configured for this account."
3320
3321
  ),
3321
- inReplyTo: z6.string().optional().describe(
3322
- "Message ID to reply to. When set, sends as a threaded reply which includes the quoted thread history automatically."
3322
+ inReplyTo: z6.union([z6.string(), z6.literal(false)]).describe(
3323
+ "Message ID to reply to. When set, sends as a threaded reply which includes the quoted thread history automatically. Set to `false` for a new email (not a reply)."
3323
3324
  ),
3324
3325
  replyAll: z6.boolean().default(false).optional().describe(
3325
3326
  "When true and `inReplyTo` is set, reply to all recipients instead of just the sender."
@@ -3460,6 +3461,18 @@ function registerComposeTools(server, ctx) {
3460
3461
  bodyPayload = composed.body;
3461
3462
  isHtmlPayload = composed.isHtml;
3462
3463
  }
3464
+ if (bodyPayload !== void 0) {
3465
+ const spacer = '<div style="line-height:12px"><br></div>';
3466
+ try {
3467
+ const existing = await provider.readEmail(account, a.id);
3468
+ const existingHtml = existing.bodyHtml ?? "";
3469
+ const spacerIdx = existingHtml.indexOf(spacer);
3470
+ if (spacerIdx !== -1) {
3471
+ bodyPayload = bodyPayload + existingHtml.slice(spacerIdx);
3472
+ }
3473
+ } catch {
3474
+ }
3475
+ }
3463
3476
  const res = await provider.updateDraft(account, a.id, {
3464
3477
  to: a.to,
3465
3478
  cc: a.cc,
@@ -3616,7 +3629,7 @@ function registerTools(server, opts) {
3616
3629
  // package.json
3617
3630
  var package_default = {
3618
3631
  name: "hypermail-mcp",
3619
- version: "0.7.2",
3632
+ version: "0.7.4",
3620
3633
  description: "Unified email MCP server \u2014 operate any inbox (Outlook now, IMAP/Gmail later) by passing an email address.",
3621
3634
  type: "module",
3622
3635
  bin: {
@@ -3677,6 +3690,7 @@ var package_default = {
3677
3690
  "@types/isomorphic-fetch": "^0.0.39",
3678
3691
  "@types/node": "^22.10.2",
3679
3692
  "@types/nodemailer": "^8.0.0",
3693
+ "@types/turndown": "^5.0.6",
3680
3694
  tsup: "^8.3.5",
3681
3695
  typescript: "^5.7.2",
3682
3696
  vitest: "^2.1.8"