imapflow 1.0.148 → 1.0.150

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.
@@ -0,0 +1,24 @@
1
+ name: 'Close stale issues and PRs'
2
+ on:
3
+ schedule:
4
+ - cron: '30 1 * * *'
5
+
6
+ jobs:
7
+ stale:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/stale@v8
11
+ with:
12
+ stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
13
+ stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.'
14
+ close-issue-message: 'This issue was closed because it has been stalled for 15 days with no activity.'
15
+ close-pr-message: 'This PR was closed because it has been stalled for 20 days with no activity.'
16
+ days-before-issue-stale: 30
17
+ days-before-pr-stale: 45
18
+ days-before-issue-close: 15
19
+ days-before-pr-close: 20
20
+ stale-issue-label: 'no-issue-activity'
21
+ exempt-issue-labels: 'pending,work-in-progress'
22
+ stale-pr-label: 'no-pr-activity'
23
+ exempt-pr-labels: 'awaiting-approval,work-in-progress'
24
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.150](https://github.com/postalsys/imapflow/compare/v1.0.149...v1.0.150) (2024-02-01)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **deps:** Bumped Nodemailer version ([ee02764](https://github.com/postalsys/imapflow/commit/ee0276493494ecf08be557cc0c486fe309d359bf))
9
+
10
+ ## [1.0.149](https://github.com/postalsys/imapflow/compare/v1.0.148...v1.0.149) (2024-01-31)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **flag-colors:** added a method to set Flag Color. The color is also included in the Fetch response structure ([d840951](https://github.com/postalsys/imapflow/commit/d8409513075b864e9131665af3f1670a0714d05c))
16
+
3
17
  ## [1.0.148](https://github.com/postalsys/imapflow/compare/v1.0.147...v1.0.148) (2024-01-16)
4
18
 
5
19
 
package/lib/imap-flow.js CHANGED
@@ -29,7 +29,17 @@ const { PassThrough } = require('stream');
29
29
 
30
30
  const { proxyConnection } = require('./proxy-connection');
31
31
 
32
- const { comparePaths, updateCapabilities, getFolderTree, formatMessageResponse, getDecoder, packMessageRange, normalizePath, expandRange } = require('./tools');
32
+ const {
33
+ comparePaths,
34
+ updateCapabilities,
35
+ getFolderTree,
36
+ formatMessageResponse,
37
+ getDecoder,
38
+ packMessageRange,
39
+ normalizePath,
40
+ expandRange,
41
+ getColorFlags
42
+ } = require('./tools');
33
43
 
34
44
  const imapCommands = require('./imap-commands.js');
35
45
 
@@ -1177,6 +1187,10 @@ class ImapFlow extends EventEmitter {
1177
1187
 
1178
1188
  updateEvent.flags = message.flags;
1179
1189
 
1190
+ if (message.flagColor) {
1191
+ updateEvent.flagColor = message.flagColor;
1192
+ }
1193
+
1180
1194
  this.emit('flags', updateEvent);
1181
1195
  }
1182
1196
  }
@@ -1926,6 +1940,68 @@ class ImapFlow extends EventEmitter {
1926
1940
  return await this.run('STORE', range, flags, queryOpts);
1927
1941
  }
1928
1942
 
1943
+ /**
1944
+ * Sets a colored flag for an email. Only supported by mail clients like Apple Mail
1945
+ *
1946
+ * @param {SequenceString | Number[] | SearchObject} range Range to filter the messages
1947
+ * @param {string} The color to set. One of 'red', 'orange', 'yellow', 'green', 'blue', 'purple', and 'grey'
1948
+ * @param {Object} [options]
1949
+ * @param {Boolean} [options.uid] If `true` then uses UID {@link SequenceString} instead of sequence numbers
1950
+ * @param {BigInt} [options.unchangedSince] If set then only messages with a lower or equal `modseq` value are updated. Ignored if server does not support `CONDSTORE` extension.
1951
+ * @returns {Promise<Boolean>} Did the operation succeed or not
1952
+ *
1953
+ * @example
1954
+ * let mailbox = await client.mailboxOpen('INBOX');
1955
+ * // add a purple flag for all emails
1956
+ * await client.setFlagColor('1:*', 'Purple');
1957
+ */
1958
+ async setFlagColor(range, color, options) {
1959
+ options = options || {};
1960
+
1961
+ range = await this.resolveRange(range, options);
1962
+ if (!range) {
1963
+ return false;
1964
+ }
1965
+
1966
+ let flagChanges = getColorFlags(color);
1967
+ if (!flagChanges) {
1968
+ return false;
1969
+ }
1970
+
1971
+ let addResults;
1972
+ let removeResults;
1973
+
1974
+ if (flagChanges.add && flagChanges.add.length) {
1975
+ let queryOpts = Object.assign(
1976
+ {
1977
+ operation: 'add'
1978
+ },
1979
+ options,
1980
+ {
1981
+ useLabels: false, // override if set
1982
+ // prevent triggering a premature Flags change notification
1983
+ silent: flagChanges.remove && flagChanges.remove.length
1984
+ }
1985
+ );
1986
+
1987
+ addResults = await this.run('STORE', range, flagChanges.add, queryOpts);
1988
+ }
1989
+
1990
+ if (flagChanges.remove && flagChanges.remove.length) {
1991
+ let queryOpts = Object.assign(
1992
+ {
1993
+ operation: 'remove'
1994
+ },
1995
+ options,
1996
+ { useLabels: false } // override if set
1997
+ );
1998
+
1999
+ removeResults = await this.run('STORE', range, flagChanges.remove, queryOpts);
2000
+ }
2001
+
2002
+ return addResults || removeResults || false;
2003
+ }
2004
+
1929
2005
  /**
1930
2006
  * Delete messages from currently opened mailbox. Method does not indicate info about deleted messages,
1931
2007
  * instead you should be using {@link ImapFlow#expunge} event for this
@@ -2077,7 +2153,7 @@ class ImapFlow extends EventEmitter {
2077
2153
  * @typedef {Object} FetchQueryObject
2078
2154
  * @global
2079
2155
  * @property {Boolean} [uid] if `true` then include UID in the response
2080
- * @property {Boolean} [flags] if `true` then include flags Set in the response
2156
+ * @property {Boolean} [flags] if `true` then include flags Set in the response. Also adds `flagColor` to the response if the message is flagged.
2081
2157
  * @property {Boolean} [bodyStructure] if `true` then include parsed BODYSTRUCTURE object in the response
2082
2158
  * @property {Boolean} [envelope] if `true` then include parsed ENVELOPE object in the response
2083
2159
  * @property {Boolean} [internalDate] if `true` then include internal date value in the response
@@ -2148,6 +2224,7 @@ class ImapFlow extends EventEmitter {
2148
2224
  * @property {Set<string>} [labels] a Set of labels. Only present if server supports `X-GM-EXT-1` extension
2149
2225
  * @property {Number} [size] message size
2150
2226
  * @property {Set<string>} [flags] a set of message flags
2227
+ * @property {String} [flagColor] flag color like "red", or "yellow". This value is derived from the `flags` Set and it uses the same color rules as Apple Mail
2151
2228
  * @property {MessageEnvelopeObject} [envelope] message envelope
2152
2229
  * @property {MessageStructureObject} [bodyStructure] message body structure
2153
2230
  * @property {Date} [internalDate] message internal date
@@ -2171,6 +2248,8 @@ class ImapFlow extends EventEmitter {
2171
2248
  * // fetch UID for all messages in a mailbox
2172
2249
  * for await (let msg of client.fetch('1:*', {uid: true})){
2173
2250
  * console.log(msg.uid);
2251
+ * // NB! You can not run any IMAP commands in this loop
2252
+ * // otherwise you will end up in a deadloop
2174
2253
  * }
2175
2254
  */
2176
2255
  async *fetch(range, query, options) {
package/lib/tools.js CHANGED
@@ -8,6 +8,8 @@ const { createHash } = require('crypto');
8
8
  const { JPDecoder } = require('./jp-decoder');
9
9
  const iconv = require('iconv-lite');
10
10
 
11
+ const FLAG_COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'grey'];
12
+
11
13
  module.exports = {
12
14
  encodePath(connection, path) {
13
15
  path = (path || '').toString();
@@ -191,6 +193,43 @@ module.exports = {
191
193
  return tree;
192
194
  },
193
195
 
196
+ getFlagColor(flags) {
197
+ if (!flags.has('\\Flagged')) {
198
+ return null;
199
+ }
200
+
201
+ const bit0 = flags.has('$MailFlagBit0') ? 1 : 0;
202
+ const bit1 = flags.has('$MailFlagBit1') ? 2 : 0;
203
+ const bit2 = flags.has('$MailFlagBit2') ? 4 : 0;
204
+
205
+ const color = bit0 | bit1 | bit2; // eslint-disable-line no-bitwise
206
+
207
+ return FLAG_COLORS[color] || 'red'; // default to red for the unused \b111
208
+ },
209
+
210
+ getColorFlags(color) {
211
+ const colorCode = color ? FLAG_COLORS.indexOf((color || '').toString().toLowerCase().trim()) : null;
212
+ if (colorCode < 0 && colorCode !== null) {
213
+ return null;
214
+ }
215
+
216
+ const bits = [];
217
+ bits[0] = colorCode & 1; // eslint-disable-line no-bitwise
218
+ bits[1] = colorCode & 2; // eslint-disable-line no-bitwise
219
+ bits[2] = colorCode & 4; // eslint-disable-line no-bitwise
220
+
221
+ let result = { add: colorCode ? ['\\Flagged'] : [], remove: colorCode ? [] : ['\\Flagged'] };
222
+
223
+ for (let i = 0; i < bits.length; i++) {
224
+ if (bits[i]) {
225
+ result.add.push(`$MailFlagBit${i}`);
226
+ } else {
227
+ result.remove.push(`$MailFlagBit${i}`);
228
+ }
229
+ }
230
+ return result;
231
+ },
232
+
194
233
  async formatMessageResponse(untagged, mailbox) {
195
234
  let map = {};
196
235
 
@@ -351,6 +390,13 @@ module.exports = {
351
390
  map.id = map.emailId || createHash('md5').update([path, mailbox.uidValidity.toString(), map.uid.toString()].join(':')).digest('hex');
352
391
  }
353
392
 
393
+ if (map.flags) {
394
+ let flagColor = module.exports.getFlagColor(map.flags);
395
+ if (flagColor) {
396
+ map.flagColor = flagColor;
397
+ }
398
+ }
399
+
354
400
  return map;
355
401
  },
356
402
 
package/lib/types.d.ts CHANGED
@@ -364,6 +364,22 @@ declare module "imapflow" {
364
364
  unchangedSince?: bigint;
365
365
  useLabels?: boolean;
366
366
  }): Promise<Boolean>;
367
+ /**
368
+ * Sets a colored flag for an email. Only supported by mail clients like Apple Mail
369
+ * @example
370
+ * let mailbox = await client.mailboxOpen('INBOX');
371
+ * // add a purple flag for all emails
372
+ * await client.setFlagColor('1:*', 'Purple');
373
+ * @param range - Range to filter the messages
374
+ * @param The - color to set. One of 'red', 'orange', 'yellow', 'green', 'blue', 'purple', and 'grey'
375
+ * @param [options.uid] - If `true` then uses UID {@link SequenceString} instead of sequence numbers
376
+ * @param [options.unchangedSince] - If set then only messages with a lower or equal `modseq` value are updated. Ignored if server does not support `CONDSTORE` extension.
377
+ * @returns Did the operation succeed or not
378
+ */
379
+ setFlagColor(range: SequenceString | Number[] | SearchObject, The: string, options?: {
380
+ uid?: boolean;
381
+ unchangedSince?: bigint;
382
+ }): Promise<Boolean>;
367
383
  /**
368
384
  * Delete messages from currently opened mailbox. Method does not indicate info about deleted messages,
369
385
  * instead you should be using {@link ImapFlow#expunge} event for this
@@ -447,6 +463,8 @@ declare module "imapflow" {
447
463
  * // fetch UID for all messages in a mailbox
448
464
  * for await (let msg of client.fetch('1:*', {uid: true})){
449
465
  * console.log(msg.uid);
466
+ * // NB! You can not run any IMAP commands in this loop
467
+ * // otherwise you will end up in a deadloop
450
468
  * }
451
469
  * @param range - Range of messages to fetch
452
470
  * @param query - Fetch query
@@ -832,7 +850,7 @@ declare type CopyResponseObject = {
832
850
 
833
851
  /**
834
852
  * @property [uid] - if `true` then include UID in the response
835
- * @property [flags] - if `true` then include flags Set in the response
853
+ * @property [flags] - if `true` then include flags Set in the response. Also adds `flagColor` to the response if the message is flagged.
836
854
  * @property [bodyStructure] - if `true` then include parsed BODYSTRUCTURE object in the response
837
855
  * @property [envelope] - if `true` then include parsed ENVELOPE object in the response
838
856
  * @property [internalDate] - if `true` then include internal date value in the response
@@ -935,6 +953,7 @@ declare type MessageStructureObject = {
935
953
  * @property [labels] - a Set of labels. Only present if server supports `X-GM-EXT-1` extension
936
954
  * @property [size] - message size
937
955
  * @property [flags] - a set of message flags
956
+ * @property [flagColor] - flag color like "red", or "yellow". This value is derived from the `flags` Set and it uses the same color rules as Apple Mail
938
957
  * @property [envelope] - message envelope
939
958
  * @property [bodyStructure] - message body structure
940
959
  * @property [internalDate] - message internal date
@@ -951,6 +970,7 @@ declare type FetchMessageObject = {
951
970
  labels?: Set<string>;
952
971
  size?: number;
953
972
  flags?: Set<string>;
973
+ flagColor?: string;
954
974
  envelope?: MessageEnvelopeObject;
955
975
  bodyStructure?: MessageStructureObject;
956
976
  internalDate?: Date;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imapflow",
3
- "version": "1.0.148",
3
+ "version": "1.0.150",
4
4
  "description": "IMAP Client for Node",
5
5
  "main": "./lib/imap-flow.js",
6
6
  "scripts": {
@@ -28,14 +28,14 @@
28
28
  },
29
29
  "homepage": "https://imapflow.com/",
30
30
  "devDependencies": {
31
- "@babel/eslint-parser": "7.22.15",
32
- "@babel/eslint-plugin": "7.22.10",
31
+ "@babel/eslint-parser": "7.23.10",
32
+ "@babel/eslint-plugin": "7.23.5",
33
33
  "@babel/plugin-syntax-class-properties": "7.12.13",
34
- "@babel/preset-env": "7.23.2",
35
- "@types/node": "20.8.10",
36
- "eslint": "8.52.0",
34
+ "@babel/preset-env": "7.23.9",
35
+ "@types/node": "20.11.15",
36
+ "eslint": "8.56.0",
37
37
  "eslint-config-nodemailer": "1.2.0",
38
- "eslint-config-prettier": "9.0.0",
38
+ "eslint-config-prettier": "9.1.0",
39
39
  "grunt": "1.6.1",
40
40
  "grunt-cli": "1.4.3",
41
41
  "grunt-contrib-nodeunit": "5.0.0",
@@ -52,8 +52,8 @@
52
52
  "libmime": "5.2.1",
53
53
  "libqp": "2.0.1",
54
54
  "mailsplit": "5.4.0",
55
- "nodemailer": "6.9.7",
56
- "pino": "8.16.1",
55
+ "nodemailer": "6.9.9",
56
+ "pino": "8.17.2",
57
57
  "socks": "2.7.1"
58
58
  }
59
59
  }