@mavogel/awscdk-rootmail 0.1.27 → 0.1.29
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 +9 -9
- package/lib/rootmail.js +1 -1
- package/lib/ses-receive.js +1 -1
- package/node_modules/@aws-sdk/checksums/package.json +4 -4
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/CloudWatchLogsClient.d.ts +2 -1
- package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +5 -5
- package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-route-53/dist-types/Route53Client.d.ts +2 -1
- package/node_modules/@aws-sdk/client-route-53/package.json +6 -6
- package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-s3/dist-types/S3Client.d.ts +2 -1
- package/node_modules/@aws-sdk/client-s3/package.json +9 -9
- package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ses/dist-types/SESClient.d.ts +2 -1
- package/node_modules/@aws-sdk/client-ses/package.json +5 -5
- package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +1 -1
- package/node_modules/@aws-sdk/client-ssm/dist-types/SSMClient.d.ts +2 -1
- package/node_modules/@aws-sdk/client-ssm/package.json +5 -5
- package/node_modules/@aws-sdk/core/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-env/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-http/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-ini/package.json +11 -11
- package/node_modules/@aws-sdk/credential-provider-login/package.json +5 -5
- package/node_modules/@aws-sdk/credential-provider-node/package.json +9 -9
- package/node_modules/@aws-sdk/credential-provider-process/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-sso/package.json +6 -6
- package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +5 -5
- package/node_modules/@aws-sdk/middleware-sdk-route53/package.json +2 -2
- package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +5 -5
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/cognito-identity/CognitoIdentityClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/signin/SigninClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso/SSOClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso-oidc/SSOOIDCClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sts/STSClient.d.ts +2 -1
- package/node_modules/@aws-sdk/nested-clients/package.json +5 -5
- package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +2 -2
- package/node_modules/@aws-sdk/token-providers/package.json +5 -5
- package/node_modules/@aws-sdk/types/dist-types/feature-ids.d.ts +3 -0
- package/node_modules/@aws-sdk/types/dist-types/ts3.4/feature-ids.d.ts +3 -0
- package/node_modules/@aws-sdk/types/package.json +1 -1
- package/node_modules/@smithy/core/dist-cjs/submodules/client/index.js +15 -2
- package/node_modules/@smithy/core/dist-cjs/submodules/event-streams/index.browser.js +10 -0
- package/node_modules/@smithy/core/dist-cjs/submodules/event-streams/index.js +10 -0
- package/node_modules/@smithy/core/dist-cjs/submodules/protocols/index.js +5 -5
- package/node_modules/@smithy/core/dist-es/submodules/client/smithy-client/command.js +16 -2
- package/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js +10 -0
- package/node_modules/@smithy/core/dist-es/submodules/protocols/json/codec-v2/JsonShapeSerializer2.js +5 -5
- package/node_modules/@smithy/core/package.json +1 -1
- package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +39 -27
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.d.ts +1 -1
- package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +38 -61
- package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +1 -1
- package/node_modules/@zone-eu/mailsplit/package.json +2 -2
- package/node_modules/libmime/CHANGELOG.md +36 -0
- package/node_modules/libmime/README.md +40 -3
- package/node_modules/libmime/dist/cjs/charset.d.ts +36 -0
- package/node_modules/libmime/dist/cjs/charset.js +165 -2
- package/node_modules/libmime/dist/cjs/charsets.js +8 -2
- package/node_modules/libmime/dist/cjs/libmime.d.ts +20 -3
- package/node_modules/libmime/dist/cjs/libmime.js +100 -6
- package/node_modules/libmime/dist/cjs/types.d.ts +28 -0
- package/node_modules/libmime/dist/esm/charset.d.ts +36 -0
- package/node_modules/libmime/dist/esm/charset.js +162 -2
- package/node_modules/libmime/dist/esm/charsets.js +8 -2
- package/node_modules/libmime/dist/esm/libmime.d.ts +20 -3
- package/node_modules/libmime/dist/esm/libmime.js +100 -6
- package/node_modules/libmime/dist/esm/types.d.ts +28 -0
- package/node_modules/libmime/package.json +3 -3
- package/node_modules/mailparser/CHANGELOG.md +51 -0
- package/node_modules/mailparser/README.md +32 -1
- package/node_modules/mailparser/dist/cjs/address-header.d.ts +19 -0
- package/node_modules/mailparser/dist/cjs/address-header.js +185 -0
- package/node_modules/mailparser/dist/cjs/index.d.ts +3 -1
- package/node_modules/mailparser/dist/cjs/index.js +4 -2
- package/node_modules/mailparser/dist/cjs/mail-parser.js +36 -183
- package/node_modules/mailparser/dist/cjs/stream-hash.d.ts +5 -4
- package/node_modules/mailparser/dist/cjs/stream-hash.js +8 -5
- package/node_modules/mailparser/dist/cjs/types.d.ts +33 -6
- package/node_modules/mailparser/dist/esm/address-header.d.ts +19 -0
- package/node_modules/mailparser/dist/esm/address-header.js +176 -0
- package/node_modules/mailparser/dist/esm/index.d.ts +3 -1
- package/node_modules/mailparser/dist/esm/index.js +3 -2
- package/node_modules/mailparser/dist/esm/mail-parser.js +36 -183
- package/node_modules/mailparser/dist/esm/stream-hash.d.ts +5 -4
- package/node_modules/mailparser/dist/esm/stream-hash.js +8 -5
- package/node_modules/mailparser/dist/esm/types.d.ts +33 -6
- package/node_modules/mailparser/package.json +6 -7
- package/node_modules/nodemailer/CHANGELOG.md +23 -0
- package/node_modules/nodemailer/dist/cjs/addressparser/index.js +2 -5
- package/node_modules/nodemailer/dist/cjs/dkim/index.js +1 -3
- package/node_modules/nodemailer/dist/cjs/errors.d.ts +19 -0
- package/node_modules/nodemailer/dist/cjs/errors.js +14 -1
- package/node_modules/nodemailer/dist/cjs/fetch/cookies.js +2 -4
- package/node_modules/nodemailer/dist/cjs/fetch/index.js +2 -8
- package/node_modules/nodemailer/dist/cjs/mail-composer/index.js +42 -9
- package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +5 -6
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +18 -1
- package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +43 -1
- package/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +3 -12
- package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +34 -1
- package/node_modules/nodemailer/dist/cjs/mime-node/index.js +40 -15
- 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/qp/index.js +3 -12
- package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +1 -3
- package/node_modules/nodemailer/dist/cjs/shared/index.js +2 -6
- package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +1 -1
- package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +6 -0
- package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +15 -12
- package/node_modules/nodemailer/dist/cjs/smtp-connection/server-message-id.d.ts +14 -0
- package/node_modules/nodemailer/dist/cjs/smtp-connection/server-message-id.js +53 -0
- package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +11 -0
- package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +25 -1
- package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +2 -5
- package/node_modules/nodemailer/dist/esm/addressparser/index.js +2 -5
- package/node_modules/nodemailer/dist/esm/dkim/index.js +1 -3
- package/node_modules/nodemailer/dist/esm/errors.d.ts +19 -0
- package/node_modules/nodemailer/dist/esm/errors.js +12 -0
- package/node_modules/nodemailer/dist/esm/fetch/cookies.js +2 -4
- package/node_modules/nodemailer/dist/esm/fetch/index.js +2 -8
- package/node_modules/nodemailer/dist/esm/mail-composer/index.js +42 -9
- package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +5 -6
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +18 -1
- package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +43 -1
- package/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.js +3 -12
- package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +34 -1
- package/node_modules/nodemailer/dist/esm/mime-node/index.js +40 -15
- 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/qp/index.js +3 -12
- package/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +1 -3
- package/node_modules/nodemailer/dist/esm/shared/index.js +2 -6
- package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +1 -1
- package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +6 -0
- package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +16 -13
- package/node_modules/nodemailer/dist/esm/smtp-connection/server-message-id.d.ts +14 -0
- package/node_modules/nodemailer/dist/esm/smtp-connection/server-message-id.js +50 -0
- package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +11 -0
- package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +25 -1
- package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +2 -5
- package/node_modules/nodemailer/package.json +11 -9
- package/package.json +8 -8
- package/node_modules/mailparser/node_modules/iconv-lite/LICENSE +0 -21
- package/node_modules/mailparser/node_modules/iconv-lite/README.md +0 -138
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/dbcs-codec.js +0 -532
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/dbcs-data.js +0 -185
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/index.js +0 -23
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/internal.js +0 -218
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-codec.js +0 -75
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-data-generated.js +0 -451
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-data.js +0 -180
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/big5-added.json +0 -122
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp936.json +0 -264
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp949.json +0 -273
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp950.json +0 -177
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/eucjp.json +0 -182
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +0 -1
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/gbk-added.json +0 -56
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/shiftjis.json +0 -125
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf16.js +0 -187
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf32.js +0 -314
- package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf7.js +0 -283
- package/node_modules/mailparser/node_modules/iconv-lite/lib/bom-handling.js +0 -48
- package/node_modules/mailparser/node_modules/iconv-lite/lib/helpers/merge-exports.js +0 -13
- package/node_modules/mailparser/node_modules/iconv-lite/lib/index.d.ts +0 -129
- package/node_modules/mailparser/node_modules/iconv-lite/lib/index.js +0 -182
- package/node_modules/mailparser/node_modules/iconv-lite/lib/streams.js +0 -105
- package/node_modules/mailparser/node_modules/iconv-lite/package.json +0 -70
- package/node_modules/mailparser/node_modules/iconv-lite/types/encodings.d.ts +0 -425
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import mailsplit from '@zone-eu/mailsplit';
|
|
2
2
|
import FlowedDecoder from '@zone-eu/mailsplit/lib/flowed-decoder.js';
|
|
3
|
-
import encodingJapanese from 'encoding-japanese';
|
|
4
3
|
import he from 'he';
|
|
5
4
|
import { htmlToText } from 'html-to-text';
|
|
6
|
-
import iconv from 'iconv-lite';
|
|
7
5
|
import libmime from 'libmime';
|
|
8
6
|
import linkifyIt from 'linkify-it';
|
|
9
7
|
import addressparser from 'nodemailer/lib/addressparser';
|
|
10
|
-
import punycode from 'punycode.js';
|
|
11
8
|
import { Transform } from 'node:stream';
|
|
12
9
|
import tlds from './tlds.cjs';
|
|
13
10
|
import StreamHash from './stream-hash.js';
|
|
11
|
+
import { decodeAddresses, formatAddressesHTML, formatAddressesText } from './address-header.js';
|
|
14
12
|
const { Splitter, ChunkedPassthrough } = mailsplit;
|
|
15
13
|
// Bounds for link detection in text bodies. Message content is untrusted and
|
|
16
14
|
// linkify-it backtracks heavily on crafted input: matching a host is quadratic
|
|
@@ -72,49 +70,6 @@ linkify.add('@', {
|
|
|
72
70
|
match.url = 'https://twitter.com/' + match.url.replace(/^@/, '');
|
|
73
71
|
}
|
|
74
72
|
});
|
|
75
|
-
// Lists the parameters a header value gives in RFC 2231 form (name*=, name*0= or
|
|
76
|
-
// name*0*=). libmime decodes those while parsing the header, so the result must not go
|
|
77
|
-
// through decodeWords as well: filename*=utf-8''a%3D%3Futf-8%3FQ%3F%3D2Eexe%3F%3D would
|
|
78
|
-
// otherwise come out as "a.exe" while a parser that decodes once sees the encoded word.
|
|
79
|
-
function rfc2231ParamNames(value) {
|
|
80
|
-
let names = new Set();
|
|
81
|
-
let quote = false;
|
|
82
|
-
let escaped = false;
|
|
83
|
-
let start = 0;
|
|
84
|
-
let addSegment = (end) => {
|
|
85
|
-
let segment = value.substring(start, end);
|
|
86
|
-
let eq = segment.indexOf('=');
|
|
87
|
-
if (eq < 0) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
let match = segment
|
|
91
|
-
.substring(0, eq)
|
|
92
|
-
.trim()
|
|
93
|
-
.toLowerCase()
|
|
94
|
-
.match(/^(.+?)\*(\d+\*?)?$/);
|
|
95
|
-
if (match) {
|
|
96
|
-
names.add(match[1]);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
for (let i = 0; i < value.length; i++) {
|
|
100
|
-
let chr = value.charAt(i);
|
|
101
|
-
if (escaped) {
|
|
102
|
-
escaped = false;
|
|
103
|
-
}
|
|
104
|
-
else if (chr === '\\') {
|
|
105
|
-
escaped = true;
|
|
106
|
-
}
|
|
107
|
-
else if (chr === '"') {
|
|
108
|
-
quote = !quote;
|
|
109
|
-
}
|
|
110
|
-
else if (chr === ';' && !quote) {
|
|
111
|
-
addSegment(i);
|
|
112
|
-
start = i + 1;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
addSegment(value.length);
|
|
116
|
-
return names;
|
|
117
|
-
}
|
|
118
73
|
// Deepest element nesting html-to-text is asked to convert. htmlparser2 keeps its open
|
|
119
74
|
// element stack at the front of an array, so parsing alone is quadratic in the nesting
|
|
120
75
|
// depth (200k nested <b> took 9 s), and html-to-text's recursive walk overflows the call
|
|
@@ -184,6 +139,14 @@ function exceedsHtmlNestingDepth(html, maxDepth) {
|
|
|
184
139
|
}
|
|
185
140
|
return false;
|
|
186
141
|
}
|
|
142
|
+
// Charsets a body is never decoded from, matched the way iconv-lite and node-iconv compare names
|
|
143
|
+
// (case and punctuation ignored). UTF-7 can carry markup past a filter that looks for "<" (a body
|
|
144
|
+
// of +ADw-script+AD4- decodes to <script>), base64 and hex are transfer encodings. libmime's decode
|
|
145
|
+
// stream refuses the same names, this check applies the refusal to the native Iconv option as well
|
|
146
|
+
const REFUSED_CHARSET = /^(?:(?:cs)?unicode11)?utf7(?:imap)?$|^base64$|^hex$/;
|
|
147
|
+
function isRefusedCharset(charset) {
|
|
148
|
+
return REFUSED_CHARSET.test((charset || '').toLowerCase().replace(/[^a-z0-9]/g, ''));
|
|
149
|
+
}
|
|
187
150
|
class IconvDecoder extends Transform {
|
|
188
151
|
constructor(Iconv, charset) {
|
|
189
152
|
super();
|
|
@@ -213,41 +176,6 @@ class IconvDecoder extends Transform {
|
|
|
213
176
|
this.stream.end();
|
|
214
177
|
}
|
|
215
178
|
}
|
|
216
|
-
class JPDecoder extends Transform {
|
|
217
|
-
constructor(charset) {
|
|
218
|
-
super();
|
|
219
|
-
this.charset = charset;
|
|
220
|
-
this.chunks = [];
|
|
221
|
-
this.chunklen = 0;
|
|
222
|
-
}
|
|
223
|
-
_transform(chunk, encoding, done) {
|
|
224
|
-
if (typeof chunk === 'string') {
|
|
225
|
-
chunk = Buffer.from(chunk, encoding);
|
|
226
|
-
}
|
|
227
|
-
this.chunks.push(chunk);
|
|
228
|
-
this.chunklen += chunk.length;
|
|
229
|
-
done();
|
|
230
|
-
}
|
|
231
|
-
_flush(done) {
|
|
232
|
-
let input = Buffer.concat(this.chunks, this.chunklen);
|
|
233
|
-
try {
|
|
234
|
-
let output = encodingJapanese.convert(input, {
|
|
235
|
-
to: 'UNICODE', // to_encoding
|
|
236
|
-
from: this.charset, // from_encoding
|
|
237
|
-
type: 'string'
|
|
238
|
-
});
|
|
239
|
-
if (typeof output === 'string') {
|
|
240
|
-
output = Buffer.from(output);
|
|
241
|
-
}
|
|
242
|
-
this.push(output);
|
|
243
|
-
}
|
|
244
|
-
catch {
|
|
245
|
-
// keep as is on errors
|
|
246
|
-
this.push(input);
|
|
247
|
-
}
|
|
248
|
-
done();
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
179
|
/**
|
|
252
180
|
* A lower level, streaming e-mail parser. It is a Transform stream: write the raw message in and
|
|
253
181
|
* read the parsed content out. It emits:
|
|
@@ -323,6 +251,10 @@ class MailParser extends Transform {
|
|
|
323
251
|
// create wrapper
|
|
324
252
|
return {
|
|
325
253
|
decodeStream(charset) {
|
|
254
|
+
if (isRefusedCharset(charset)) {
|
|
255
|
+
// the same refusal as without the Iconv option, see below
|
|
256
|
+
return libmime.createDecodeStream(charset);
|
|
257
|
+
}
|
|
326
258
|
// node-iconv resolves its own charset aliases and needs charset-specific
|
|
327
259
|
// fixups (see IconvDecoder, eg. ks_c_5601-1987), so pass the charset through as is
|
|
328
260
|
return new IconvDecoder(Iconv, charset);
|
|
@@ -332,13 +264,12 @@ class MailParser extends Transform {
|
|
|
332
264
|
else {
|
|
333
265
|
return {
|
|
334
266
|
decodeStream(charset) {
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
return iconv.decodeStream(charset);
|
|
267
|
+
// libmime resolves charset aliases (eg. iso-8859-8-i -> ISO-8859-8), decodes the
|
|
268
|
+
// Japanese charsets iconv-lite lacks and keeps a multibyte character split across
|
|
269
|
+
// chunks intact. A charset it does not know or refuses (UTF-7, which would turn
|
|
270
|
+
// +ADw-script+AD4- into <script>, and the base64 and hex transfer encodings) is
|
|
271
|
+
// decoded as UTF-8 with invalid bytes replaced, the same as encoded words get
|
|
272
|
+
return libmime.createDecodeStream(charset || 'ascii');
|
|
342
273
|
}
|
|
343
274
|
};
|
|
344
275
|
}
|
|
@@ -441,9 +372,18 @@ class MailParser extends Transform {
|
|
|
441
372
|
case 'content-type':
|
|
442
373
|
case 'content-disposition':
|
|
443
374
|
case 'dkim-signature': {
|
|
444
|
-
// a
|
|
445
|
-
|
|
446
|
-
|
|
375
|
+
// The comments of a MIME header are not part of its value, so they are
|
|
376
|
+
// dropped as mailsplit drops them for the structure: `boundary=b (comment)`
|
|
377
|
+
// names the boundary `b`. A DKIM-Signature is a tag list without comment
|
|
378
|
+
// syntax, so a parenthesis in a tag value is data
|
|
379
|
+
value = this.libmime.parseHeaderValue(value, { stripComments: key !== 'dkim-signature' });
|
|
380
|
+
// A parameter given in RFC 2231 form was decoded by parseHeaderValue already,
|
|
381
|
+
// which names it in decodedParams, and must not go through decodeWords as
|
|
382
|
+
// well: filename*=utf-8''a%3D%3Futf-8%3FQ%3F%3D2Eexe%3F%3D would otherwise come
|
|
383
|
+
// out as a.exe while a parser that decodes once sees the encoded word. A
|
|
384
|
+
// second scan of the raw header for the name used to decide this, and read
|
|
385
|
+
// `(c)filename*=` as `(c)filename` once the comment was dropped from the real one
|
|
386
|
+
let rfc2231 = new Set(value.decodedParams);
|
|
447
387
|
if (value.value) {
|
|
448
388
|
value.value = this.libmime.decodeWords(value.value);
|
|
449
389
|
}
|
|
@@ -676,52 +616,7 @@ class MailParser extends Transform {
|
|
|
676
616
|
}
|
|
677
617
|
/** @internal */
|
|
678
618
|
decodeAddresses(addresses) {
|
|
679
|
-
|
|
680
|
-
let address = addresses[i];
|
|
681
|
-
address.name = (address.name || '').toString().trim();
|
|
682
|
-
// An encoded word decodes into the display name and nothing else, whatever it
|
|
683
|
-
// decodes to. RFC 2047 section 5 keeps encoded words out of the addr-spec, so a
|
|
684
|
-
// name that decodes to "CEO" <ceo@bank.com> is still only a name: parsing it
|
|
685
|
-
// again would report an address the header never carried
|
|
686
|
-
if (address.name) {
|
|
687
|
-
try {
|
|
688
|
-
address.name = this.libmime.decodeWords(address.name);
|
|
689
|
-
}
|
|
690
|
-
catch {
|
|
691
|
-
//ignore, keep as is
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
// Security fix: detect RFC 2047 encoded-words in the address field.
|
|
695
|
-
// Per RFC 2047 Section 5, encoded-words MUST NOT appear in addr-spec.
|
|
696
|
-
// If found, decode and validate; reject if result is not a simple local@domain.
|
|
697
|
-
if (address.address && /[=]\?[^?]+\?[BbQq]\?[^?]*\?[=]/.test(address.address)) {
|
|
698
|
-
try {
|
|
699
|
-
let decodedAddr = this.libmime.decodeWords(address.address);
|
|
700
|
-
if (/^[^\s@]+@[^\s@]+$/.test(decodedAddr) && !/[=]\?/.test(decodedAddr)) {
|
|
701
|
-
address.address = decodedAddr;
|
|
702
|
-
}
|
|
703
|
-
else {
|
|
704
|
-
address.address = '';
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
catch {
|
|
708
|
-
address.address = '';
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
if (address.address && /@xn--/.test(address.address)) {
|
|
712
|
-
try {
|
|
713
|
-
address.address =
|
|
714
|
-
address.address.slice(0, address.address.lastIndexOf('@') + 1) +
|
|
715
|
-
punycode.toUnicode(address.address.slice(address.address.lastIndexOf('@') + 1));
|
|
716
|
-
}
|
|
717
|
-
catch {
|
|
718
|
-
// Not a valid punycode string; keep as is
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
if (address.group) {
|
|
722
|
-
this.decodeAddresses(address.group);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
619
|
+
decodeAddresses(addresses, this.libmime);
|
|
725
620
|
}
|
|
726
621
|
/** @internal */
|
|
727
622
|
createNode(node) {
|
|
@@ -1003,7 +898,8 @@ class MailParser extends Transform {
|
|
|
1003
898
|
this.waitUntilAttachmentEnd = false;
|
|
1004
899
|
}
|
|
1005
900
|
};
|
|
1006
|
-
|
|
901
|
+
// false skips hashing, checksum is then left unset
|
|
902
|
+
let algo = this.options.checksumAlgo === false ? false : this.options.checksumAlgo || 'md5';
|
|
1007
903
|
let hasher;
|
|
1008
904
|
try {
|
|
1009
905
|
hasher = new StreamHash(attachment, algo);
|
|
@@ -1156,56 +1052,13 @@ class MailParser extends Transform {
|
|
|
1156
1052
|
* Formats parsed addresses for an HTML context, every value HTML-escaped.
|
|
1157
1053
|
*/
|
|
1158
1054
|
getAddressesHTML(value) {
|
|
1159
|
-
|
|
1160
|
-
.map(address => {
|
|
1161
|
-
let str = '<span class="mp_address_group">';
|
|
1162
|
-
if (address.name) {
|
|
1163
|
-
str += '<span class="mp_address_name">' + he.encode(address.name) + (address.group ? ': ' : '') + '</span>';
|
|
1164
|
-
}
|
|
1165
|
-
if (address.address) {
|
|
1166
|
-
let link = '<a href="mailto:' + he.encode(address.address) + '" class="mp_address_email">' + he.encode(address.address) + '</a>';
|
|
1167
|
-
if (address.name) {
|
|
1168
|
-
str += ' <' + link + '>';
|
|
1169
|
-
}
|
|
1170
|
-
else {
|
|
1171
|
-
str += link;
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
if (address.group) {
|
|
1175
|
-
str += formatSingleLevel(address.group) + ';';
|
|
1176
|
-
}
|
|
1177
|
-
return str + '</span>';
|
|
1178
|
-
})
|
|
1179
|
-
.join(', ');
|
|
1180
|
-
return formatSingleLevel([].concat(value || []));
|
|
1055
|
+
return formatAddressesHTML(value);
|
|
1181
1056
|
}
|
|
1182
1057
|
/**
|
|
1183
1058
|
* Formats parsed addresses as plain text, display names quoted.
|
|
1184
1059
|
*/
|
|
1185
1060
|
getAddressesText(value) {
|
|
1186
|
-
|
|
1187
|
-
.map(address => {
|
|
1188
|
-
let str = '';
|
|
1189
|
-
if (address.name) {
|
|
1190
|
-
// a quoted-string, so a quote or backslash inside the name is escaped
|
|
1191
|
-
str += `"${address.name.replace(/["\\]/g, '\\$&')}"` + (address.group ? ': ' : '');
|
|
1192
|
-
}
|
|
1193
|
-
if (address.address) {
|
|
1194
|
-
let link = address.address;
|
|
1195
|
-
if (address.name) {
|
|
1196
|
-
str += ' <' + link + '>';
|
|
1197
|
-
}
|
|
1198
|
-
else {
|
|
1199
|
-
str += link;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
if (address.group) {
|
|
1203
|
-
str += formatSingleLevel(address.group) + ';';
|
|
1204
|
-
}
|
|
1205
|
-
return str;
|
|
1206
|
-
})
|
|
1207
|
-
.join(', ');
|
|
1208
|
-
return formatSingleLevel([].concat(value || []));
|
|
1061
|
+
return formatAddressesText(value);
|
|
1209
1062
|
}
|
|
1210
1063
|
/**
|
|
1211
1064
|
* Replaces `cid:` links to image attachments in the HTML content. Call it once the parser has
|
|
@@ -10,14 +10,15 @@ export interface HashTarget {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* A pass-through stream that records the checksum and byte size of what flows through it on the
|
|
13
|
-
* given object once the stream ends. Throws when the hash algorithm is not available.
|
|
13
|
+
* given object once the stream ends. Throws when the hash algorithm is not available. With `algo`
|
|
14
|
+
* set to `false` nothing is hashed and only the size is recorded.
|
|
14
15
|
*/
|
|
15
16
|
declare class StreamHash extends Transform {
|
|
16
17
|
attachment: HashTarget;
|
|
17
|
-
algo: string;
|
|
18
|
-
hash: crypto.Hash;
|
|
18
|
+
algo: string | false;
|
|
19
|
+
hash: crypto.Hash | null;
|
|
19
20
|
byteCount: number;
|
|
20
|
-
constructor(attachment: HashTarget, algo?: string);
|
|
21
|
+
constructor(attachment: HashTarget, algo?: string | false);
|
|
21
22
|
_transform(chunk: Buffer, encoding: BufferEncoding, done: TransformCallback): void;
|
|
22
23
|
_flush(done: TransformCallback): void;
|
|
23
24
|
}
|
|
@@ -2,23 +2,26 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import { Transform } from 'node:stream';
|
|
3
3
|
/**
|
|
4
4
|
* A pass-through stream that records the checksum and byte size of what flows through it on the
|
|
5
|
-
* given object once the stream ends. Throws when the hash algorithm is not available.
|
|
5
|
+
* given object once the stream ends. Throws when the hash algorithm is not available. With `algo`
|
|
6
|
+
* set to `false` nothing is hashed and only the size is recorded.
|
|
6
7
|
*/
|
|
7
8
|
class StreamHash extends Transform {
|
|
8
9
|
constructor(attachment, algo) {
|
|
9
10
|
super();
|
|
10
11
|
this.attachment = attachment;
|
|
11
|
-
this.algo = (algo || 'md5').toLowerCase();
|
|
12
|
-
this.hash = crypto.createHash(this.algo);
|
|
12
|
+
this.algo = algo === false ? false : (algo || 'md5').toLowerCase();
|
|
13
|
+
this.hash = this.algo === false ? null : crypto.createHash(this.algo);
|
|
13
14
|
this.byteCount = 0;
|
|
14
15
|
}
|
|
15
16
|
_transform(chunk, encoding, done) {
|
|
16
|
-
this.hash
|
|
17
|
+
this.hash?.update(chunk);
|
|
17
18
|
this.byteCount += chunk.length;
|
|
18
19
|
done(null, chunk);
|
|
19
20
|
}
|
|
20
21
|
_flush(done) {
|
|
21
|
-
|
|
22
|
+
if (this.hash) {
|
|
23
|
+
this.attachment.checksum = this.hash.digest('hex');
|
|
24
|
+
}
|
|
22
25
|
this.attachment.size = this.byteCount;
|
|
23
26
|
done();
|
|
24
27
|
}
|
|
@@ -37,6 +37,24 @@ export interface AddressObject {
|
|
|
37
37
|
/** The addresses formatted as plain text, display names quoted. */
|
|
38
38
|
text: string;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Options for `parseAddressHeader`.
|
|
42
|
+
*/
|
|
43
|
+
export interface ParseAddressHeaderOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Replace every group with its members, so the result lists mailboxes only and the group names
|
|
46
|
+
* are dropped.
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
flatten?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Decode an internationalized (punycode) domain to Unicode. Set to false to keep the domain as
|
|
52
|
+
* it appears in the header, for an address that is going to be used to send mail, such as an
|
|
53
|
+
* SMTP envelope, where the ASCII form is the one every server accepts.
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
decodePunycode?: boolean;
|
|
57
|
+
}
|
|
40
58
|
/**
|
|
41
59
|
* One entry of the combined `list` header, built from a `List-*` header such as `List-Unsubscribe`.
|
|
42
60
|
*/
|
|
@@ -122,7 +140,10 @@ export interface AttachmentStream extends AttachmentCommon {
|
|
|
122
140
|
* message. Must be called for every attachment. Set to `null` once called.
|
|
123
141
|
*/
|
|
124
142
|
release: (() => void) | null;
|
|
125
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* The hex encoded checksum of the content (md5 unless `checksumAlgo` says otherwise). Set once
|
|
145
|
+
* `content` has ended, never when `checksumAlgo` is `false`.
|
|
146
|
+
*/
|
|
126
147
|
checksum?: string;
|
|
127
148
|
/** The size of the decoded content in bytes. Set once `content` has ended. */
|
|
128
149
|
size?: number;
|
|
@@ -135,7 +156,11 @@ export interface Attachment extends AttachmentCommon {
|
|
|
135
156
|
content: Buffer;
|
|
136
157
|
/** Always `null`, `simpleParser` has released the attachment already. */
|
|
137
158
|
release: null;
|
|
138
|
-
/**
|
|
159
|
+
/**
|
|
160
|
+
* The hex encoded checksum of the content (md5 unless `checksumAlgo` says otherwise). Not set when
|
|
161
|
+
* `checksumAlgo` is `false`: the type keeps it a string so code written for the default does not
|
|
162
|
+
* have to check it, so a caller that turns hashing off must not read it.
|
|
163
|
+
*/
|
|
139
164
|
checksum: string;
|
|
140
165
|
/** The size of the decoded content in bytes. */
|
|
141
166
|
size: number;
|
|
@@ -211,16 +236,18 @@ export interface MailParserOptions {
|
|
|
211
236
|
*/
|
|
212
237
|
keepDeliveryStatus?: boolean;
|
|
213
238
|
/**
|
|
214
|
-
* Decode character sets with the native `iconv` module instead of
|
|
215
|
-
* `Iconv` class: `{ Iconv: require('iconv').Iconv }`.
|
|
239
|
+
* Decode the character sets of text bodies with the native `iconv` module instead of libmime's
|
|
240
|
+
* decoder (`iconv-lite`). Pass the `Iconv` class: `{ Iconv: require('iconv').Iconv }`. Bodies
|
|
241
|
+
* declared as UTF-7 are never decoded from it either way, see the note on charsets in the README.
|
|
216
242
|
*/
|
|
217
243
|
Iconv?: IconvConstructor;
|
|
218
244
|
/**
|
|
219
245
|
* The hash algorithm for attachment checksums, any name `crypto.createHash()` accepts. An algorithm
|
|
220
|
-
* that is not available makes the parser emit an error.
|
|
246
|
+
* that is not available makes the parser emit an error. `false` skips hashing attachments
|
|
247
|
+
* altogether, and their `checksum` is then not set (`size` still is).
|
|
221
248
|
* @default 'md5'
|
|
222
249
|
*/
|
|
223
|
-
checksumAlgo?: string;
|
|
250
|
+
checksumAlgo?: string | false;
|
|
224
251
|
/**
|
|
225
252
|
* The longest the URLs `updateImageLinks()` writes into the HTML may be in total, in characters.
|
|
226
253
|
* References past the limit are left as `cid:` links.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailparser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.4",
|
|
4
4
|
"description": "Parse e-mails",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -92,14 +92,12 @@
|
|
|
92
92
|
],
|
|
93
93
|
"license": "MIT",
|
|
94
94
|
"dependencies": {
|
|
95
|
-
"@zone-eu/mailsplit": "5.4.
|
|
96
|
-
"encoding-japanese": "2.4.0",
|
|
95
|
+
"@zone-eu/mailsplit": "5.4.29",
|
|
97
96
|
"he": "1.2.0",
|
|
98
97
|
"html-to-text": "10.0.1",
|
|
99
|
-
"
|
|
100
|
-
"libmime": "5.5.2",
|
|
98
|
+
"libmime": "5.6.3",
|
|
101
99
|
"linkify-it": "5.0.2",
|
|
102
|
-
"nodemailer": "10.1
|
|
100
|
+
"nodemailer": "10.2.1",
|
|
103
101
|
"punycode.js": "2.3.1",
|
|
104
102
|
"tlds": "1.261.0"
|
|
105
103
|
},
|
|
@@ -110,10 +108,11 @@
|
|
|
110
108
|
"eslint-config-prettier": "10.1.8",
|
|
111
109
|
"globals": "17.13.0",
|
|
112
110
|
"iconv": "3.0.1",
|
|
111
|
+
"iconv-lite": "0.7.3",
|
|
113
112
|
"prettier": "3.9.10",
|
|
114
113
|
"tsx": "4.23.15",
|
|
115
114
|
"typescript": "6.0.3",
|
|
116
|
-
"typescript-eslint": "8.
|
|
115
|
+
"typescript-eslint": "8.72.0"
|
|
117
116
|
},
|
|
118
117
|
"repository": {
|
|
119
118
|
"type": "git",
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [10.2.1](https://github.com/nodemailer/nodemailer/compare/v10.2.0...v10.2.1) (2026-10-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* drop the comments of a Content-Type or Content-Disposition value with the stripComments option ([b3052b7](https://github.com/nodemailer/nodemailer/commit/b3052b7fe2e49b51dd66d6c7814a072e885f1ac8))
|
|
9
|
+
|
|
10
|
+
## [10.2.0](https://github.com/nodemailer/nodemailer/compare/v10.1.7...v10.2.0) (2026-10-21)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add info.serverMessageId from the final 250 reply ([108dddd](https://github.com/nodemailer/nodemailer/commit/108dddd88d9d71f708630b7aba7fa2a7d2f14076))
|
|
16
|
+
* add pendingCount() to the SMTP pool ([6cffb70](https://github.com/nodemailer/nodemailer/commit/6cffb7037269a6012d992c263a8927fcaf0563f2))
|
|
17
|
+
* make header value encoding public with MimeNode encodeHeaderValue() ([3b048c7](https://github.com/nodemailer/nodemailer/commit/3b048c7a0fb60f946985b09b3143b0680194e47b))
|
|
18
|
+
* mark SMTP errors as permanent or transient with err.permanent ([6a20e2a](https://github.com/nodemailer/nodemailer/commit/6a20e2ae109eeb5662235d72d1e5a2d38515997a))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* label an ASCII message/rfc822 attachment 7bit instead of 8bit ([ad66fa1](https://github.com/nodemailer/nodemailer/commit/ad66fa1a048135867a629bcb7b6dc308ee06a945))
|
|
24
|
+
* report the recipients an LMTP server refuses after DATA in rejectedErrors ([dd64eb3](https://github.com/nodemailer/nodemailer/commit/dd64eb3171e3ab5629828084d3944a7859790968))
|
|
25
|
+
|
|
3
26
|
## [10.1.7](https://github.com/nodemailer/nodemailer/compare/v10.1.6...v10.1.7) (2026-10-18)
|
|
4
27
|
|
|
5
28
|
|
|
@@ -693,9 +693,7 @@ function _handleAddress(tokens, from, to) {
|
|
|
693
693
|
// A run that is a quoted local part with its '@' and domain is an addr-spec of
|
|
694
694
|
// its own, with the quoting put back on, and takes its turn like any other
|
|
695
695
|
const local = data.quotedLocalAt[i];
|
|
696
|
-
const quotedLocal = data.textWasQuoted[i] && local >= 0 && QUOTED_LOCAL_DOMAIN.test(data.text[i].slice(local))
|
|
697
|
-
? _quoteLocalPart(data.text[i])
|
|
698
|
-
: '';
|
|
696
|
+
const quotedLocal = data.textWasQuoted[i] && local >= 0 && QUOTED_LOCAL_DOMAIN.test(data.text[i].slice(local)) ? _quoteLocalPart(data.text[i]) : '';
|
|
699
697
|
if (quotedLocal || (!data.textWasQuoted[i] && _isAddrSpec(candidates[i]))) {
|
|
700
698
|
data.address = [quotedLocal || candidates[i]];
|
|
701
699
|
data.text.splice(i, 1);
|
|
@@ -1020,8 +1018,7 @@ class Tokenizer {
|
|
|
1020
1018
|
return;
|
|
1021
1019
|
}
|
|
1022
1020
|
if (this.node < 0) {
|
|
1023
|
-
this.node = this.list.push((this.operatorExpecting === '"' || this.operatorExpecting === ')' ? TOKEN_ESCAPES : 0) |
|
|
1024
|
-
(this.escaped ? TOKEN_STARTS_ESCAPED : 0), i, i);
|
|
1021
|
+
this.node = this.list.push((this.operatorExpecting === '"' || this.operatorExpecting === ')' ? TOKEN_ESCAPES : 0) | (this.escaped ? TOKEN_STARTS_ESCAPED : 0), i, i);
|
|
1025
1022
|
}
|
|
1026
1023
|
if (chr === '\n') {
|
|
1027
1024
|
// Convert newlines to spaces. Carriage return is ignored as \r and \n usually
|
|
@@ -25,9 +25,7 @@ class DKIMSigner {
|
|
|
25
25
|
this.chunks = [];
|
|
26
26
|
this.chunklen = 0;
|
|
27
27
|
this.readPos = 0;
|
|
28
|
-
this.cachePath = this.cacheDir
|
|
29
|
-
? node_path_1.default.join(this.cacheDir, 'message.' + Date.now() + '-' + node_crypto_1.default.randomBytes(14).toString('hex'))
|
|
30
|
-
: false;
|
|
28
|
+
this.cachePath = this.cacheDir ? node_path_1.default.join(this.cacheDir, 'message.' + Date.now() + '-' + node_crypto_1.default.randomBytes(14).toString('hex')) : false;
|
|
31
29
|
this.cache = false;
|
|
32
30
|
this.headers = false;
|
|
33
31
|
this.bodyHash = false;
|
|
@@ -68,6 +68,18 @@ export declare const isTransientError: (err: {
|
|
|
68
68
|
code?: string | undefined;
|
|
69
69
|
responseCode?: number | undefined;
|
|
70
70
|
}) => boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Tells whether an SMTP reply code is a permanent rejection, one that retrying the same
|
|
73
|
+
* message would get again. RFC 5321 makes every 5yz reply a permanent negative completion
|
|
74
|
+
* and every 4yz reply a transient one. 503 (bad sequence of commands) is the exception: it
|
|
75
|
+
* says the session was in the wrong state for the command rather than that the message was
|
|
76
|
+
* refused, so the same message can go through on a new connection. 2yz and 3yz replies are
|
|
77
|
+
* only an error when the client expected something else, and are not permanent either.
|
|
78
|
+
*
|
|
79
|
+
* @param responseCode SMTP reply code
|
|
80
|
+
* @returns true for a permanent rejection
|
|
81
|
+
*/
|
|
82
|
+
export declare const isPermanentResponseCode: (responseCode: number) => boolean;
|
|
71
83
|
/**
|
|
72
84
|
* Code Node.js sets on an error when its permission model (`--permission`) denies an
|
|
73
85
|
* operation. It is not replaced with the Nodemailer code of the failing step (`ESOCKET`,
|
|
@@ -89,6 +101,13 @@ export interface NodemailerError extends NodeJS.ErrnoException {
|
|
|
89
101
|
response?: string | undefined;
|
|
90
102
|
/** Numeric SMTP response code */
|
|
91
103
|
responseCode?: number | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Set together with responseCode, from the reply class: true when the server rejected the
|
|
106
|
+
* message for good (5xx except 503), false when the same message may be accepted on a later
|
|
107
|
+
* attempt (4xx, 503, or an unexpected 2xx or 3xx). Not set on an error that carries no SMTP
|
|
108
|
+
* reply, such as a connection failure or missing credentials, see isPermanentResponseCode
|
|
109
|
+
*/
|
|
110
|
+
permanent?: boolean | undefined;
|
|
92
111
|
/** URL of the resource that could not be fetched */
|
|
93
112
|
sourceUrl?: string | undefined;
|
|
94
113
|
/** Recipient address the error applies to */
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* err.code = errors.ECONNECTION;
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.ERR_ACCESS_DENIED = exports.isTransientError = exports.EFETCH = exports.EURLACCESS = exports.EFILEACCESS = exports.EPROXY = exports.ECONFIG = exports.ESES = exports.ESENDMAIL = exports.EMAXRECIPIENTS = exports.EMAXLIMIT = exports.EOAUTH2 = exports.ENOAUTH = exports.EAUTH = exports.ESTREAM = exports.EMESSAGE = exports.EENVELOPE = exports.EPROTOCOL = exports.EREQUIRETLS = exports.ETLS = exports.EDNS = exports.ESOCKET = exports.ETIMEDOUT = exports.ECONNECTION = exports.ERROR_CODES = void 0;
|
|
13
|
+
exports.ERR_ACCESS_DENIED = exports.isPermanentResponseCode = exports.isTransientError = exports.EFETCH = exports.EURLACCESS = exports.EFILEACCESS = exports.EPROXY = exports.ECONFIG = exports.ESES = exports.ESENDMAIL = exports.EMAXRECIPIENTS = exports.EMAXLIMIT = exports.EOAUTH2 = exports.ENOAUTH = exports.EAUTH = exports.ESTREAM = exports.EMESSAGE = exports.EENVELOPE = exports.EPROTOCOL = exports.EREQUIRETLS = exports.ETLS = exports.EDNS = exports.ESOCKET = exports.ETIMEDOUT = exports.ECONNECTION = exports.ERROR_CODES = void 0;
|
|
14
14
|
/**
|
|
15
15
|
* Error code descriptions for documentation and debugging
|
|
16
16
|
*/
|
|
@@ -73,6 +73,19 @@ exports.EFETCH = 'EFETCH';
|
|
|
73
73
|
*/
|
|
74
74
|
const isTransientError = (err) => err.responseCode === 421 || err.code === exports.ECONNECTION || err.code === exports.ESOCKET || err.code === exports.ETIMEDOUT;
|
|
75
75
|
exports.isTransientError = isTransientError;
|
|
76
|
+
/**
|
|
77
|
+
* Tells whether an SMTP reply code is a permanent rejection, one that retrying the same
|
|
78
|
+
* message would get again. RFC 5321 makes every 5yz reply a permanent negative completion
|
|
79
|
+
* and every 4yz reply a transient one. 503 (bad sequence of commands) is the exception: it
|
|
80
|
+
* says the session was in the wrong state for the command rather than that the message was
|
|
81
|
+
* refused, so the same message can go through on a new connection. 2yz and 3yz replies are
|
|
82
|
+
* only an error when the client expected something else, and are not permanent either.
|
|
83
|
+
*
|
|
84
|
+
* @param responseCode SMTP reply code
|
|
85
|
+
* @returns true for a permanent rejection
|
|
86
|
+
*/
|
|
87
|
+
const isPermanentResponseCode = (responseCode) => responseCode >= 500 && responseCode < 600 && responseCode !== 503;
|
|
88
|
+
exports.isPermanentResponseCode = isPermanentResponseCode;
|
|
76
89
|
/**
|
|
77
90
|
* Code Node.js sets on an error when its permission model (`--permission`) denies an
|
|
78
91
|
* operation. It is not replaced with the Nodemailer code of the failing step (`ESOCKET`,
|
|
@@ -198,16 +198,14 @@ class Cookies {
|
|
|
198
198
|
// check if hostname matches
|
|
199
199
|
// .foo.com also matches subdomains, foo.com does not
|
|
200
200
|
if (urlparts.hostname !== cookie.domain &&
|
|
201
|
-
(cookie.domain.charAt(0) !== '.' ||
|
|
202
|
-
('.' + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)) {
|
|
201
|
+
(cookie.domain.charAt(0) !== '.' || ('.' + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)) {
|
|
203
202
|
return false;
|
|
204
203
|
}
|
|
205
204
|
// check if the request path path-matches the cookie path (RFC 6265 section 5.1.4):
|
|
206
205
|
// identical paths match, otherwise the cookie path must be a directory prefix
|
|
207
206
|
const pathname = urlparts.pathname || '/';
|
|
208
207
|
const cookiePath = cookie.path;
|
|
209
|
-
const pathMatches = pathname === cookiePath ||
|
|
210
|
-
(pathname.startsWith(cookiePath) && (cookiePath.endsWith('/') || pathname.charAt(cookiePath.length) === '/'));
|
|
208
|
+
const pathMatches = pathname === cookiePath || (pathname.startsWith(cookiePath) && (cookiePath.endsWith('/') || pathname.charAt(cookiePath.length) === '/'));
|
|
211
209
|
if (!pathMatches) {
|
|
212
210
|
return false;
|
|
213
211
|
}
|
|
@@ -262,11 +262,7 @@ function nmfetch(url, options) {
|
|
|
262
262
|
}
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
|
-
if (parsed.protocol === 'https:' &&
|
|
266
|
-
parsed.hostname &&
|
|
267
|
-
parsed.hostname !== reqOptions.host &&
|
|
268
|
-
!node_net_1.default.isIP(parsed.hostname) &&
|
|
269
|
-
!reqOptions.servername) {
|
|
265
|
+
if (parsed.protocol === 'https:' && parsed.hostname && parsed.hostname !== reqOptions.host && !node_net_1.default.isIP(parsed.hostname) && !reqOptions.servername) {
|
|
270
266
|
reqOptions.servername = parsed.hostname;
|
|
271
267
|
}
|
|
272
268
|
try {
|
|
@@ -369,9 +365,7 @@ function nmfetch(url, options) {
|
|
|
369
365
|
// downgrade would also put them on the wire in cleartext). Strip sensitive
|
|
370
366
|
// request headers so an attacker who controls the redirect target cannot
|
|
371
367
|
// harvest them.
|
|
372
|
-
const crossOrigin = redirectParsed.protocol !== parsed.protocol ||
|
|
373
|
-
redirectParsed.hostname !== parsed.hostname ||
|
|
374
|
-
fetchPort(redirectParsed) !== fetchPort(parsed);
|
|
368
|
+
const crossOrigin = redirectParsed.protocol !== parsed.protocol || redirectParsed.hostname !== parsed.hostname || fetchPort(redirectParsed) !== fetchPort(parsed);
|
|
375
369
|
if (options.headers && crossOrigin) {
|
|
376
370
|
const sensitive = ['authorization', 'cookie', 'proxy-authorization'];
|
|
377
371
|
Object.keys(options.headers).forEach(key => {
|