@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
|
@@ -54,6 +54,40 @@ function isContentObject(value) {
|
|
|
54
54
|
const content = value;
|
|
55
55
|
return typeof value === 'object' && !!(content.content || content.path || content.href || content.raw);
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Tells whether attachment content is a string or a Buffer that 7bit can describe: ASCII
|
|
59
|
+
* only, no NUL and no line over the 998 octets of RFC 5322. Anything else, a stream or a
|
|
60
|
+
* file path included, can not be checked here
|
|
61
|
+
*/
|
|
62
|
+
function fitsSevenBit(content) {
|
|
63
|
+
let at;
|
|
64
|
+
let length;
|
|
65
|
+
if (typeof content === 'string') {
|
|
66
|
+
at = i => content.charCodeAt(i);
|
|
67
|
+
length = content.length;
|
|
68
|
+
}
|
|
69
|
+
else if (Buffer.isBuffer(content)) {
|
|
70
|
+
at = i => content[i];
|
|
71
|
+
length = content.length;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
let lineLength = 0;
|
|
77
|
+
for (let i = 0; i < length; i++) {
|
|
78
|
+
const c = at(i);
|
|
79
|
+
if (c === 0 || c > 0x7f) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (c === 0x0a || c === 0x0d) {
|
|
83
|
+
lineLength = 0;
|
|
84
|
+
}
|
|
85
|
+
else if (++lineLength > 998) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
57
91
|
class MailComposer {
|
|
58
92
|
constructor(mail) {
|
|
59
93
|
this.mail = mail || {};
|
|
@@ -136,8 +170,11 @@ class MailComposer {
|
|
|
136
170
|
contentTransferEncoding = attachment.contentTransferEncoding;
|
|
137
171
|
}
|
|
138
172
|
else if (isMessageNode) {
|
|
139
|
-
//
|
|
140
|
-
|
|
173
|
+
// a message/* part can not be encoded (RFC 2046 5.2.1), so the label has to describe
|
|
174
|
+
// the content as it is. A stream or a file might hold non-ASCII bytes that can not be
|
|
175
|
+
// checked here, so only content at hand that fits 7bit is labelled as such
|
|
176
|
+
// content with an `encoding` is decoded later, so what it decodes to is not known here either
|
|
177
|
+
contentTransferEncoding = !attachment.encoding && fitsSevenBit(attachment.content) ? '7bit' : '8bit';
|
|
141
178
|
}
|
|
142
179
|
else {
|
|
143
180
|
contentTransferEncoding = 'base64'; // the default
|
|
@@ -152,9 +189,7 @@ class MailComposer {
|
|
|
152
189
|
}
|
|
153
190
|
else if (!isMessageNode && attachment.filename !== false) {
|
|
154
191
|
// a backslash separates as well, so a Windows path does not put the sender's directories in the headers
|
|
155
|
-
data.filename =
|
|
156
|
-
(attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() ||
|
|
157
|
-
'attachment-' + (i + 1);
|
|
192
|
+
data.filename = (attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() || 'attachment-' + (i + 1);
|
|
158
193
|
if (data.filename.indexOf('.') < 0) {
|
|
159
194
|
data.filename += '.' + mimeFuncs.detectExtension(data.contentType);
|
|
160
195
|
}
|
|
@@ -315,8 +350,7 @@ class MailComposer {
|
|
|
315
350
|
if (this.mail.icalEvent) {
|
|
316
351
|
eventObject = Object.assign({}, this._getIcalEvent());
|
|
317
352
|
eventObject.filename = false;
|
|
318
|
-
eventObject.contentType =
|
|
319
|
-
'text/calendar; charset=utf-8; method=' + (eventObject.method || 'PUBLISH').toString().trim().toUpperCase();
|
|
353
|
+
eventObject.contentType = 'text/calendar; charset=utf-8; method=' + (eventObject.method || 'PUBLISH').toString().trim().toUpperCase();
|
|
320
354
|
if (!eventObject.headers) {
|
|
321
355
|
eventObject.headers = {};
|
|
322
356
|
}
|
|
@@ -344,8 +378,7 @@ class MailComposer {
|
|
|
344
378
|
alternative = this._processDataUrl(alternative);
|
|
345
379
|
}
|
|
346
380
|
const data = {
|
|
347
|
-
contentType: alternative.contentType ||
|
|
348
|
-
mimeFuncs.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
|
|
381
|
+
contentType: alternative.contentType || mimeFuncs.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
|
|
349
382
|
contentTransferEncoding: alternative.contentTransferEncoding
|
|
350
383
|
};
|
|
351
384
|
if (alternative.filename) {
|
|
@@ -109,8 +109,7 @@ class MailMessage {
|
|
|
109
109
|
if (!attachment.filename) {
|
|
110
110
|
// a backslash separates as well, so a Windows path does not put the sender's directories in the headers
|
|
111
111
|
attachment.filename =
|
|
112
|
-
(attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() ||
|
|
113
|
-
'attachment-' + (i + 1);
|
|
112
|
+
(attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() || 'attachment-' + (i + 1);
|
|
114
113
|
if (attachment.filename.indexOf('.') < 0) {
|
|
115
114
|
attachment.filename += '.' + mimeFuncs.detectExtension(attachment.contentType);
|
|
116
115
|
}
|
|
@@ -245,7 +244,7 @@ class MailMessage {
|
|
|
245
244
|
value = (value && value.value) || value;
|
|
246
245
|
if (value) {
|
|
247
246
|
if (['references', 'in-reply-to', 'message-id', 'content-id'].includes(key)) {
|
|
248
|
-
value = this.message.
|
|
247
|
+
value = this.message.encodeHeaderValue(key, value);
|
|
249
248
|
}
|
|
250
249
|
data.normalizedHeaders[key] = value;
|
|
251
250
|
}
|
|
@@ -257,10 +256,10 @@ class MailMessage {
|
|
|
257
256
|
});
|
|
258
257
|
}
|
|
259
258
|
if (data.references) {
|
|
260
|
-
data.normalizedHeaders.references = this.message.
|
|
259
|
+
data.normalizedHeaders.references = this.message.encodeHeaderValue('references', data.references);
|
|
261
260
|
}
|
|
262
261
|
if (data.inReplyTo) {
|
|
263
|
-
data.normalizedHeaders['in-reply-to'] = this.message.
|
|
262
|
+
data.normalizedHeaders['in-reply-to'] = this.message.encodeHeaderValue('in-reply-to', data.inReplyTo);
|
|
264
263
|
}
|
|
265
264
|
return callback(null, data);
|
|
266
265
|
});
|
|
@@ -329,7 +328,7 @@ class MailMessage {
|
|
|
329
328
|
comment = needsEncoding ? mimeFuncs.encodeWord(comment) : mimeFuncs.quoteString(comment);
|
|
330
329
|
// List-ID expects a bare domain-like identifier, so strip the
|
|
331
330
|
// scheme prefix that _formatListUrl adds or passes through
|
|
332
|
-
return (
|
|
331
|
+
return (value.comment ? comment + ' ' : '') + this._formatListUrl(value.url).replace(/^<[^:]+:\/{0,2}/, '<');
|
|
333
332
|
}
|
|
334
333
|
// List-*: <http://domain> (comment)
|
|
335
334
|
// the ctext specials go out as quoted-pairs, otherwise a ")" closes the
|
|
@@ -107,6 +107,22 @@ export declare function buildHeaderValue(structured: StructuredHeaderValue): str
|
|
|
107
107
|
* @return A list of encoded keys and headers
|
|
108
108
|
*/
|
|
109
109
|
export declare function buildHeaderParam(key: string, data: string | Buffer, maxLength?: number): EncodedHeaderParam[];
|
|
110
|
+
/**
|
|
111
|
+
* Options of parseHeaderValue()
|
|
112
|
+
*/
|
|
113
|
+
export interface ParseHeaderValueOptions {
|
|
114
|
+
/**
|
|
115
|
+
* Drop the RFC 822 comments outside quoted strings, which the MIME headers allow and
|
|
116
|
+
* which are not part of the value: 'boundary=b (comment)' names the boundary 'b'. A
|
|
117
|
+
* parenthesis right behind the '=' of a parameter or behind a token character of its
|
|
118
|
+
* value continues the token, as it does for Python and postal-mime, so 'Invoice(1).pdf'
|
|
119
|
+
* keeps its name and 'boundary=(c)b' names the boundary '(c)b'. A comment that never
|
|
120
|
+
* closes runs to the end of the value, unless a parameter follows it, in which case it is
|
|
121
|
+
* content and the parameter survives. Comments are kept by default for the sake of the
|
|
122
|
+
* callers of this exported function, not because keeping them is ever the better reading
|
|
123
|
+
*/
|
|
124
|
+
stripComments?: boolean | undefined;
|
|
125
|
+
}
|
|
110
126
|
/**
|
|
111
127
|
* Parses a header value with key=value arguments into a structured
|
|
112
128
|
* object.
|
|
@@ -120,9 +136,10 @@ export declare function buildHeaderParam(key: string, data: string | Buffer, max
|
|
|
120
136
|
* }
|
|
121
137
|
*
|
|
122
138
|
* @param str Header value
|
|
139
|
+
* @param options Options, see ParseHeaderValueOptions
|
|
123
140
|
* @return Header value as a parsed structure
|
|
124
141
|
*/
|
|
125
|
-
export declare function parseHeaderValue(str: string): ParsedHeaderValue;
|
|
142
|
+
export declare function parseHeaderValue(str: string, options?: ParseHeaderValueOptions): ParsedHeaderValue;
|
|
126
143
|
/**
|
|
127
144
|
* Returns file extension for a content type string. If no suitable extensions
|
|
128
145
|
* are found, 'bin' is used as the default extension
|
|
@@ -414,6 +414,26 @@ function buildHeaderParam(key, data, maxLength) {
|
|
|
414
414
|
* goes in. Whitespace used to come off it only because the value was trimmed first.
|
|
415
415
|
*/
|
|
416
416
|
const TOKEN = /^[^\x00-\x20\x7f()<>@,;:\\"/[\]?=]+$/;
|
|
417
|
+
/**
|
|
418
|
+
* Offset of the ')' that closes the RFC 822 comment opening at `start`, or -1 when the
|
|
419
|
+
* comment never closes. Comments nest, and a backslash escapes the character after it
|
|
420
|
+
*/
|
|
421
|
+
function _findCommentEnd(str, start) {
|
|
422
|
+
let depth = 0;
|
|
423
|
+
for (let i = start, len = str.length; i < len; i++) {
|
|
424
|
+
const c = str.charAt(i);
|
|
425
|
+
if (c === '\\') {
|
|
426
|
+
i++;
|
|
427
|
+
}
|
|
428
|
+
else if (c === '(') {
|
|
429
|
+
depth++;
|
|
430
|
+
}
|
|
431
|
+
else if (c === ')' && --depth === 0) {
|
|
432
|
+
return i;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return -1;
|
|
436
|
+
}
|
|
417
437
|
/**
|
|
418
438
|
* Whether a string can be a header parameter name.
|
|
419
439
|
*
|
|
@@ -440,13 +460,16 @@ function _isParamName(name) {
|
|
|
440
460
|
* }
|
|
441
461
|
*
|
|
442
462
|
* @param str Header value
|
|
463
|
+
* @param options Options, see ParseHeaderValueOptions
|
|
443
464
|
* @return Header value as a parsed structure
|
|
444
465
|
*/
|
|
445
|
-
function parseHeaderValue(str) {
|
|
466
|
+
function parseHeaderValue(str, options) {
|
|
446
467
|
const response = {
|
|
447
468
|
value: '',
|
|
448
469
|
params: {}
|
|
449
470
|
};
|
|
471
|
+
// Cleared again by an unclosed '(', see the loop
|
|
472
|
+
let stripComments = !!options?.stripComments;
|
|
450
473
|
// A duplicated parameter resolves to its first occurrence, the way a duplicated header
|
|
451
474
|
// does. Letting the last one win disagrees with the receivers that take the first, and
|
|
452
475
|
// the two readings of 'boundary="b"; boundary="c"' name different delimiters. The
|
|
@@ -508,6 +531,25 @@ function parseHeaderValue(str) {
|
|
|
508
531
|
};
|
|
509
532
|
for (let i = 0, len = str.length; i < len; i++) {
|
|
510
533
|
chr = str.charAt(i);
|
|
534
|
+
// With stripComments, an RFC 822 comment stands anywhere outside a quoted string but
|
|
535
|
+
// right behind a token it would continue, see ParseHeaderValueOptions. In the value
|
|
536
|
+
// of a parameter, no pending whitespace means the last significant character was the
|
|
537
|
+
// '=' or a character of the token
|
|
538
|
+
if (stripComments && chr === '(' && !quote && !quoteClosed && !(stage === 'value' && key !== false && !pendingSpace)) {
|
|
539
|
+
let end = _findCommentEnd(str, i);
|
|
540
|
+
if (end < 0 && str.indexOf(';', i) < 0) {
|
|
541
|
+
// a comment that never closes runs to the end of the value, unless a
|
|
542
|
+
// parameter follows it, which is content then and survives
|
|
543
|
+
end = len - 1;
|
|
544
|
+
}
|
|
545
|
+
if (end >= 0) {
|
|
546
|
+
i = end;
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
// looking for a closing ')' again would scan a run of unclosed '(' to its end
|
|
550
|
+
// once for each of them
|
|
551
|
+
stripComments = false;
|
|
552
|
+
}
|
|
511
553
|
if (stage === 'key') {
|
|
512
554
|
if (chr === '=') {
|
|
513
555
|
key = takeValue().trim();
|
|
@@ -1104,10 +1104,7 @@ const extensions = new Map([
|
|
|
1104
1104
|
['bdm', 'application/vnd.syncml.dm+wbxml'],
|
|
1105
1105
|
['bed', 'application/vnd.realvnc.bed'],
|
|
1106
1106
|
['bh2', 'application/vnd.fujitsu.oasysprs'],
|
|
1107
|
-
[
|
|
1108
|
-
'bin',
|
|
1109
|
-
['application/octet-stream', 'application/mac-binary', 'application/macbinary', 'application/x-macbinary', 'application/x-binary']
|
|
1110
|
-
],
|
|
1107
|
+
['bin', ['application/octet-stream', 'application/mac-binary', 'application/macbinary', 'application/x-macbinary', 'application/x-binary']],
|
|
1111
1108
|
['bm', 'image/bmp'],
|
|
1112
1109
|
['bmi', 'application/vnd.bmi'],
|
|
1113
1110
|
['bmp', ['image/bmp', 'image/x-windows-bmp']],
|
|
@@ -1152,10 +1149,7 @@ const extensions = new Map([
|
|
|
1152
1149
|
['cii', 'application/vnd.anser-web-certificate-issue-initiation'],
|
|
1153
1150
|
['cil', 'application/vnd.ms-artgalry'],
|
|
1154
1151
|
['cla', 'application/vnd.claymore'],
|
|
1155
|
-
[
|
|
1156
|
-
'class',
|
|
1157
|
-
['application/octet-stream', 'application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java-class']
|
|
1158
|
-
],
|
|
1152
|
+
['class', ['application/octet-stream', 'application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java-class']],
|
|
1159
1153
|
['clkk', 'application/vnd.crick.clicker.keyboard'],
|
|
1160
1154
|
['clkp', 'application/vnd.crick.clicker.palette'],
|
|
1161
1155
|
['clkt', 'application/vnd.crick.clicker.template'],
|
|
@@ -1760,10 +1754,7 @@ const extensions = new Map([
|
|
|
1760
1754
|
['sbml', 'application/sbml+xml'],
|
|
1761
1755
|
['sc', 'application/vnd.ibm.secure-container'],
|
|
1762
1756
|
['scd', 'application/x-msschedule'],
|
|
1763
|
-
[
|
|
1764
|
-
'scm',
|
|
1765
|
-
['application/vnd.lotus-screencam', 'video/x-scm', 'text/x-script.guile', 'application/x-lotusscreencam', 'text/x-script.scheme']
|
|
1766
|
-
],
|
|
1757
|
+
['scm', ['application/vnd.lotus-screencam', 'video/x-scm', 'text/x-script.guile', 'application/x-lotusscreencam', 'text/x-script.scheme']],
|
|
1767
1758
|
['scq', 'application/scvp-cv-request'],
|
|
1768
1759
|
['scs', 'application/scvp-cv-response'],
|
|
1769
1760
|
['sct', 'text/scriptlet'],
|
|
@@ -58,6 +58,13 @@ export interface MimeNodePreparedHeaderValue {
|
|
|
58
58
|
* objects (for the address headers), a prepared value object, or a list of these
|
|
59
59
|
*/
|
|
60
60
|
export type MimeNodeHeaderValue = string | number | boolean | Date | MimeNodeAddress | MimeNodePreparedHeaderValue | MimeNodeHeaderValue[] | null | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Options for the static MimeNode.encodeHeaderValue
|
|
63
|
+
*/
|
|
64
|
+
export interface MimeNodeHeaderEncodingOptions {
|
|
65
|
+
/** Either 'Q' (the default) or 'B' */
|
|
66
|
+
textEncoding?: string | undefined;
|
|
67
|
+
}
|
|
61
68
|
/**
|
|
62
69
|
* A single header, the shape the headers are stored in and one of the list forms
|
|
63
70
|
* setHeader and addHeader accept
|
|
@@ -319,6 +326,31 @@ declare class MimeNode {
|
|
|
319
326
|
* @param raw Raw MIME contents
|
|
320
327
|
*/
|
|
321
328
|
setRaw(raw: MimeNodeContent): this;
|
|
329
|
+
/**
|
|
330
|
+
* Encodes a header value the way this node encodes it in the generated message:
|
|
331
|
+
* address headers are punycoded and mime encoded, message id headers get their
|
|
332
|
+
* angle brackets, a Date object is formatted and any other value is mime encoded
|
|
333
|
+
* when it holds non-ascii or control characters (using the node's `textEncoding`).
|
|
334
|
+
*
|
|
335
|
+
* The result is a single unfolded line without the key. Fold it before writing it
|
|
336
|
+
* into a message, `key + ': ' + value` folded at 76 characters is what the node does.
|
|
337
|
+
*
|
|
338
|
+
* @param key Header key, case insensitive
|
|
339
|
+
* @param value Header value
|
|
340
|
+
* @returns Encoded header value
|
|
341
|
+
*/
|
|
342
|
+
encodeHeaderValue(key: string, value: MimeNodeHeaderValue): string;
|
|
343
|
+
/**
|
|
344
|
+
* Encodes a header value without a node at hand. Same as the instance method of a
|
|
345
|
+
* node created with the given options.
|
|
346
|
+
*
|
|
347
|
+
* @param key Header key, case insensitive
|
|
348
|
+
* @param value Header value
|
|
349
|
+
* @param [options] Encoding options
|
|
350
|
+
* @param [options.textEncoding] either 'Q' (the default) or 'B'
|
|
351
|
+
* @returns Encoded header value
|
|
352
|
+
*/
|
|
353
|
+
static encodeHeaderValue(key: string, value: MimeNodeHeaderValue, options?: MimeNodeHeaderEncodingOptions): string;
|
|
322
354
|
}
|
|
323
355
|
/**
|
|
324
356
|
* Type aliases in the layout of @types/nodemailer, so `MimeNode.Options` style references keep working
|
|
@@ -327,7 +359,8 @@ declare namespace MimeNode {
|
|
|
327
359
|
type Options = MimeNodeOptions;
|
|
328
360
|
type Addresses = MimeNodeAddresses;
|
|
329
361
|
type Envelope = MimeNodeEnvelope;
|
|
362
|
+
type HeaderEncodingOptions = MimeNodeHeaderEncodingOptions;
|
|
330
363
|
}
|
|
331
364
|
/** The same aliases as module level exports, for `import * as MimeNode` and `import MimeNode = require()` */
|
|
332
|
-
export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope };
|
|
365
|
+
export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope, MimeNodeHeaderEncodingOptions as HeaderEncodingOptions };
|
|
333
366
|
export default MimeNode;
|
|
@@ -155,9 +155,7 @@ function exceedsDomainLimits(domain) {
|
|
|
155
155
|
*/
|
|
156
156
|
function normalizeDomain(domain, toUnicode) {
|
|
157
157
|
// domainToASCII and domainToUnicode landed in Node 7, the bundled codec covers Node 6
|
|
158
|
-
if (typeof node_url_1.default.domainToASCII === 'function' &&
|
|
159
|
-
typeof node_url_1.default.domainToUnicode === 'function' &&
|
|
160
|
-
!URL_PARSER_UNSAFE.test(domain)) {
|
|
158
|
+
if (typeof node_url_1.default.domainToASCII === 'function' && typeof node_url_1.default.domainToUnicode === 'function' && !URL_PARSER_UNSAFE.test(domain)) {
|
|
161
159
|
// The U-label form is decoded from the A-label form rather than from the input:
|
|
162
160
|
// Deno's domainToASCII returns an empty string for a label it cannot decode, while
|
|
163
161
|
// its domainToUnicode returns the label with U+FFFD in place of the bad part
|
|
@@ -656,23 +654,24 @@ class MimeNode {
|
|
|
656
654
|
return;
|
|
657
655
|
}
|
|
658
656
|
switch (header.key) {
|
|
657
|
+
// The comments of a MIME header are not part of its value and are dropped, so a
|
|
658
|
+
// caller supplied 'boundary=b (comment)' is the boundary b it names, and the
|
|
659
|
+
// header goes out without the comment
|
|
659
660
|
case 'Content-Disposition':
|
|
660
|
-
structured = mimeFuncs.parseHeaderValue(value);
|
|
661
|
+
structured = mimeFuncs.parseHeaderValue(value, { stripComments: true });
|
|
661
662
|
if (this.filename) {
|
|
662
663
|
structured.params.filename = this.filename;
|
|
663
664
|
}
|
|
664
665
|
value = mimeFuncs.buildHeaderValue(structured);
|
|
665
666
|
break;
|
|
666
667
|
case 'Content-Type':
|
|
667
|
-
structured = mimeFuncs.parseHeaderValue(value);
|
|
668
|
+
structured = mimeFuncs.parseHeaderValue(value, { stripComments: true });
|
|
668
669
|
// the type token decides multipart and charset below, so clean it before
|
|
669
670
|
// those run and not just on the way out, otherwise a control char makes
|
|
670
671
|
// the checks miss and the header ends up claiming a type it is not set up for
|
|
671
672
|
structured.value = (structured.value || '').toString().replace(/[\x00-\x1f\x7f]/g, '');
|
|
672
673
|
this._handleContentType(structured);
|
|
673
|
-
if (structured.value.match(/^text\/plain\b/) &&
|
|
674
|
-
typeof this.content === 'string' &&
|
|
675
|
-
/[\u0080-\uFFFF]/.test(this.content)) {
|
|
674
|
+
if (structured.value.match(/^text\/plain\b/) && typeof this.content === 'string' && /[\u0080-\uFFFF]/.test(this.content)) {
|
|
676
675
|
structured.params.charset = 'utf-8';
|
|
677
676
|
}
|
|
678
677
|
if (this.filename) {
|
|
@@ -713,7 +712,7 @@ class MimeNode {
|
|
|
713
712
|
}
|
|
714
713
|
break;
|
|
715
714
|
}
|
|
716
|
-
value = this.
|
|
715
|
+
value = this.encodeHeaderValue(key, value);
|
|
717
716
|
// skip empty lines
|
|
718
717
|
if (!(value || '').toString().trim()) {
|
|
719
718
|
return;
|
|
@@ -1331,8 +1330,7 @@ class MimeNode {
|
|
|
1331
1330
|
// where it came from. MimeNode is exported and subclassable, so the generator is
|
|
1332
1331
|
// not necessarily the one below. Stripping twice costs nothing, it is idempotent.
|
|
1333
1332
|
const declared = _stripBoundaryControls(structured.params.boundary || this.boundary || '');
|
|
1334
|
-
this.boundary = structured.params.boundary =
|
|
1335
|
-
declared || _stripBoundaryControls(this._generateBoundary());
|
|
1333
|
+
this.boundary = structured.params.boundary = declared || _stripBoundaryControls(this._generateBoundary());
|
|
1336
1334
|
}
|
|
1337
1335
|
else {
|
|
1338
1336
|
this.boundary = false;
|
|
@@ -1350,13 +1348,19 @@ class MimeNode {
|
|
|
1350
1348
|
return _stripBoundaryControls(this.rootNode.boundaryPrefix + '-' + this.rootNode.baseBoundary) + '-Part_' + this._nodeId;
|
|
1351
1349
|
}
|
|
1352
1350
|
/**
|
|
1353
|
-
* Encodes a header value
|
|
1351
|
+
* Encodes a header value the way this node encodes it in the generated message:
|
|
1352
|
+
* address headers are punycoded and mime encoded, message id headers get their
|
|
1353
|
+
* angle brackets, a Date object is formatted and any other value is mime encoded
|
|
1354
|
+
* when it holds non-ascii or control characters (using the node's `textEncoding`).
|
|
1354
1355
|
*
|
|
1355
|
-
*
|
|
1356
|
+
* The result is a single unfolded line without the key. Fold it before writing it
|
|
1357
|
+
* into a message, `key + ': ' + value` folded at 76 characters is what the node does.
|
|
1358
|
+
*
|
|
1359
|
+
* @param key Header key, case insensitive
|
|
1356
1360
|
* @param value Header value
|
|
1357
|
-
* @
|
|
1361
|
+
* @returns Encoded header value
|
|
1358
1362
|
*/
|
|
1359
|
-
|
|
1363
|
+
encodeHeaderValue(key, value) {
|
|
1360
1364
|
key = this._normalizeHeaderKey(key);
|
|
1361
1365
|
switch (key) {
|
|
1362
1366
|
// Structured headers
|
|
@@ -1421,6 +1425,27 @@ class MimeNode {
|
|
|
1421
1425
|
return this._encodeHeaderText(value);
|
|
1422
1426
|
}
|
|
1423
1427
|
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Encodes a header value without a node at hand. Same as the instance method of a
|
|
1430
|
+
* node created with the given options.
|
|
1431
|
+
*
|
|
1432
|
+
* @param key Header key, case insensitive
|
|
1433
|
+
* @param value Header value
|
|
1434
|
+
* @param [options] Encoding options
|
|
1435
|
+
* @param [options.textEncoding] either 'Q' (the default) or 'B'
|
|
1436
|
+
* @returns Encoded header value
|
|
1437
|
+
*/
|
|
1438
|
+
static encodeHeaderValue(key, value, options) {
|
|
1439
|
+
return new MimeNode(false, { textEncoding: options?.textEncoding }).encodeHeaderValue(key, value);
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Alias of encodeHeaderValue, kept for callers that used the method before it was public
|
|
1443
|
+
*
|
|
1444
|
+
* @internal
|
|
1445
|
+
*/
|
|
1446
|
+
_encodeHeaderValue(key, value) {
|
|
1447
|
+
return this.encodeHeaderValue(key, value);
|
|
1448
|
+
}
|
|
1424
1449
|
/**
|
|
1425
1450
|
* Rebuilds address object using punycode and other adjustments
|
|
1426
1451
|
*
|
|
@@ -50,15 +50,9 @@ function encodeBytes(buffer, next, binary, previous) {
|
|
|
50
50
|
for (let i = 0; i < len; i++) {
|
|
51
51
|
const ord = buffer[i];
|
|
52
52
|
const following = i + 1 < len ? buffer[i + 1] : next;
|
|
53
|
-
const lineBreakByte = binary && (ord === 0x0d || ord === 0x0a)
|
|
54
|
-
? ord === 0x0d
|
|
55
|
-
? following === 0x0a
|
|
56
|
-
: (i > 0 ? buffer[i - 1] : previous) === 0x0d
|
|
57
|
-
: true;
|
|
53
|
+
const lineBreakByte = binary && (ord === 0x0d || ord === 0x0a) ? (ord === 0x0d ? following === 0x0a : (i > 0 ? buffer[i - 1] : previous) === 0x0d) : true;
|
|
58
54
|
// if the char is in allowed range, then keep as is, unless it is a WS in the end of a line
|
|
59
|
-
if (QP_LITERAL[ord] &&
|
|
60
|
-
lineBreakByte &&
|
|
61
|
-
!(isWhitespace(ord) && (following === undefined || following === 0x0a || following === 0x0d))) {
|
|
55
|
+
if (QP_LITERAL[ord] && lineBreakByte && !(isWhitespace(ord) && (following === undefined || following === 0x0a || following === 0x0d))) {
|
|
62
56
|
output[pos++] = ord;
|
|
63
57
|
continue;
|
|
64
58
|
}
|
|
@@ -119,10 +113,7 @@ function wrap(str, lineLength) {
|
|
|
119
113
|
line = line.substr(0, line.length - match[0].length);
|
|
120
114
|
}
|
|
121
115
|
// ensure that utf-8 sequences are not split
|
|
122
|
-
while (line.length > 3 &&
|
|
123
|
-
line.length < len - pos &&
|
|
124
|
-
!line.match(/^(?:=[\da-f]{2}){1,4}$/i) &&
|
|
125
|
-
(match = line.match(/[=][\da-f]{2}$/gi))) {
|
|
116
|
+
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/[=][\da-f]{2}$/gi))) {
|
|
126
117
|
code = parseInt(match[0].substr(1, 2), 16);
|
|
127
118
|
if (code < 128) {
|
|
128
119
|
break;
|
|
@@ -109,9 +109,7 @@ class SendmailTransport {
|
|
|
109
109
|
return done(err);
|
|
110
110
|
}
|
|
111
111
|
// force -i to keep single dots
|
|
112
|
-
const args = this.args
|
|
113
|
-
? ['-i'].concat(this.args).concat(envelope.to)
|
|
114
|
-
: ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
|
|
112
|
+
const args = this.args ? ['-i'].concat(this.args).concat(envelope.to) : ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
|
|
115
113
|
const callback = (err) => {
|
|
116
114
|
if (returned) {
|
|
117
115
|
// ignore any additional responses, already done
|
|
@@ -263,9 +263,7 @@ const resolveHostname = (options, callback) => {
|
|
|
263
263
|
return respond(err);
|
|
264
264
|
}
|
|
265
265
|
// Get all supported addresses from dns.lookup
|
|
266
|
-
const supportedAddresses = addresses
|
|
267
|
-
? addresses.filter(addr => isFamilySupported(addr.family)).map(addr => addr.address)
|
|
268
|
-
: [];
|
|
266
|
+
const supportedAddresses = addresses ? addresses.filter(addr => isFamilySupported(addr.family)).map(addr => addr.address) : [];
|
|
269
267
|
if (addresses && addresses.length && !supportedAddresses.length) {
|
|
270
268
|
// there are addresses but none can be used
|
|
271
269
|
console.warn(`Failed to resolve IPv${addresses[0].family} addresses with current network`);
|
|
@@ -601,9 +599,7 @@ const assign = function (...args) {
|
|
|
601
599
|
if ((0, objects_js_1.isProtoKey)(key)) {
|
|
602
600
|
return;
|
|
603
601
|
}
|
|
604
|
-
if (['tls', 'auth'].includes(key) &&
|
|
605
|
-
source[key] &&
|
|
606
|
-
typeof source[key] === 'object') {
|
|
602
|
+
if (['tls', 'auth'].includes(key) && source[key] && typeof source[key] === 'object') {
|
|
607
603
|
// tls and auth are special keys that need to be enumerated separately
|
|
608
604
|
// other objects are passed as is. Enumerating is a copy of user supplied
|
|
609
605
|
// keys just like the loop above, so it gets the same treatment
|
|
@@ -47,7 +47,7 @@ const errors = __importStar(require("../errors.js"));
|
|
|
47
47
|
// never sends \r\n\r\n cannot grow memory unboundedly before the socket times out.
|
|
48
48
|
const MAX_RESPONSE_HEADER_BYTES = 64 * 1024;
|
|
49
49
|
// URL hostnames keep the brackets around an IPv6 literal, socket options and net.isIPv6 take it without
|
|
50
|
-
const unbracket = (host) => typeof host === 'string' && host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host;
|
|
50
|
+
const unbracket = (host) => (typeof host === 'string' && host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host);
|
|
51
51
|
function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, callback) {
|
|
52
52
|
if (typeof tlsOptions === 'function') {
|
|
53
53
|
callback = tlsOptions;
|
|
@@ -245,6 +245,12 @@ export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo {
|
|
|
245
245
|
messageSize: number;
|
|
246
246
|
/** Final server response for the message */
|
|
247
247
|
response: string;
|
|
248
|
+
/**
|
|
249
|
+
* Message-ID the server gave the message, with angle brackets, when its final reply names
|
|
250
|
+
* one in a known format (Microsoft 365 and Outlook.com, Amazon SES). Such a server replaces
|
|
251
|
+
* the Message-ID header, so the delivered copy carries this id instead of messageId
|
|
252
|
+
*/
|
|
253
|
+
serverMessageId?: string | undefined;
|
|
248
254
|
}
|
|
249
255
|
/**
|
|
250
256
|
* Callback for send(), receives the result once the server accepted the message. The error
|
|
@@ -45,6 +45,7 @@ const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
|
45
45
|
const data_stream_js_1 = __importDefault(require("./data-stream.js"));
|
|
46
46
|
const node_stream_1 = require("node:stream");
|
|
47
47
|
const shared = __importStar(require("../shared/index.js"));
|
|
48
|
+
const server_message_id_js_1 = require("./server-message-id.js");
|
|
48
49
|
const errors_js_1 = require("../errors.js");
|
|
49
50
|
// default timeout values in ms
|
|
50
51
|
const CONNECTION_TIMEOUT = 2 * 60 * 1000; // how much to wait for the connection to be established
|
|
@@ -399,9 +400,7 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
|
|
399
400
|
if (this._destroyed || this._closing) {
|
|
400
401
|
return;
|
|
401
402
|
}
|
|
402
|
-
const connectFn = secure
|
|
403
|
-
? node_tls_1.default.connect
|
|
404
|
-
: node_net_1.default.connect;
|
|
403
|
+
const connectFn = secure ? node_tls_1.default.connect : node_net_1.default.connect;
|
|
405
404
|
try {
|
|
406
405
|
this._socket = connectFn(opts, () => this._onConnect());
|
|
407
406
|
this._setupConnectionHandlers();
|
|
@@ -739,6 +738,16 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
|
|
739
738
|
result.messageTime = Date.now() - envelopeTime;
|
|
740
739
|
result.messageSize = stream.outByteCount;
|
|
741
740
|
result.response = str;
|
|
741
|
+
const serverMessageId = (0, server_message_id_js_1.parseServerMessageId)(result.response, this.options.host);
|
|
742
|
+
if (serverMessageId) {
|
|
743
|
+
result.serverMessageId = serverMessageId;
|
|
744
|
+
}
|
|
745
|
+
// an LMTP server answers the message once per recipient, so recipients can be
|
|
746
|
+
// refused after the envelope info was built without any rejected errors on it
|
|
747
|
+
const rejectedErrors = this._envelope?.rejectedErrors;
|
|
748
|
+
if (!result.rejectedErrors && rejectedErrors && rejectedErrors.length) {
|
|
749
|
+
result.rejectedErrors = rejectedErrors;
|
|
750
|
+
}
|
|
742
751
|
return callback(null, result);
|
|
743
752
|
});
|
|
744
753
|
if (typeof message.pipe === 'function') {
|
|
@@ -966,6 +975,7 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
|
|
966
975
|
const responseCode = (typeof response === 'string' && Number((response.match(/^\d+/) || [])[0])) || false;
|
|
967
976
|
if (responseCode) {
|
|
968
977
|
err.responseCode = responseCode;
|
|
978
|
+
err.permanent = (0, errors_js_1.isPermanentResponseCode)(responseCode);
|
|
969
979
|
}
|
|
970
980
|
if (command) {
|
|
971
981
|
err.command = command;
|
|
@@ -1008,12 +1018,7 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
|
|
1008
1018
|
this.close();
|
|
1009
1019
|
return;
|
|
1010
1020
|
}
|
|
1011
|
-
if (!failureResponse &&
|
|
1012
|
-
this.stage === 'connected' &&
|
|
1013
|
-
!this._responseActions.length &&
|
|
1014
|
-
!this._pendingSend &&
|
|
1015
|
-
!this._destroyed &&
|
|
1016
|
-
!this._closing) {
|
|
1021
|
+
if (!failureResponse && this.stage === 'connected' && !this._responseActions.length && !this._pendingSend && !this._destroyed && !this._closing) {
|
|
1017
1022
|
// nothing was waiting for the server, so this is the server ending an idle session
|
|
1018
1023
|
// (usually after its idle timeout), not a failure
|
|
1019
1024
|
this.logger.info({
|
|
@@ -1234,9 +1239,7 @@ class SMTPConnection extends node_events_1.EventEmitter {
|
|
|
1234
1239
|
const args = [];
|
|
1235
1240
|
let useSmtpUtf8 = false;
|
|
1236
1241
|
this._envelope = (envelope || {});
|
|
1237
|
-
this._envelope.from = ((this._envelope.from && this._envelope.from.address) || this._envelope.from || '')
|
|
1238
|
-
.toString()
|
|
1239
|
-
.trim();
|
|
1242
|
+
this._envelope.from = ((this._envelope.from && this._envelope.from.address) || this._envelope.from || '').toString().trim();
|
|
1240
1243
|
this._envelope.to = []
|
|
1241
1244
|
.concat(this._envelope.to || [])
|
|
1242
1245
|
.map(to => ((to && to.address) || to || '').toString().trim());
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the Message-ID a receiving server gave the message out of its final 250 reply. Some
|
|
3
|
+
* servers replace the Message-ID header of a submitted message with one of their own, and
|
|
4
|
+
* the copy the recipients and the sent folder get carries that one instead of the id the
|
|
5
|
+
* message was built with. Only replies in a format known to carry such an id are read.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Reads the server assigned Message-ID out of the final reply to a message
|
|
9
|
+
*
|
|
10
|
+
* @param response Final server reply for the message
|
|
11
|
+
* @param [host] Hostname the connection was made to, SES replies are only read for an SES host
|
|
12
|
+
* @returns The Message-ID with its angle brackets, or undefined when the reply names none
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseServerMessageId(response: string | undefined, host?: string): string | undefined;
|