imapflow 2.1.1 → 2.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.2.0](https://github.com/postalsys/imapflow/compare/v2.1.2...v2.2.0) (2026-10-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * let the client choose the hash behind the fallback message id ([0eb74e1](https://github.com/postalsys/imapflow/commit/0eb74e1915b7b568ed137b69d0cfbcce0100679f))
9
+
10
+ ## [2.1.2](https://github.com/postalsys/imapflow/compare/v2.1.1...v2.1.2) (2026-09-28)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **deps:** update libmime to 5.4.6 and mailsplit to 5.4.19 ([f6afb32](https://github.com/postalsys/imapflow/commit/f6afb32cbb1df43993a1df2cbd003e013bc10fa8))
16
+
3
17
  ## [2.1.1](https://github.com/postalsys/imapflow/compare/v2.1.0...v2.1.1) (2026-09-28)
4
18
 
5
19
 
@@ -182,7 +182,7 @@ async function fetch(connection, range, query, options) {
182
182
  // (useful for large result sets). Otherwise, collect all into messages.list.
183
183
  FETCH: async (untagged) => {
184
184
  messages.count++;
185
- let formatted = await (0, tools_js_1.formatMessageResponse)(untagged, mailbox);
185
+ let formatted = await (0, tools_js_1.formatMessageResponse)(untagged, mailbox, connection.idHashAlgorithm);
186
186
  if (typeof options.onUntaggedFetch === 'function') {
187
187
  await new Promise((resolve, reject) => {
188
188
  options.onUntaggedFetch(formatted, err => {
@@ -136,6 +136,8 @@ export declare class ImapFlow extends EventEmitter {
136
136
  idling: boolean;
137
137
  /** Whether log entries are also emitted as 'log' events, see the `emitLogs` option */
138
138
  emitLogs: boolean;
139
+ /** Hash algorithm for the fallback message id, see `ImapFlowOptions.idHashAlgorithm` */
140
+ idHashAlgorithm: string;
139
141
  /** The personal namespace, from the NAMESPACE command */
140
142
  namespace: NamespaceObject | undefined;
141
143
  /** Every namespace the server reported */
@@ -285,6 +285,7 @@ class ImapFlow extends node_events_1.EventEmitter {
285
285
  this._openDownloads = 0;
286
286
  this.missingIdleCommand = (this.options.missingIdleCommand || '').toString().toUpperCase().trim() || 'NOOP';
287
287
  this.disableBinary = !!this.options.disableBinary;
288
+ this.idHashAlgorithm = this.options.idHashAlgorithm || 'md5';
288
289
  this.skipListSubscribedArg = false;
289
290
  this.skipListStatusArgs = false;
290
291
  this.skipListAuxArgs = false;
@@ -1809,7 +1810,7 @@ class ImapFlow extends node_events_1.EventEmitter {
1809
1810
  // mailbox closed, ignore
1810
1811
  return;
1811
1812
  }
1812
- let message = await (0, tools_js_1.formatMessageResponse)(untagged, mailbox);
1813
+ let message = await (0, tools_js_1.formatMessageResponse)(untagged, mailbox, this.idHashAlgorithm);
1813
1814
  if (message.flags) {
1814
1815
  let updateEvent = {
1815
1816
  path: mailbox.path,
@@ -1,3 +1,3 @@
1
1
  export declare const name = "imapflow";
2
- export declare const version = "2.1.1";
2
+ export declare const version = "2.2.0";
3
3
  export declare const homepage = "https://imapflow.com/";
@@ -3,5 +3,5 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.homepage = exports.version = exports.name = void 0;
5
5
  exports.name = "imapflow";
6
- exports.version = "2.1.1";
6
+ exports.version = "2.2.0";
7
7
  exports.homepage = "https://imapflow.com/";
@@ -284,9 +284,10 @@ export declare function getColorFlags(color: string | null | undefined): {
284
284
  *
285
285
  * @param untagged - Parsed untagged IMAP response
286
286
  * @param mailbox - Current mailbox state object
287
+ * @param idHashAlgorithm - Hash for the fallback message id, `md5` unless the client was told otherwise
287
288
  * @returns Formatted message object with properties like seq, uid, flags, envelope, etc.
288
289
  */
289
- export declare function formatMessageResponse(untagged: ImapResponse, mailbox: MailboxObject): Promise<FetchMessageObject>;
290
+ export declare function formatMessageResponse(untagged: ImapResponse, mailbox: MailboxObject, idHashAlgorithm?: string): Promise<FetchMessageObject>;
290
291
  /**
291
292
  * Strips surrounding double quotes from a name string.
292
293
  *
package/dist/cjs/tools.js CHANGED
@@ -700,9 +700,10 @@ function getColorFlags(color) {
700
700
  *
701
701
  * @param untagged - Parsed untagged IMAP response
702
702
  * @param mailbox - Current mailbox state object
703
+ * @param idHashAlgorithm - Hash for the fallback message id, `md5` unless the client was told otherwise
703
704
  * @returns Formatted message object with properties like seq, uid, flags, envelope, etc.
704
705
  */
705
- async function formatMessageResponse(untagged, mailbox) {
706
+ async function formatMessageResponse(untagged, mailbox, idHashAlgorithm) {
706
707
  let map = {};
707
708
  // The sequence number indexes into mailbox state, so an unusable one is dropped rather
708
709
  // than coerced to NaN or Infinity
@@ -884,13 +885,14 @@ async function formatMessageResponse(untagged, mailbox) {
884
885
  // ignore
885
886
  }
886
887
  }
887
- // Non-cryptographic identifier: MD5 is used only to derive a stable, compact
888
- // account-unique id from non-secret data (path:uidValidity:uid). No security
889
- // property (collision/preimage resistance, secrecy) is relied upon, so a fast
890
- // hash is the appropriate choice here - not a security-sensitive use.
888
+ // Non-cryptographic identifier: the hash only derives a stable, compact account-unique
889
+ // id from non-secret data (path:uidValidity:uid). No security property (collision or
890
+ // preimage resistance, secrecy) is relied upon, so the fast default is MD5; a host whose
891
+ // OpenSSL runs in FIPS mode has no MD5 and names another algorithm through the client
892
+ // option, at the price of ids that differ from the default ones
891
893
  map.id =
892
894
  map.emailId ||
893
- (0, node_crypto_1.createHash)('md5')
895
+ (0, node_crypto_1.createHash)(idHashAlgorithm || 'md5')
894
896
  .update([path, mailbox.uidValidity?.toString() || '', map.uid.toString()].join(':'))
895
897
  .digest('hex');
896
898
  }
@@ -44,6 +44,14 @@ export interface ImapFlowOptions {
44
44
  clientInfo?: IdInfoObject | undefined;
45
45
  /** If true, then do not start IDLE when connection is established */
46
46
  disableAutoIdle?: boolean | undefined;
47
+ /**
48
+ * Hash algorithm (any name Node's crypto supports) for the fallback message `id` that is
49
+ * derived from the mailbox path, UIDVALIDITY and UID when the server provides no email id
50
+ * through OBJECTID or X-GM-EXT-1. Defaults to `'md5'`, which keeps the ids earlier releases
51
+ * produced. A host whose OpenSSL runs in FIPS mode does not offer MD5, and has to set a
52
+ * different one, for example `'sha256'`, which yields a 64 character hex id
53
+ */
54
+ idHashAlgorithm?: string | undefined;
47
55
  /**
48
56
  * How long (in ms) the connection has to be inactive before IDLE is started automatically.
49
57
  * Keep it above the pause your own code usually leaves between two commands, otherwise every
@@ -179,7 +179,7 @@ export default async function fetch(connection, range, query, options) {
179
179
  // (useful for large result sets). Otherwise, collect all into messages.list.
180
180
  FETCH: async (untagged) => {
181
181
  messages.count++;
182
- let formatted = await formatMessageResponse(untagged, mailbox);
182
+ let formatted = await formatMessageResponse(untagged, mailbox, connection.idHashAlgorithm);
183
183
  if (typeof options.onUntaggedFetch === 'function') {
184
184
  await new Promise((resolve, reject) => {
185
185
  options.onUntaggedFetch(formatted, err => {
@@ -136,6 +136,8 @@ export declare class ImapFlow extends EventEmitter {
136
136
  idling: boolean;
137
137
  /** Whether log entries are also emitted as 'log' events, see the `emitLogs` option */
138
138
  emitLogs: boolean;
139
+ /** Hash algorithm for the fallback message id, see `ImapFlowOptions.idHashAlgorithm` */
140
+ idHashAlgorithm: string;
139
141
  /** The personal namespace, from the NAMESPACE command */
140
142
  namespace: NamespaceObject | undefined;
141
143
  /** Every namespace the server reported */
@@ -244,6 +244,7 @@ export class ImapFlow extends EventEmitter {
244
244
  this._openDownloads = 0;
245
245
  this.missingIdleCommand = (this.options.missingIdleCommand || '').toString().toUpperCase().trim() || 'NOOP';
246
246
  this.disableBinary = !!this.options.disableBinary;
247
+ this.idHashAlgorithm = this.options.idHashAlgorithm || 'md5';
247
248
  this.skipListSubscribedArg = false;
248
249
  this.skipListStatusArgs = false;
249
250
  this.skipListAuxArgs = false;
@@ -1768,7 +1769,7 @@ export class ImapFlow extends EventEmitter {
1768
1769
  // mailbox closed, ignore
1769
1770
  return;
1770
1771
  }
1771
- let message = await formatMessageResponse(untagged, mailbox);
1772
+ let message = await formatMessageResponse(untagged, mailbox, this.idHashAlgorithm);
1772
1773
  if (message.flags) {
1773
1774
  let updateEvent = {
1774
1775
  path: mailbox.path,
@@ -1,3 +1,3 @@
1
1
  export declare const name = "imapflow";
2
- export declare const version = "2.1.1";
2
+ export declare const version = "2.2.0";
3
3
  export declare const homepage = "https://imapflow.com/";
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/build.js from package.json. Do not edit by hand.
2
2
  export const name = "imapflow";
3
- export const version = "2.1.1";
3
+ export const version = "2.2.0";
4
4
  export const homepage = "https://imapflow.com/";
@@ -284,9 +284,10 @@ export declare function getColorFlags(color: string | null | undefined): {
284
284
  *
285
285
  * @param untagged - Parsed untagged IMAP response
286
286
  * @param mailbox - Current mailbox state object
287
+ * @param idHashAlgorithm - Hash for the fallback message id, `md5` unless the client was told otherwise
287
288
  * @returns Formatted message object with properties like seq, uid, flags, envelope, etc.
288
289
  */
289
- export declare function formatMessageResponse(untagged: ImapResponse, mailbox: MailboxObject): Promise<FetchMessageObject>;
290
+ export declare function formatMessageResponse(untagged: ImapResponse, mailbox: MailboxObject, idHashAlgorithm?: string): Promise<FetchMessageObject>;
290
291
  /**
291
292
  * Strips surrounding double quotes from a name string.
292
293
  *
package/dist/esm/tools.js CHANGED
@@ -645,9 +645,10 @@ export function getColorFlags(color) {
645
645
  *
646
646
  * @param untagged - Parsed untagged IMAP response
647
647
  * @param mailbox - Current mailbox state object
648
+ * @param idHashAlgorithm - Hash for the fallback message id, `md5` unless the client was told otherwise
648
649
  * @returns Formatted message object with properties like seq, uid, flags, envelope, etc.
649
650
  */
650
- export async function formatMessageResponse(untagged, mailbox) {
651
+ export async function formatMessageResponse(untagged, mailbox, idHashAlgorithm) {
651
652
  let map = {};
652
653
  // The sequence number indexes into mailbox state, so an unusable one is dropped rather
653
654
  // than coerced to NaN or Infinity
@@ -829,13 +830,14 @@ export async function formatMessageResponse(untagged, mailbox) {
829
830
  // ignore
830
831
  }
831
832
  }
832
- // Non-cryptographic identifier: MD5 is used only to derive a stable, compact
833
- // account-unique id from non-secret data (path:uidValidity:uid). No security
834
- // property (collision/preimage resistance, secrecy) is relied upon, so a fast
835
- // hash is the appropriate choice here - not a security-sensitive use.
833
+ // Non-cryptographic identifier: the hash only derives a stable, compact account-unique
834
+ // id from non-secret data (path:uidValidity:uid). No security property (collision or
835
+ // preimage resistance, secrecy) is relied upon, so the fast default is MD5; a host whose
836
+ // OpenSSL runs in FIPS mode has no MD5 and names another algorithm through the client
837
+ // option, at the price of ids that differ from the default ones
836
838
  map.id =
837
839
  map.emailId ||
838
- createHash('md5')
840
+ createHash(idHashAlgorithm || 'md5')
839
841
  .update([path, mailbox.uidValidity?.toString() || '', map.uid.toString()].join(':'))
840
842
  .digest('hex');
841
843
  }
@@ -44,6 +44,14 @@ export interface ImapFlowOptions {
44
44
  clientInfo?: IdInfoObject | undefined;
45
45
  /** If true, then do not start IDLE when connection is established */
46
46
  disableAutoIdle?: boolean | undefined;
47
+ /**
48
+ * Hash algorithm (any name Node's crypto supports) for the fallback message `id` that is
49
+ * derived from the mailbox path, UIDVALIDITY and UID when the server provides no email id
50
+ * through OBJECTID or X-GM-EXT-1. Defaults to `'md5'`, which keeps the ids earlier releases
51
+ * produced. A host whose OpenSSL runs in FIPS mode does not offer MD5, and has to set a
52
+ * different one, for example `'sha256'`, which yields a 64 character hex id
53
+ */
54
+ idHashAlgorithm?: string | undefined;
47
55
  /**
48
56
  * How long (in ms) the connection has to be inactive before IDLE is started automatically.
49
57
  * Keep it above the pause your own code usually leaves between two commands, otherwise every
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imapflow",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "IMAP Client for Node",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/imap-flow.js",
@@ -81,12 +81,12 @@
81
81
  "wrangler": "4.142.0"
82
82
  },
83
83
  "dependencies": {
84
- "@zone-eu/mailsplit": "5.4.18",
84
+ "@zone-eu/mailsplit": "5.4.19",
85
85
  "encoding-japanese": "2.4.0",
86
86
  "iconv-lite": "0.7.3",
87
- "libbase64": "1.3.0",
88
- "libmime": "5.4.5",
89
- "libqp": "2.1.1",
87
+ "libbase64": "1.3.1",
88
+ "libmime": "5.4.6",
89
+ "libqp": "2.1.2",
90
90
  "pino": "10.3.1",
91
91
  "socks": "2.8.10"
92
92
  },