proton-mail-bridge-client 1.19.5 → 2.0.1

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
@@ -12,7 +12,7 @@
12
12
  [![npm version](https://img.shields.io/npm/v/proton-mail-bridge-client?color=%236d4aff&label=npm)](https://www.npmjs.com/package/proton-mail-bridge-client)
13
13
  [![CI](https://github.com/googlarz/proton-mail-bridge-client/actions/workflows/ci.yml/badge.svg)](https://github.com/googlarz/proton-mail-bridge-client/actions/workflows/ci.yml)
14
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
15
- [![Node.js 18+](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
15
+ [![Node.js 20+](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
16
16
  [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
17
17
  [![MCP](https://img.shields.io/badge/MCP-compatible-blueviolet)](https://modelcontextprotocol.io)
18
18
  [![GitHub stars](https://img.shields.io/github/stars/googlarz/proton-mail-bridge-client?style=social)](https://github.com/googlarz/proton-mail-bridge-client)
@@ -26,6 +26,8 @@
26
26
 
27
27
  Give Claude Desktop (or Cline, or any MCP client) full access to your Proton Mail inbox: read, search, send, draft, triage threads, manage folders, save attachments, and more — 95 MCP tools in total. Most of the same capabilities are also available as a full CLI for scripting, cron, and piped automation — no Claude required.
28
28
 
29
+ > **Battle-tested at scale (v2.0.0):** full mailbox backfill validated end-to-end against a real account with 57,000+ indexed messages across 62 folders/labels — including a 22,800-message Archive folder backfilled from scratch, UID-window by UID-window, with zero data loss across restarts, transient IMAP disconnects, and connection timeouts.
30
+
29
31
  ## What you get
30
32
 
31
33
  - **Claude reads and manages your Proton Mail** — triage, reply, draft, archive, search, move, batch-act on threads, pull attachments
@@ -53,7 +55,7 @@ Download: [proton.me/mail/bridge](https://proton.me/mail/bridge)
53
55
 
54
56
  > **Bridge password vs Proton password:** Proton Bridge generates a separate local password that is *not* your Proton account password. Find it inside the Bridge app under **Account → Copy password** (or similar — exact label varies by Bridge version). You'll need this for setup.
55
57
 
56
- **2. Node.js 18 or later** — `node --version` to check.
58
+ **2. Node.js 20 or later** — `node --version` to check.
57
59
 
58
60
  **3. Your Bridge credentials** — from the Bridge app:
59
61
  - IMAP host/port (default: `127.0.0.1:1143`)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAA2H,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/L,OAAO,EAAkB,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAUV,WAAW,EAEX,gBAAgB,EAEjB,MAAM,kBAAkB,CAAC;AA0qD1B,eAAO,MAAM,eAAe,aAyB1B,CAAC;AAgGH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAmED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3G;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAI1G;AASD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa9E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7F;AA4KD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CAyBhC;AA4wBD,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkGrD;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAg2FP;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE1C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAA2H,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/L,OAAO,EAAkB,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAUV,WAAW,EAEX,gBAAgB,EAEjB,MAAM,kBAAkB,CAAC;AA0qD1B,eAAO,MAAM,eAAe,aAyB1B,CAAC;AAgGH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAmED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3G;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAI1G;AASD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa9E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7F;AA4KD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CAyBhC;AA4wBD,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkGrD;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAk5FP;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE1C"}
package/dist/index.js CHANGED
@@ -4002,7 +4002,7 @@ export function createServer(config, options = {}) {
4002
4002
  return createTextResult(result);
4003
4003
  }
4004
4004
  case "bulk_move": {
4005
- ensureMailboxWriteAllowed(config.runtime);
4005
+ ensureEmailActionAllowed(config.runtime, "move");
4006
4006
  const emailIds = Array.isArray(args.emailIds)
4007
4007
  ? args.emailIds.map(String) : undefined;
4008
4008
  const match = args.match && typeof args.match === "object"
@@ -4230,7 +4230,7 @@ export function createServer(config, options = {}) {
4230
4230
  return createTextResult(await withAudit(auditService, name, args, async () => imapService.starEmail(requireString(args, "emailId"), normalizeBoolean(args.isStarred, true))));
4231
4231
  case "move_email":
4232
4232
  {
4233
- ensureMailboxWriteAllowed(config.runtime);
4233
+ ensureEmailActionAllowed(config.runtime, "move");
4234
4234
  const emailId = requireString(args, "emailId");
4235
4235
  const targetFolder = requireString(args, "targetFolder");
4236
4236
  const result = await withAudit(auditService, name, args, async () => {
@@ -4379,6 +4379,9 @@ export function createServer(config, options = {}) {
4379
4379
  }
4380
4380
  const action = requireEmailAction(args);
4381
4381
  ensureEmailActionAllowed(config.runtime, action);
4382
+ if (action === "delete") {
4383
+ ensureDestructiveConfirmed(config.runtime, normalizeBoolean(args.confirmed, false), `Permanently delete ${emailIds.length} email(s) (cannot be recovered)`);
4384
+ }
4382
4385
  const result = await withAudit(auditService, name, args, async () => applyBatchEmailAction(imapService, [], {
4383
4386
  emailIds,
4384
4387
  action,
@@ -4625,6 +4628,47 @@ export function createServer(config, options = {}) {
4625
4628
  }));
4626
4629
  case "sync_emails":
4627
4630
  {
4631
+ const folder = optionalString(args, "folder");
4632
+ const full = typeof args.full === "boolean" ? args.full : undefined;
4633
+ const limitPerFolder = typeof args.limitPerFolder === "number" ? args.limitPerFolder : undefined;
4634
+ const includeAttachmentText = typeof args.includeAttachmentText === "boolean" ? args.includeAttachmentText : undefined;
4635
+ // backgroundSyncService.runNow() always runs the *fixed* background-
4636
+ // sync config (autoSyncFolder/autoSyncFull/autoSyncLimitPerFolder —
4637
+ // typically just "INBOX,Sent", incremental, 100/folder) and ignores
4638
+ // any argument entirely. This tool's own schema advertises folder/
4639
+ // full/limitPerFolder/includeAttachmentText as per-call overrides,
4640
+ // but every one of them was silently discarded — a caller asking to
4641
+ // sync "Archive" with full:true got back a status snapshot of the
4642
+ // last INBOX/Sent background run, with Archive never touched at
4643
+ // all. Found live: sync_emails({folder:"Archive", full:true}) did
4644
+ // not add an Archive entry to get_index_status's syncCheckpoints.
4645
+ // When the caller supplies any of these, run a one-off sync with
4646
+ // their actual parameters instead.
4647
+ if (folder !== undefined || full !== undefined || limitPerFolder !== undefined || includeAttachmentText !== undefined) {
4648
+ const snapshot = await imapService.collectEmailsForIndex({
4649
+ folder,
4650
+ full,
4651
+ limitPerFolder,
4652
+ includeAttachmentText,
4653
+ checkpoints: await localIndexService.getSyncCheckpointMap(),
4654
+ });
4655
+ const indexStatus = await localIndexService.recordSnapshot({
4656
+ folders: snapshot.folders,
4657
+ emails: snapshot.emails,
4658
+ syncedAt: snapshot.syncedAt,
4659
+ folderStats: snapshot.folderStats,
4660
+ });
4661
+ return createTextResult({
4662
+ checkedAt: new Date().toISOString(),
4663
+ synced: { folder: folder ?? "all", full: Boolean(full), folderStats: snapshot.folderStats },
4664
+ index: {
4665
+ updatedAt: indexStatus.updatedAt,
4666
+ storedMessageCount: indexStatus.storedMessageCount,
4667
+ dedupedMessageCount: indexStatus.dedupedMessageCount,
4668
+ path: indexStatus.path,
4669
+ },
4670
+ });
4671
+ }
4628
4672
  const syncStatus = await backgroundSyncService.runNow("sync_emails");
4629
4673
  const indexStatus = await localIndexService.getStatus();
4630
4674
  return createTextResult({
@@ -4915,6 +4959,9 @@ export function createServer(config, options = {}) {
4915
4959
  const emailIds = [...new Set(thread.messages
4916
4960
  .filter((message) => !unreadOnly || !message.isRead)
4917
4961
  .map((message) => message.primaryEmailId))];
4962
+ if (action === "delete") {
4963
+ ensureDestructiveConfirmed(config.runtime, normalizeBoolean(args.confirmed, false), `Permanently delete ${emailIds.length} email(s) in thread (cannot be recovered)`);
4964
+ }
4918
4965
  const result = await withAudit(auditService, name, args, async () => applyBatchEmailAction(imapService, [], {
4919
4966
  emailIds,
4920
4967
  action,