@mavogel/awscdk-rootmail 0.1.7 → 0.1.9
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/.jsii +10 -10
- package/lib/rootmail.js +1 -1
- package/lib/ses-receive.js +1 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +5 -5
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-es/schemas/schemas_0.js +4 -4
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/DescribeDeliveryDestinationsCommand.d.ts +1 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/GetDeliveryDestinationCommand.d.ts +1 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutAccountPolicyCommand.d.ts +4 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutDeliveryDestinationCommand.d.ts +2 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/models/models_0.d.ts +80 -36
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/ts3.4/models/models_0.d.ts +2 -0
- package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +1 -1
- package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-route-53/package.json +1 -1
- package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +2 -1
- package/node_modules/@aws-sdk/client-s3/dist-es/models/enums.js +1 -0
- package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetBucketInventoryConfigurationCommand.d.ts +1 -1
- package/node_modules/@aws-sdk/client-s3/dist-types/commands/ListBucketInventoryConfigurationsCommand.d.ts +1 -1
- package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutBucketInventoryConfigurationCommand.d.ts +1 -1
- package/node_modules/@aws-sdk/client-s3/dist-types/models/enums.d.ts +1 -0
- package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/enums.d.ts +1 -0
- package/node_modules/@aws-sdk/client-s3/package.json +2 -2
- package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ses/package.json +1 -1
- package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +9 -3
- package/node_modules/@aws-sdk/client-ssm/dist-es/models/enums.js +4 -0
- package/node_modules/@aws-sdk/client-ssm/dist-es/schemas/schemas_0.js +3 -2
- package/node_modules/@aws-sdk/client-ssm/dist-types/commands/DeleteResourcePolicyCommand.d.ts +6 -0
- package/node_modules/@aws-sdk/client-ssm/dist-types/commands/PutResourcePolicyCommand.d.ts +12 -0
- package/node_modules/@aws-sdk/client-ssm/dist-types/models/enums.d.ts +12 -0
- package/node_modules/@aws-sdk/client-ssm/dist-types/models/models_0.d.ts +20 -1
- package/node_modules/@aws-sdk/client-ssm/dist-types/models/models_1.d.ts +2 -2
- package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/enums.d.ts +5 -0
- package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/models_0.d.ts +2 -0
- package/node_modules/@aws-sdk/client-ssm/package.json +1 -1
- package/node_modules/@zone-eu/mailsplit/lib/flowed-decoder.js +1 -5
- package/node_modules/@zone-eu/mailsplit/lib/headers.js +35 -25
- package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +126 -79
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +27 -5
- package/node_modules/@zone-eu/mailsplit/lib/node-rewriter.js +3 -2
- package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +0 -3
- package/node_modules/@zone-eu/mailsplit/package.json +5 -5
- package/node_modules/libbase64/.github/workflows/release.yaml +12 -10
- package/node_modules/libbase64/.ncurc.js +7 -1
- package/node_modules/libbase64/CHANGELOG.md +7 -0
- package/node_modules/libbase64/lib/libbase64.js +27 -0
- package/node_modules/libbase64/package.json +4 -4
- package/node_modules/libmime/CHANGELOG.md +14 -0
- package/node_modules/libmime/lib/libmime.js +41 -21
- package/node_modules/libmime/package.json +3 -3
- package/node_modules/libqp/.github/workflows/release.yaml +12 -10
- package/node_modules/libqp/CHANGELOG.md +7 -0
- package/node_modules/libqp/lib/libqp.js +6 -4
- package/node_modules/libqp/package.json +2 -2
- package/node_modules/libqp/test/libqp-test.js +71 -14
- package/node_modules/mailparser/.release-please-manifest.json +1 -1
- package/node_modules/mailparser/CHANGELOG.md +42 -0
- package/node_modules/mailparser/README.md +5 -0
- package/node_modules/mailparser/lib/mail-parser.js +107 -32
- package/node_modules/mailparser/lib/simple-parser.js +12 -0
- package/node_modules/mailparser/lib/stream-hash.js +1 -1
- package/node_modules/mailparser/package.json +6 -6
- package/node_modules/nodemailer/CHANGELOG.md +38 -0
- package/node_modules/nodemailer/README.md +1 -1
- package/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +16 -2
- package/node_modules/nodemailer/dist/cjs/addressparser/index.js +147 -28
- package/node_modules/nodemailer/dist/cjs/base64/index.js +2 -1
- package/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +13 -1
- package/node_modules/nodemailer/dist/cjs/dkim/index.js +25 -8
- package/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +10 -1
- package/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +28 -4
- package/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +10 -1
- package/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +3 -0
- package/node_modules/nodemailer/dist/cjs/dkim/sign.js +18 -1
- package/node_modules/nodemailer/dist/cjs/errors.d.ts +3 -2
- package/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +12 -1
- package/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +15 -1
- package/node_modules/nodemailer/dist/cjs/fetch/index.js +39 -64
- package/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +14 -4
- package/node_modules/nodemailer/dist/cjs/json-transport/index.js +2 -0
- package/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +8 -3
- package/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +43 -25
- package/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +11 -4
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +7 -3
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +198 -84
- package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +5 -2
- package/node_modules/nodemailer/dist/cjs/mime-node/index.js +2 -1
- package/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +38 -16
- package/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
- package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
- package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
- package/node_modules/nodemailer/dist/cjs/punycode/index.js +1 -0
- package/node_modules/nodemailer/dist/cjs/qp/index.d.ts +2 -0
- package/node_modules/nodemailer/dist/cjs/qp/index.js +10 -1
- package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +2 -0
- package/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +39 -2
- package/node_modules/nodemailer/dist/cjs/shared/index.d.ts +43 -7
- package/node_modules/nodemailer/dist/cjs/shared/index.js +5 -2
- package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +2 -1
- package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +32 -24
- package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +13 -5
- package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +23 -11
- package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +59 -24
- package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +156 -75
- package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +12 -4
- package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +39 -11
- package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +27 -31
- package/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +19 -6
- package/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +25 -33
- package/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +2 -0
- package/node_modules/nodemailer/dist/cjs/well-known/services.js +6 -0
- package/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +13 -3
- package/node_modules/nodemailer/dist/cjs/xoauth2/index.js +25 -13
- package/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +16 -2
- package/node_modules/nodemailer/dist/esm/addressparser/index.js +147 -27
- package/node_modules/nodemailer/dist/esm/base64/index.js +2 -1
- package/node_modules/nodemailer/dist/esm/dkim/index.d.ts +13 -1
- package/node_modules/nodemailer/dist/esm/dkim/index.js +25 -8
- package/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +10 -1
- package/node_modules/nodemailer/dist/esm/dkim/message-parser.js +30 -5
- package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +10 -1
- package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +2 -1
- package/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +3 -0
- package/node_modules/nodemailer/dist/esm/dkim/sign.js +18 -1
- package/node_modules/nodemailer/dist/esm/errors.d.ts +3 -2
- package/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +12 -1
- package/node_modules/nodemailer/dist/esm/fetch/cookies.js +2 -1
- package/node_modules/nodemailer/dist/esm/fetch/index.d.ts +15 -1
- package/node_modules/nodemailer/dist/esm/fetch/index.js +39 -64
- package/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +14 -4
- package/node_modules/nodemailer/dist/esm/json-transport/index.js +2 -0
- package/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +8 -3
- package/node_modules/nodemailer/dist/esm/mailer/index.d.ts +43 -25
- package/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +11 -4
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +7 -3
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +198 -84
- package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +5 -2
- package/node_modules/nodemailer/dist/esm/mime-node/index.js +2 -1
- package/node_modules/nodemailer/dist/esm/nodemailer.d.ts +38 -16
- package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
- package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
- package/node_modules/nodemailer/dist/esm/punycode/index.js +1 -0
- package/node_modules/nodemailer/dist/esm/qp/index.d.ts +2 -0
- package/node_modules/nodemailer/dist/esm/qp/index.js +10 -1
- package/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +2 -0
- package/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +39 -2
- package/node_modules/nodemailer/dist/esm/shared/index.d.ts +43 -7
- package/node_modules/nodemailer/dist/esm/shared/index.js +5 -2
- package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +2 -1
- package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +32 -24
- package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +13 -5
- package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +23 -11
- package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +59 -24
- package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +156 -75
- package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +12 -4
- package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +39 -11
- package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +27 -31
- package/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +19 -6
- package/node_modules/nodemailer/dist/esm/smtp-transport/index.js +25 -33
- package/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +2 -0
- package/node_modules/nodemailer/dist/esm/well-known/services.js +6 -0
- package/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +13 -3
- package/node_modules/nodemailer/dist/esm/xoauth2/index.js +25 -13
- package/node_modules/nodemailer/dist/well-known/services.json +7 -0
- package/node_modules/nodemailer/package.json +16 -12
- package/package.json +18 -16
- package/renovate.json5 +59 -0
|
@@ -34,6 +34,16 @@ const MAX_LINKIFY_SEGMENT_LENGTH = 4096;
|
|
|
34
34
|
const MAX_LINKIFY_HOST_LABELS = 6;
|
|
35
35
|
const MAX_LINKIFY_WORK = 768 * 1024 * 1024; // shared by all text parts of a message
|
|
36
36
|
|
|
37
|
+
// Default upper bound for the total length of the URLs updateImageLinks() writes
|
|
38
|
+
// into the HTML (options.maxInlinedImagesSize). simpleParser inlines every cid:
|
|
39
|
+
// reference as a full data: URL, so a small message repeating a reference to
|
|
40
|
+
// one image thousands of times would otherwise grow the HTML past the maximum
|
|
41
|
+
// string length. References beyond the budget are left as cid: links.
|
|
42
|
+
const MAX_INLINED_IMAGES_SIZE = 20 * 1024 * 1024;
|
|
43
|
+
|
|
44
|
+
// List-* header names that must not become keys of the plain list object
|
|
45
|
+
const UNSAFE_LIST_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
46
|
+
|
|
37
47
|
linkify
|
|
38
48
|
.tlds(tlds) // Reload with full tlds list
|
|
39
49
|
.tlds('onion', true) // Add unofficial `.onion` domain
|
|
@@ -72,6 +82,31 @@ linkify.add('@', {
|
|
|
72
82
|
}
|
|
73
83
|
});
|
|
74
84
|
|
|
85
|
+
// Linear equivalent of /<[^<>]+@[^<>]+>/.test(str). The regex backtracks
|
|
86
|
+
// quadratically on a long run of @ characters after a lone <, and the input is a
|
|
87
|
+
// decoded encoded-word bounded only by the header size limit.
|
|
88
|
+
function hasBracketedAddress(str) {
|
|
89
|
+
let start = -1;
|
|
90
|
+
// first @ after the current < that has at least one character before it
|
|
91
|
+
let at = -1;
|
|
92
|
+
for (let i = 0, len = str.length; i < len; i++) {
|
|
93
|
+
let chr = str.charAt(i);
|
|
94
|
+
if (chr === '<') {
|
|
95
|
+
start = i;
|
|
96
|
+
at = -1;
|
|
97
|
+
} else if (chr === '>') {
|
|
98
|
+
if (start >= 0 && at >= 0 && at < i - 1) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
start = -1;
|
|
102
|
+
at = -1;
|
|
103
|
+
} else if (chr === '@' && start >= 0 && at < 0 && i > start + 1) {
|
|
104
|
+
at = i;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
75
110
|
class IconvDecoder extends Transform {
|
|
76
111
|
constructor(Iconv, charset) {
|
|
77
112
|
super();
|
|
@@ -185,8 +220,6 @@ class MailParser extends Transform {
|
|
|
185
220
|
|
|
186
221
|
this.attachmentList = [];
|
|
187
222
|
|
|
188
|
-
this.boundaries = [];
|
|
189
|
-
|
|
190
223
|
this.textTypes = ['text/plain', 'text/html'].concat(!this.options.keepDeliveryStatus ? 'message/delivery-status' : []);
|
|
191
224
|
|
|
192
225
|
this.decoder = this.getDecoder();
|
|
@@ -236,7 +269,7 @@ class MailParser extends Transform {
|
|
|
236
269
|
decodeStream(charset) {
|
|
237
270
|
// resolve charset aliases (eg. iso-8859-8-i -> ISO-8859-8) via libmime's canonical table
|
|
238
271
|
charset = libmime.normalizeCharset((charset || 'ascii').toString());
|
|
239
|
-
if (/^jis|^iso-?2022-?jp
|
|
272
|
+
if (/^jis|^iso-?2022-?jp/i.test(charset)) {
|
|
240
273
|
// special case not supported by iconv-lite
|
|
241
274
|
return new JPDecoder(charset);
|
|
242
275
|
}
|
|
@@ -302,7 +335,12 @@ class MailParser extends Transform {
|
|
|
302
335
|
if (this.finished) {
|
|
303
336
|
return this.cleanup(done);
|
|
304
337
|
}
|
|
305
|
-
this.waitingEnd =
|
|
338
|
+
this.waitingEnd = err => {
|
|
339
|
+
// runs once, either on a splitter error after end of input or when the splitter ends
|
|
340
|
+
this.waitingEnd = false;
|
|
341
|
+
if (err) {
|
|
342
|
+
return done(err);
|
|
343
|
+
}
|
|
306
344
|
this.cleanup(done);
|
|
307
345
|
};
|
|
308
346
|
}
|
|
@@ -479,6 +517,10 @@ class MailParser extends Transform {
|
|
|
479
517
|
}
|
|
480
518
|
|
|
481
519
|
parseListHeader(key, value) {
|
|
520
|
+
if (UNSAFE_LIST_KEYS.has(key)) {
|
|
521
|
+
// would replace the prototype of (or shadow) the normalized list object
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
482
524
|
let addresses = addressparser(value);
|
|
483
525
|
let response = {};
|
|
484
526
|
let data = addresses
|
|
@@ -563,7 +605,7 @@ class MailParser extends Transform {
|
|
|
563
605
|
// must not be re-interpreted as an address -- RFC 2047 Section 5 prohibits
|
|
564
606
|
// encoded-words in addr-spec, and re-parsing fabricates addresses not present
|
|
565
607
|
// in the original header.
|
|
566
|
-
if (
|
|
608
|
+
if (hasBracketedAddress(decoded)) {
|
|
567
609
|
let parsed = addressparser(decoded);
|
|
568
610
|
if (parsed.length) {
|
|
569
611
|
parsed.forEach(entry => {
|
|
@@ -852,7 +894,8 @@ class MailParser extends Transform {
|
|
|
852
894
|
processChunk(data, done) {
|
|
853
895
|
let partId = null;
|
|
854
896
|
if (data._parentBoundary) {
|
|
855
|
-
|
|
897
|
+
// mailsplit numbers parts IMAP style from the actual tree, TEXT markers are not part of the id
|
|
898
|
+
partId = (data.partNr || []).filter(nr => typeof nr === 'number').join('.') || null;
|
|
856
899
|
}
|
|
857
900
|
switch (data.type) {
|
|
858
901
|
case 'node': {
|
|
@@ -884,6 +927,11 @@ class MailParser extends Transform {
|
|
|
884
927
|
contentType = this.libmime.detectMimeType(data.filename) || 'application/octet-stream';
|
|
885
928
|
}
|
|
886
929
|
|
|
930
|
+
// backpressure state for the attachment stream, see pump() below
|
|
931
|
+
let released = false;
|
|
932
|
+
let waitingDrain = false;
|
|
933
|
+
let pump = null;
|
|
934
|
+
|
|
887
935
|
let attachment = {
|
|
888
936
|
type: 'attachment',
|
|
889
937
|
content: null,
|
|
@@ -891,6 +939,11 @@ class MailParser extends Transform {
|
|
|
891
939
|
partId,
|
|
892
940
|
release: () => {
|
|
893
941
|
attachment.release = null;
|
|
942
|
+
released = true;
|
|
943
|
+
if (waitingDrain) {
|
|
944
|
+
waitingDrain = false;
|
|
945
|
+
pump();
|
|
946
|
+
}
|
|
894
947
|
if (this.waitUntilAttachmentEnd && typeof this.attachmentCallback === 'function') {
|
|
895
948
|
setImmediate(this.attachmentCallback);
|
|
896
949
|
}
|
|
@@ -900,16 +953,38 @@ class MailParser extends Transform {
|
|
|
900
953
|
};
|
|
901
954
|
|
|
902
955
|
let algo = this.options.checksumAlgo || 'md5';
|
|
903
|
-
let hasher
|
|
956
|
+
let hasher;
|
|
957
|
+
try {
|
|
958
|
+
hasher = new StreamHash(attachment, algo);
|
|
959
|
+
} catch (err) {
|
|
960
|
+
// an algorithm this Node does not offer (a typo, or MD5 on a host whose
|
|
961
|
+
// OpenSSL runs in FIPS mode) is a parser error, not a process-ending throw
|
|
962
|
+
err.message = `Checksum algorithm "${algo}" is not available: ${err.message}`;
|
|
963
|
+
return done(err);
|
|
964
|
+
}
|
|
904
965
|
node.decoder.on('error', err => {
|
|
905
966
|
hasher.emit('error', err);
|
|
906
967
|
});
|
|
907
968
|
|
|
908
|
-
|
|
969
|
+
// Honour the consumer's backpressure while it reads the attachment. Once the
|
|
970
|
+
// attachment is released it is drained regardless, so that a caller that
|
|
971
|
+
// releases without reading the content does not stall the parser.
|
|
972
|
+
pump = () => {
|
|
909
973
|
let chunk;
|
|
910
|
-
|
|
911
974
|
while ((chunk = node.decoder.read()) !== null) {
|
|
912
|
-
hasher.write(chunk)
|
|
975
|
+
if (hasher.write(chunk) === false && !released) {
|
|
976
|
+
waitingDrain = true;
|
|
977
|
+
return hasher.once('drain', () => {
|
|
978
|
+
waitingDrain = false;
|
|
979
|
+
pump();
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
node.decoder.on('readable', () => {
|
|
986
|
+
if (!waitingDrain) {
|
|
987
|
+
pump();
|
|
913
988
|
}
|
|
914
989
|
});
|
|
915
990
|
|
|
@@ -1041,22 +1116,6 @@ class MailParser extends Transform {
|
|
|
1041
1116
|
setImmediate(done);
|
|
1042
1117
|
}
|
|
1043
1118
|
|
|
1044
|
-
_getPartId(parentBoundary) {
|
|
1045
|
-
let boundaryIndex = this.boundaries.findIndex(item => item.name === parentBoundary);
|
|
1046
|
-
if (boundaryIndex === -1) {
|
|
1047
|
-
this.boundaries.push({ name: parentBoundary, count: 1 });
|
|
1048
|
-
boundaryIndex = this.boundaries.length - 1;
|
|
1049
|
-
} else {
|
|
1050
|
-
this.boundaries[boundaryIndex].count++;
|
|
1051
|
-
}
|
|
1052
|
-
let partId = '1';
|
|
1053
|
-
for (let i = 0; i <= boundaryIndex; i++) {
|
|
1054
|
-
if (i === 0) partId = this.boundaries[i].count.toString();
|
|
1055
|
-
else partId += '.' + this.boundaries[i].count.toString();
|
|
1056
|
-
}
|
|
1057
|
-
return partId;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
1119
|
getAddressesHTML(value) {
|
|
1061
1120
|
let formatSingleLevel = addresses =>
|
|
1062
1121
|
addresses
|
|
@@ -1139,12 +1198,28 @@ class MailParser extends Transform {
|
|
|
1139
1198
|
let pos = 0;
|
|
1140
1199
|
let processNext = () => {
|
|
1141
1200
|
if (pos >= cidList.length) {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1201
|
+
let maxSize = this.options.maxInlinedImagesSize;
|
|
1202
|
+
if (typeof maxSize !== 'number' || !(maxSize >= 0)) {
|
|
1203
|
+
maxSize = MAX_INLINED_IMAGES_SIZE;
|
|
1204
|
+
}
|
|
1205
|
+
let inlinedSize = 0;
|
|
1206
|
+
try {
|
|
1207
|
+
html = html.replace(/\bcid:([^'"\s]{1,256})/g, (match, cid) => {
|
|
1208
|
+
let url = cids.has(cid) && cids.get(cid).url;
|
|
1209
|
+
if (!url) {
|
|
1210
|
+
return match;
|
|
1211
|
+
}
|
|
1212
|
+
url = String(url);
|
|
1213
|
+
if (inlinedSize + url.length > maxSize) {
|
|
1214
|
+
return match;
|
|
1215
|
+
}
|
|
1216
|
+
inlinedSize += url.length;
|
|
1217
|
+
return url;
|
|
1218
|
+
});
|
|
1219
|
+
} catch (err) {
|
|
1220
|
+
// runs from setImmediate, a throw here would be an uncaught exception
|
|
1221
|
+
return done(err);
|
|
1222
|
+
}
|
|
1148
1223
|
|
|
1149
1224
|
return done(null, html);
|
|
1150
1225
|
}
|
|
@@ -19,6 +19,18 @@ module.exports = (input, options, callback) => {
|
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// MailParser may emit a non-fatal 'error' (eg. HTML too long to convert to text) and
|
|
23
|
+
// still reach 'end', so settle only once: the first error or the result wins
|
|
24
|
+
let settled = false;
|
|
25
|
+
let settle = callback;
|
|
26
|
+
callback = (...args) => {
|
|
27
|
+
if (settled) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
settled = true;
|
|
31
|
+
settle(...args);
|
|
32
|
+
};
|
|
33
|
+
|
|
22
34
|
options = options || {};
|
|
23
35
|
let keepCidLinks = !!options.keepCidLinks;
|
|
24
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailparser",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.34",
|
|
4
4
|
"description": "Parse e-mails",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"he": "1.2.0",
|
|
23
23
|
"html-to-text": "10.0.1",
|
|
24
24
|
"iconv-lite": "0.7.3",
|
|
25
|
-
"libmime": "5.4.
|
|
25
|
+
"libmime": "5.4.6",
|
|
26
26
|
"linkify-it": "5.0.2",
|
|
27
|
-
"@zone-eu/mailsplit": "5.4.
|
|
28
|
-
"nodemailer": "10.0.
|
|
27
|
+
"@zone-eu/mailsplit": "5.4.19",
|
|
28
|
+
"nodemailer": "10.0.14",
|
|
29
29
|
"punycode.js": "2.3.1",
|
|
30
30
|
"tlds": "1.261.0"
|
|
31
31
|
},
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@eslint/eslintrc": "3.3.7",
|
|
34
34
|
"@eslint/js": "10.0.1",
|
|
35
35
|
"ajv": "8.20.0",
|
|
36
|
-
"eslint": "10.
|
|
36
|
+
"eslint": "10.12.0",
|
|
37
37
|
"eslint-config-nodemailer": "1.2.0",
|
|
38
38
|
"eslint-config-prettier": "10.1.8",
|
|
39
39
|
"grunt": "1.6.3",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"grunt-contrib-nodeunit": "5.0.0",
|
|
42
42
|
"grunt-eslint": "27.0.0",
|
|
43
43
|
"iconv": "3.0.1",
|
|
44
|
-
"prettier": "3.9.
|
|
44
|
+
"prettier": "3.9.9",
|
|
45
45
|
"random-message": "1.1.0"
|
|
46
46
|
},
|
|
47
47
|
"repository": {
|
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [10.0.14](https://github.com/nodemailer/nodemailer/compare/v10.0.13...v10.0.14) (2026-10-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **addressparser:** keep a quoted display name that holds no "@" out of the address ([3570d26](https://github.com/nodemailer/nodemailer/commit/3570d26c7b55f6e5df50d4076046600ad3fd040b))
|
|
9
|
+
* **addressparser:** keep the group recursion depth out of the options object ([a680254](https://github.com/nodemailer/nodemailer/commit/a68025405a1378c82e78f64ffad27b92c1035cbe))
|
|
10
|
+
* **addressparser:** stop a "[" from hiding the operators after it ([5619784](https://github.com/nodemailer/nodemailer/commit/561978491d5cc33d2052a6c89a499b838b960262))
|
|
11
|
+
* **dkim:** trim a header field name in linear time ([c6f7a55](https://github.com/nodemailer/nodemailer/commit/c6f7a55a2978bf031b8519ebf59baddf94c032c8))
|
|
12
|
+
* **mime-funcs:** read and write header parameters per rfc2045 and rfc2231 ([b8ccad7](https://github.com/nodemailer/nodemailer/commit/b8ccad723a7e49a674a4d70f32eb9fe77312008d))
|
|
13
|
+
* search only the new bytes for the end of the proxy CONNECT response ([81efd7b](https://github.com/nodemailer/nodemailer/commit/81efd7bfc559305f900d6a22b5c56aa94556002b))
|
|
14
|
+
|
|
15
|
+
## [10.0.13](https://github.com/nodemailer/nodemailer/compare/v10.0.12...v10.0.13) (2026-09-30)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* read the advertised SASL methods without backtracking regexes ([b5a896f](https://github.com/nodemailer/nodemailer/commit/b5a896fcb02df1628329d7cd665ca08490b14b56))
|
|
21
|
+
* strip comments inside an angle-addr before it becomes the address ([a502247](https://github.com/nodemailer/nodemailer/commit/a502247555fd81773eac337486781f3b6008e16a))
|
|
22
|
+
|
|
23
|
+
## [10.0.12](https://github.com/nodemailer/nodemailer/compare/v10.0.11...v10.0.12) (2026-09-28)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
* settle every send on a connection error, back off pool requeues, turn a bare CR into CRLF, bound fetch, honour requireTLS ([63ccd66](https://github.com/nodemailer/nodemailer/commit/63ccd66c894bbaac18c82084ee385bf6488226cf))
|
|
29
|
+
|
|
30
|
+
## [10.0.11](https://github.com/nodemailer/nodemailer/compare/v10.0.10...v10.0.11) (2026-09-27)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* **fetch:** report a form body that can not be encoded through the returned stream ([74d40bf](https://github.com/nodemailer/nodemailer/commit/74d40bf1e4553bc0568b471250a9251bcb569b00))
|
|
36
|
+
* keep the CommonJS entry point and the services subpath compatible with the pre-TypeScript build ([52901ef](https://github.com/nodemailer/nodemailer/commit/52901ef3725ad179aa56276495a60f53b2c83516))
|
|
37
|
+
* **qp:** keep wrap() terminating for short line lengths and a trailing incomplete escape ([8fa140b](https://github.com/nodemailer/nodemailer/commit/8fa140b11c62cb1202eac84d35bb3ba28bc3b1a1))
|
|
38
|
+
* **smtp-connection:** fail a password login cleanly when the server offers only XOAUTH2 ([90abf7d](https://github.com/nodemailer/nodemailer/commit/90abf7d11db5ebfeb4292b62c1fff969741c7d33))
|
|
39
|
+
* **types:** restore the layout of @types/nodemailer in the bundled declarations ([ac2e40f](https://github.com/nodemailer/nodemailer/commit/ac2e40ffc69427e0eb33ce3945fae76c4c828c8d))
|
|
40
|
+
|
|
3
41
|
## [10.0.10](https://github.com/nodemailer/nodemailer/compare/v10.0.9...v10.0.10) (2026-09-14)
|
|
4
42
|
|
|
5
43
|
|
|
@@ -72,7 +72,7 @@ let configOptions = {
|
|
|
72
72
|
|
|
73
73
|
#### I have an issue with TypeScript types
|
|
74
74
|
|
|
75
|
-
Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter<SMTPTransport.SentMessageInfo>` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply.
|
|
75
|
+
Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter<SMTPTransport.SentMessageInfo>` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. The modules under `nodemailer/lib/` are declared with a default export, so import a class as `import SMTPTransport from 'nodemailer/lib/smtp-transport'` (with `esModuleInterop` in a CommonJS project). The `import SMTPTransport = require(...)` and `import * as SMTPTransport from ...` forms still resolve the type aliases such as `SMTPTransport.Options`, but they refer to the module rather than to the class, so the class itself has to be imported with a default import. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply.
|
|
76
76
|
|
|
77
77
|
#### I have a different problem
|
|
78
78
|
|
|
@@ -39,7 +39,21 @@ export type Address = MailboxAddress | GroupAddress;
|
|
|
39
39
|
*
|
|
40
40
|
* @param str Address field
|
|
41
41
|
* @param options Optional options object
|
|
42
|
-
* @param options._depth Internal recursion depth counter (do not set manually)
|
|
43
42
|
* @return An array of address objects
|
|
44
43
|
*/
|
|
45
|
-
|
|
44
|
+
declare function addressparser(str: string | null | undefined, options: AddressParserOptions & {
|
|
45
|
+
flatten: true;
|
|
46
|
+
}): MailboxAddress[];
|
|
47
|
+
declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
|
|
48
|
+
/**
|
|
49
|
+
* Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working
|
|
50
|
+
*/
|
|
51
|
+
type AddressEntry = Address;
|
|
52
|
+
declare namespace addressparser {
|
|
53
|
+
type Address = MailboxAddress;
|
|
54
|
+
type Group = GroupAddress;
|
|
55
|
+
type AddressOrGroup = AddressEntry;
|
|
56
|
+
}
|
|
57
|
+
/** The names @types/nodemailer used for the group entry and for the union of both entry types */
|
|
58
|
+
export type { GroupAddress as Group, Address as AddressOrGroup };
|
|
59
|
+
export default addressparser;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = addressparser;
|
|
4
3
|
/**
|
|
5
4
|
* Restores the quoting of a local part that was read out of a quoted string.
|
|
6
5
|
*
|
|
@@ -243,6 +242,81 @@ function _recoverAddrSpec(data) {
|
|
|
243
242
|
.filter(part => part)
|
|
244
243
|
.join(' ');
|
|
245
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Takes the RFC 5322 comments out of the contents of an angle-addr.
|
|
247
|
+
*
|
|
248
|
+
* The tokenizer tracks a single open operator, so once '<' is open a '(' is plain text and
|
|
249
|
+
* a comment inside the brackets reached the address verbatim: 'Name <user@example.com(x)evil.com>'
|
|
250
|
+
* put 'user@example.com(x)evil.com' into the envelope, a value that is no mailbox and that a
|
|
251
|
+
* receiver stripping the comment reads as 'user@example.comevil.com' (GHSA-g73g-hqqh-jr95).
|
|
252
|
+
* A comment is folding whitespace, so it is read as a space that splits two atoms and as
|
|
253
|
+
* nothing next to an '@', the same rule the token walk applies outside the brackets. Quoted
|
|
254
|
+
* strings and domain literals are copied through untouched, a '(' in there is not a comment.
|
|
255
|
+
*
|
|
256
|
+
* @param address Contents of the angle brackets
|
|
257
|
+
* @return The address with the comments removed, and the text of the comments
|
|
258
|
+
*/
|
|
259
|
+
function _stripAddressComments(address) {
|
|
260
|
+
const comments = [];
|
|
261
|
+
let result = '';
|
|
262
|
+
let comment = '';
|
|
263
|
+
let depth = 0;
|
|
264
|
+
let closer = '';
|
|
265
|
+
// carried along rather than read back off the growing result, which would flatten it on
|
|
266
|
+
// every comment (see lastChars in _handleAddress)
|
|
267
|
+
let lastChar = '';
|
|
268
|
+
for (let i = 0, len = address.length; i < len; i++) {
|
|
269
|
+
const chr = address.charAt(i);
|
|
270
|
+
if (depth) {
|
|
271
|
+
if (chr === '\\' && i < len - 1) {
|
|
272
|
+
comment += address.charAt(++i);
|
|
273
|
+
}
|
|
274
|
+
else if (chr === '(') {
|
|
275
|
+
depth++;
|
|
276
|
+
comment += chr;
|
|
277
|
+
}
|
|
278
|
+
else if (chr === ')' && !--depth) {
|
|
279
|
+
comments.push(comment.trim());
|
|
280
|
+
comment = '';
|
|
281
|
+
if (lastChar !== '@' && address.charAt(i + 1) !== '@') {
|
|
282
|
+
result += ' ';
|
|
283
|
+
lastChar = ' ';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
comment += chr;
|
|
288
|
+
}
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (closer) {
|
|
292
|
+
if (chr === '\\' && closer === '"' && i < len - 1) {
|
|
293
|
+
result += chr + address.charAt(++i);
|
|
294
|
+
lastChar = address.charAt(i);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (chr === closer) {
|
|
298
|
+
closer = '';
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else if (chr === '"') {
|
|
302
|
+
closer = '"';
|
|
303
|
+
}
|
|
304
|
+
else if (chr === '[') {
|
|
305
|
+
closer = ']';
|
|
306
|
+
}
|
|
307
|
+
else if (chr === '(') {
|
|
308
|
+
depth = 1;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
result += chr;
|
|
312
|
+
lastChar = chr;
|
|
313
|
+
}
|
|
314
|
+
if (depth) {
|
|
315
|
+
// an unterminated comment runs to the end of the address
|
|
316
|
+
comments.push(comment.trim());
|
|
317
|
+
}
|
|
318
|
+
return { address: result.trim(), comments: comments.filter(text => text) };
|
|
319
|
+
}
|
|
246
320
|
/**
|
|
247
321
|
* Converts tokens for a single address into an address object
|
|
248
322
|
*
|
|
@@ -354,7 +428,7 @@ function _handleAddress(tokens, depth) {
|
|
|
354
428
|
// Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
|
|
355
429
|
let groupMembers = [];
|
|
356
430
|
if (data.group.length) {
|
|
357
|
-
const parsedGroup =
|
|
431
|
+
const parsedGroup = _parseAddressList(data.group.join(','), depth + 1);
|
|
358
432
|
parsedGroup.forEach(member => {
|
|
359
433
|
if (member.group) {
|
|
360
434
|
groupMembers = groupMembers.concat(member.group);
|
|
@@ -370,6 +444,24 @@ function _handleAddress(tokens, depth) {
|
|
|
370
444
|
});
|
|
371
445
|
}
|
|
372
446
|
else {
|
|
447
|
+
// Comments come out of the angle-addr before anything asks whether one was found, so
|
|
448
|
+
// that brackets holding nothing but a comment read the same as empty ones
|
|
449
|
+
const addressComments = [];
|
|
450
|
+
const addressParts = [];
|
|
451
|
+
for (const part of data.address) {
|
|
452
|
+
if (part.indexOf('(') < 0) {
|
|
453
|
+
addressParts.push(part);
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
const stripped = _stripAddressComments(part);
|
|
457
|
+
for (const comment of stripped.comments) {
|
|
458
|
+
addressComments.push(comment);
|
|
459
|
+
}
|
|
460
|
+
if (stripped.address) {
|
|
461
|
+
addressParts.push(stripped.address);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
data.address = addressParts;
|
|
373
465
|
// If no address was found, try to detect one from regular text
|
|
374
466
|
if (!data.address.length && data.text.length) {
|
|
375
467
|
for (let i = data.text.length - 1; i >= 0; i--) {
|
|
@@ -423,7 +515,13 @@ function _handleAddress(tokens, depth) {
|
|
|
423
515
|
// Join values with spaces
|
|
424
516
|
data.text = data.text.join(' ');
|
|
425
517
|
data.address = data.address.join(' ');
|
|
426
|
-
if (addressFromQuotedText && data.text) {
|
|
518
|
+
if (addressFromQuotedText && data.text.indexOf('@') >= 0) {
|
|
519
|
+
// A quoted run with no '@' in it is a display name and nothing else, so it stays
|
|
520
|
+
// where it is. Moving it over anyway made a comment the mailbox was read from:
|
|
521
|
+
// '"Display Name" <(a comment)>' handed on 'Display Name' as the address with the
|
|
522
|
+
// comment as the name, and a quoted name holding a ',' or a ';' became an address
|
|
523
|
+
// that reads as two recipients once a consumer writes it back into a header.
|
|
524
|
+
//
|
|
427
525
|
// The mailbox is still sitting in the text, so it moves over here and is quoted
|
|
428
526
|
// before the recovery below rather than after it. Anything else the text holds
|
|
429
527
|
// came along with it: a comment ends the domain but leaves the atoms behind it in
|
|
@@ -436,6 +534,10 @@ function _handleAddress(tokens, depth) {
|
|
|
436
534
|
data.text = '';
|
|
437
535
|
}
|
|
438
536
|
_recoverAddrSpec(data);
|
|
537
|
+
// a comment names the mailbox only when nothing else does, as one outside the brackets
|
|
538
|
+
if (!data.text && addressComments.length) {
|
|
539
|
+
data.text = addressComments.join(' ');
|
|
540
|
+
}
|
|
439
541
|
const address = {
|
|
440
542
|
address: data.address || data.text || '',
|
|
441
543
|
name: data.text || data.address || ''
|
|
@@ -466,6 +568,7 @@ class Tokenizer {
|
|
|
466
568
|
this.node = null;
|
|
467
569
|
this.escaped = false;
|
|
468
570
|
this.inDomainLiteral = false;
|
|
571
|
+
this.afterAt = false;
|
|
469
572
|
this.list = [];
|
|
470
573
|
/**
|
|
471
574
|
* Operator tokens and which tokens are expected to end the sequence
|
|
@@ -509,17 +612,23 @@ class Tokenizer {
|
|
|
509
612
|
* Checks if a character is an operator or text and acts accordingly
|
|
510
613
|
*
|
|
511
614
|
* @param chr Character from the address field
|
|
615
|
+
* @param nextChr Character following chr, null at the end of the field
|
|
512
616
|
*/
|
|
513
617
|
checkChar(chr, nextChr) {
|
|
514
|
-
// Track RFC 5322 domain-literals ("[" *dtext "]").
|
|
515
|
-
//
|
|
516
|
-
//
|
|
517
|
-
//
|
|
518
|
-
//
|
|
519
|
-
//
|
|
520
|
-
//
|
|
618
|
+
// Track RFC 5322 domain-literals ("[" *dtext "]"). The ":" of an IPv6
|
|
619
|
+
// address-literal (user@[IPv6:2001:db8::1]) is dtext and must not be treated as
|
|
620
|
+
// the group delimiter while inside the brackets. That is the only operator the
|
|
621
|
+
// literal hides: letting it hide the others as well meant a "[" could turn the
|
|
622
|
+
// comment, quoted string or angle-addr after it into text and pick a different
|
|
623
|
+
// mailbox, '[ ( ] <a@victim.com> ) <b@evil.com>' yielded a@victim.com where
|
|
624
|
+
// RFC 5322 reads b@evil.com. A "[" also only opens a literal right after the "@"
|
|
625
|
+
// of an addr-spec, so the group delimiter of a display name holding one stays
|
|
626
|
+
// intact. Quoted strings and comments are handled separately via
|
|
627
|
+
// operatorExpecting, so only enter this state when no operator is open. The list
|
|
628
|
+
// separators "," and ";" always end the literal (and split the address list) so
|
|
629
|
+
// that an unclosed "[" cannot swallow later recipients.
|
|
521
630
|
if (!this.escaped && !this.operatorExpecting) {
|
|
522
|
-
if (!this.inDomainLiteral && chr === '[') {
|
|
631
|
+
if (!this.inDomainLiteral && chr === '[' && this.afterAt) {
|
|
523
632
|
this.inDomainLiteral = true;
|
|
524
633
|
}
|
|
525
634
|
else if (this.inDomainLiteral && (chr === ']' || chr === ',' || chr === ';')) {
|
|
@@ -539,17 +648,24 @@ class Tokenizer {
|
|
|
539
648
|
}
|
|
540
649
|
this.list.push(this.node);
|
|
541
650
|
this.node = null;
|
|
651
|
+
if (chr !== ')') {
|
|
652
|
+
// a comment is folding whitespace, it does not part the "@" from the "["
|
|
653
|
+
this.afterAt = false;
|
|
654
|
+
}
|
|
542
655
|
this.operatorExpecting = '';
|
|
543
656
|
this.escaped = false;
|
|
544
657
|
return;
|
|
545
658
|
}
|
|
546
|
-
else if (!this.operatorExpecting && !this.inDomainLiteral && chr in this.operators) {
|
|
659
|
+
else if (!this.operatorExpecting && !(this.inDomainLiteral && chr === ':') && chr in this.operators) {
|
|
547
660
|
this.node = {
|
|
548
661
|
type: 'operator',
|
|
549
662
|
value: chr
|
|
550
663
|
};
|
|
551
664
|
this.list.push(this.node);
|
|
552
665
|
this.node = null;
|
|
666
|
+
if (chr !== '(') {
|
|
667
|
+
this.afterAt = false;
|
|
668
|
+
}
|
|
553
669
|
this.operatorExpecting = this.operators[chr];
|
|
554
670
|
this.escaped = false;
|
|
555
671
|
return;
|
|
@@ -573,6 +689,11 @@ class Tokenizer {
|
|
|
573
689
|
if (chr.charCodeAt(0) >= 0x21 || [' ', '\t'].includes(chr)) {
|
|
574
690
|
// skip command bytes
|
|
575
691
|
this.node.value += chr;
|
|
692
|
+
// text inside a quoted string or a comment is not part of an addr-spec. Tracked
|
|
693
|
+
// as it goes rather than read back off the value (see lastChars in _handleAddress)
|
|
694
|
+
if (!this.operatorExpecting && chr !== ' ' && chr !== '\t') {
|
|
695
|
+
this.afterAt = chr === '@';
|
|
696
|
+
}
|
|
576
697
|
}
|
|
577
698
|
this.escaped = false;
|
|
578
699
|
}
|
|
@@ -584,24 +705,18 @@ class Tokenizer {
|
|
|
584
705
|
*/
|
|
585
706
|
const MAX_NESTED_GROUP_DEPTH = 50;
|
|
586
707
|
/**
|
|
587
|
-
* Parses
|
|
588
|
-
*
|
|
589
|
-
* Example:
|
|
590
|
-
*
|
|
591
|
-
* 'Name <address@domain>'
|
|
708
|
+
* Parses an address list, recursing into the groups it holds.
|
|
592
709
|
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
710
|
+
* The depth is threaded through the calls rather than carried in an options object, so a
|
|
711
|
+
* caller supplied one can not seed it and lift the recursion limit: `{ _depth: -1e9 }`
|
|
712
|
+
* bought a billion levels of nesting and turned the guard below into the stack overflow it
|
|
713
|
+
* is there to prevent.
|
|
596
714
|
*
|
|
597
715
|
* @param str Address field
|
|
598
|
-
* @param
|
|
599
|
-
* @param options._depth Internal recursion depth counter (do not set manually)
|
|
716
|
+
* @param depth Current recursion depth for nested group protection
|
|
600
717
|
* @return An array of address objects
|
|
601
718
|
*/
|
|
602
|
-
function
|
|
603
|
-
options = options || {};
|
|
604
|
-
const depth = options._depth || 0;
|
|
719
|
+
function _parseAddressList(str, depth) {
|
|
605
720
|
// Prevent stack overflow from deeply nested groups (DoS protection)
|
|
606
721
|
if (depth > MAX_NESTED_GROUP_DEPTH) {
|
|
607
722
|
return [];
|
|
@@ -610,7 +725,7 @@ function addressparser(str, options) {
|
|
|
610
725
|
const tokens = tokenizer.tokenize();
|
|
611
726
|
const addresses = [];
|
|
612
727
|
let address = [];
|
|
613
|
-
|
|
728
|
+
const parsedAddresses = [];
|
|
614
729
|
tokens.forEach(token => {
|
|
615
730
|
if (token.type === 'operator' && (token.value === ',' || token.value === ';')) {
|
|
616
731
|
if (address.length) {
|
|
@@ -651,8 +766,11 @@ function addressparser(str, options) {
|
|
|
651
766
|
}
|
|
652
767
|
}
|
|
653
768
|
mergedAddresses.reverse();
|
|
654
|
-
|
|
655
|
-
|
|
769
|
+
return mergedAddresses;
|
|
770
|
+
}
|
|
771
|
+
function addressparser(str, options) {
|
|
772
|
+
const parsedAddresses = _parseAddressList(str, 0);
|
|
773
|
+
if (options?.flatten) {
|
|
656
774
|
const flatAddresses = [];
|
|
657
775
|
const walkAddressList = (list) => {
|
|
658
776
|
list.forEach(entry => {
|
|
@@ -667,5 +785,6 @@ function addressparser(str, options) {
|
|
|
667
785
|
}
|
|
668
786
|
return parsedAddresses;
|
|
669
787
|
}
|
|
788
|
+
exports.default = addressparser;
|
|
670
789
|
module.exports = exports.default;
|
|
671
790
|
Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });
|