imapflow 1.0.107 → 1.0.109
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 +4 -0
- package/lib/commands/namespace.js +0 -25
- package/lib/imap-flow.js +131 -0
- package/lib/types.d.ts +16 -0
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -81,31 +81,6 @@ async function getListPrefix(connection) {
|
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
83
|
response.next();
|
|
84
|
-
if (map.flags.has('\\Noselect') && map.delimiter) {
|
|
85
|
-
// can not use root namespace
|
|
86
|
-
let inboxEntry = {};
|
|
87
|
-
response = await connection.exec('LIST', ['INBOX', ''], {
|
|
88
|
-
untagged: {
|
|
89
|
-
LIST: async untagged => {
|
|
90
|
-
if (!untagged.attributes || !untagged.attributes.length) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
inboxEntry.flags = new Set(untagged.attributes[0].map(entry => entry.value));
|
|
95
|
-
inboxEntry.delimiter = untagged.attributes[1] && untagged.attributes[1].value;
|
|
96
|
-
inboxEntry.prefix = (untagged.attributes[2] && untagged.attributes[2].value) || '';
|
|
97
|
-
|
|
98
|
-
if (inboxEntry.delimiter && inboxEntry.prefix.charAt(0) === inboxEntry.delimiter) {
|
|
99
|
-
inboxEntry.prefix = inboxEntry.prefix.slice(1);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
response.next();
|
|
105
|
-
if (inboxEntry) {
|
|
106
|
-
return inboxEntry;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
84
|
return map;
|
|
110
85
|
} catch (err) {
|
|
111
86
|
connection.log.warn({ err, cid: connection.id });
|
package/lib/imap-flow.js
CHANGED
|
@@ -2451,6 +2451,137 @@ class ImapFlow extends EventEmitter {
|
|
|
2451
2451
|
};
|
|
2452
2452
|
}
|
|
2453
2453
|
|
|
2454
|
+
/**
|
|
2455
|
+
* Fetch multiple attachments as Buffer values
|
|
2456
|
+
*
|
|
2457
|
+
* @param {SequenceString} range UID or sequence number for the message to fetch
|
|
2458
|
+
* @param {String} parts A list of bodystructure parts
|
|
2459
|
+
* @param {Object} [options]
|
|
2460
|
+
* @param {Boolean} [options.uid] If `true` then uses UID number instead of sequence number for `range`
|
|
2461
|
+
* @returns {Promise<Object>} Download data object
|
|
2462
|
+
*
|
|
2463
|
+
* @example
|
|
2464
|
+
* let mailbox = await client.mailboxOpen('INBOX');
|
|
2465
|
+
* // download body part nr '1.2' from latest message
|
|
2466
|
+
* let response = await client.downloadMany('*', ['2', '3]);
|
|
2467
|
+
* process.stdout.write(response[2].content)
|
|
2468
|
+
* process.stdout.write(response[3].content)
|
|
2469
|
+
*/
|
|
2470
|
+
async downloadMany(range, parts, options) {
|
|
2471
|
+
if (!this.mailbox) {
|
|
2472
|
+
// no mailbox selected, nothing to do
|
|
2473
|
+
return {};
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
options = Object.assign(
|
|
2477
|
+
{
|
|
2478
|
+
chunkSize: 64 * 1024,
|
|
2479
|
+
maxBytes: Infinity
|
|
2480
|
+
},
|
|
2481
|
+
options || {}
|
|
2482
|
+
);
|
|
2483
|
+
|
|
2484
|
+
let query = { bodyParts: [] };
|
|
2485
|
+
|
|
2486
|
+
for (let part of parts) {
|
|
2487
|
+
query.bodyParts.push(part + '.mime');
|
|
2488
|
+
query.bodyParts.push(part);
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
let response = await this.fetchOne(range, query, options);
|
|
2492
|
+
|
|
2493
|
+
if (!response || !response.bodyParts) {
|
|
2494
|
+
return { response: false };
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
let data = {};
|
|
2498
|
+
|
|
2499
|
+
for (let [part, content] of response.bodyParts) {
|
|
2500
|
+
let keyParts = part.split('.');
|
|
2501
|
+
if (keyParts.length === 1) {
|
|
2502
|
+
// content
|
|
2503
|
+
let key = keyParts[0];
|
|
2504
|
+
if (!data[key]) {
|
|
2505
|
+
data[key] = { content };
|
|
2506
|
+
} else {
|
|
2507
|
+
data[key].content = content;
|
|
2508
|
+
}
|
|
2509
|
+
} else if (keyParts.length === 2) {
|
|
2510
|
+
// header
|
|
2511
|
+
let key = keyParts[0];
|
|
2512
|
+
if (!data[key]) {
|
|
2513
|
+
data[key] = {};
|
|
2514
|
+
}
|
|
2515
|
+
if (!data[key].meta) {
|
|
2516
|
+
data[key].meta = {};
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
let headers = new Headers(content);
|
|
2520
|
+
let contentType = libmime.parseHeaderValue(headers.getFirst('Content-Type'));
|
|
2521
|
+
let transferEncoding = libmime.parseHeaderValue(headers.getFirst('Content-Transfer-Encoding'));
|
|
2522
|
+
let disposition = libmime.parseHeaderValue(headers.getFirst('Content-Disposition'));
|
|
2523
|
+
|
|
2524
|
+
if (contentType.value.toLowerCase().trim()) {
|
|
2525
|
+
data[key].meta.contentType = contentType.value.toLowerCase().trim();
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
if (contentType.params.charset) {
|
|
2529
|
+
data[key].meta.charset = contentType.params.charset.toLowerCase().trim();
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
if (transferEncoding.value) {
|
|
2533
|
+
data[key].meta.encoding = transferEncoding.value
|
|
2534
|
+
.replace(/\(.*\)/g, '')
|
|
2535
|
+
.toLowerCase()
|
|
2536
|
+
.trim();
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
if (disposition.value) {
|
|
2540
|
+
data[key].meta.disposition = disposition.value.toLowerCase().trim() || false;
|
|
2541
|
+
try {
|
|
2542
|
+
data[key].meta.disposition = libmime.decodeWords(data[key].meta.disposition);
|
|
2543
|
+
} catch (err) {
|
|
2544
|
+
// failed to parse disposition, keep as is (most probably an unknown charset is used)
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
if (contentType.params.format && contentType.params.format.toLowerCase().trim() === 'flowed') {
|
|
2549
|
+
data[key].meta.flowed = true;
|
|
2550
|
+
if (contentType.params.delsp && contentType.params.delsp.toLowerCase().trim() === 'yes') {
|
|
2551
|
+
data[key].meta.delSp = true;
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
let filename = disposition.params.filename || contentType.params.name || false;
|
|
2556
|
+
if (filename) {
|
|
2557
|
+
try {
|
|
2558
|
+
filename = this.libmime.decodeWords(filename);
|
|
2559
|
+
} catch (err) {
|
|
2560
|
+
// failed to parse filename, keep as is (most probably an unknown charset is used)
|
|
2561
|
+
}
|
|
2562
|
+
data[key].meta.filename = filename;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
for (let part of Object.keys(data)) {
|
|
2568
|
+
let meta = data[part].meta;
|
|
2569
|
+
|
|
2570
|
+
switch (meta.encoding) {
|
|
2571
|
+
case 'base64':
|
|
2572
|
+
data[part].content = data[part].content ? libbase64.decode(data[part].content.toString()) : null;
|
|
2573
|
+
break;
|
|
2574
|
+
case 'quoted-printable':
|
|
2575
|
+
data[part].content = data[part].content ? libqp.decode(data[part].content.toString()) : null;
|
|
2576
|
+
break;
|
|
2577
|
+
default:
|
|
2578
|
+
// keep as is, already a buffer
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
return data;
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2454
2585
|
async run(command, ...args) {
|
|
2455
2586
|
command = command.toUpperCase();
|
|
2456
2587
|
if (!this.commands.has(command)) {
|
package/lib/types.d.ts
CHANGED
|
@@ -478,6 +478,22 @@ declare module "imapflow" {
|
|
|
478
478
|
maxBytes?: number;
|
|
479
479
|
chunkSize?: number;
|
|
480
480
|
}): Promise<DownloadObject>;
|
|
481
|
+
/**
|
|
482
|
+
* Fetch multiple attachments as Buffer values
|
|
483
|
+
* @example
|
|
484
|
+
* let mailbox = await client.mailboxOpen('INBOX');
|
|
485
|
+
* // download body part nr '1.2' from latest message
|
|
486
|
+
* let response = await client.downloadMany('*', ['2', '3]);
|
|
487
|
+
* process.stdout.write(response[2].content)
|
|
488
|
+
* process.stdout.write(response[3].content)
|
|
489
|
+
* @param range - UID or sequence number for the message to fetch
|
|
490
|
+
* @param parts - A list of bodystructure parts
|
|
491
|
+
* @param [options.uid] - If `true` then uses UID number instead of sequence number for `range`
|
|
492
|
+
* @returns Download data object
|
|
493
|
+
*/
|
|
494
|
+
downloadMany(range: SequenceString, parts: string, options?: {
|
|
495
|
+
uid?: boolean;
|
|
496
|
+
}): Promise<object>;
|
|
481
497
|
/**
|
|
482
498
|
* Opens a mailbox if not already open and returns a lock. Next call to `getMailboxLock()` is queued
|
|
483
499
|
* until previous lock is released. This is suggested over {@link module:imapflow~ImapFlow#mailboxOpen|mailboxOpen()} as
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapflow",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.109",
|
|
4
4
|
"description": "IMAP Client for Node",
|
|
5
5
|
"main": "./lib/imap-flow.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://imapflow.com/",
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@babel/eslint-parser": "7.
|
|
31
|
-
"@babel/eslint-plugin": "7.
|
|
30
|
+
"@babel/eslint-parser": "7.19.1",
|
|
31
|
+
"@babel/eslint-plugin": "7.19.1",
|
|
32
32
|
"@babel/plugin-syntax-class-properties": "7.12.13",
|
|
33
|
-
"@babel/preset-env": "7.
|
|
34
|
-
"@types/node": "18.7.
|
|
33
|
+
"@babel/preset-env": "7.19.3",
|
|
34
|
+
"@types/node": "18.7.23",
|
|
35
35
|
"braintree-jsdoc-template": "3.3.0",
|
|
36
|
-
"eslint": "8.
|
|
36
|
+
"eslint": "8.24.0",
|
|
37
37
|
"eslint-config-nodemailer": "1.2.0",
|
|
38
38
|
"eslint-config-prettier": "8.5.0",
|
|
39
39
|
"grunt": "1.5.3",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"libmime": "5.1.0",
|
|
52
52
|
"libqp": "1.1.0",
|
|
53
53
|
"mailsplit": "5.3.2",
|
|
54
|
-
"nodemailer": "6.
|
|
55
|
-
"pino": "8.
|
|
54
|
+
"nodemailer": "6.8.0",
|
|
55
|
+
"pino": "8.6.1",
|
|
56
56
|
"socks": "2.7.0"
|
|
57
57
|
}
|
|
58
58
|
}
|