@mavogel/awscdk-rootmail 0.1.8 → 0.1.10
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 +16 -16
- package/renovate.json5 +1 -0
|
@@ -66,8 +66,8 @@ function isPartialLine(line) {
|
|
|
66
66
|
* * **port** - is the port to connect to (defaults to 587 or 465)
|
|
67
67
|
* * **host** - is the hostname or IP address to connect to (defaults to 'localhost')
|
|
68
68
|
* * **secure** - use SSL
|
|
69
|
-
* * **ignoreTLS** - ignore server support for STARTTLS
|
|
70
|
-
* * **requireTLS** - forces the client to use STARTTLS
|
|
69
|
+
* * **ignoreTLS** - ignore server support for STARTTLS (has no effect when requireTLS is set)
|
|
70
|
+
* * **requireTLS** - forces the client to use STARTTLS, takes precedence over ignoreTLS and opportunisticTLS
|
|
71
71
|
* * **name** - the name of the client server
|
|
72
72
|
* * **localAddress** - outbound address to bind to (see: http://nodejs.org/api/net.html#net_net_connect_options_connectionlistener)
|
|
73
73
|
* * **greetingTimeout** - Time to wait in ms until greeting message is received from the server (defaults to 30 seconds)
|
|
@@ -92,6 +92,11 @@ class SMTPConnection extends EventEmitter {
|
|
|
92
92
|
this.id = crypto.randomBytes(8).toString('base64').replace(/\W/g, '');
|
|
93
93
|
this.stage = 'init';
|
|
94
94
|
this.options = options || {};
|
|
95
|
+
if (this.options.requireTLS && (this.options.ignoreTLS || this.options.opportunisticTLS)) {
|
|
96
|
+
// requireTLS wins, a contradictory configuration must not quietly fall back to plaintext.
|
|
97
|
+
// Copied so the caller's (possibly shared) options object is left as it was
|
|
98
|
+
this.options = Object.assign({}, this.options, { ignoreTLS: false, opportunisticTLS: false });
|
|
99
|
+
}
|
|
95
100
|
this.secureConnection = !!this.options.secure;
|
|
96
101
|
this.alreadySecured = !!this.options.secured;
|
|
97
102
|
this.port = Number(this.options.port) || (this.secureConnection ? 465 : 587);
|
|
@@ -135,6 +140,8 @@ class SMTPConnection extends EventEmitter {
|
|
|
135
140
|
this._destroyed = false;
|
|
136
141
|
this._closing = false;
|
|
137
142
|
this._currentDataStream = false;
|
|
143
|
+
this._pendingSend = false;
|
|
144
|
+
this._connectCallback = false;
|
|
138
145
|
this._onSocketData = chunk => this._onData(chunk);
|
|
139
146
|
this._onSocketError = error => this._onError(error, 'ESOCKET', false, 'CONN');
|
|
140
147
|
this._onSocketClose = () => this._onClose();
|
|
@@ -149,7 +156,9 @@ class SMTPConnection extends EventEmitter {
|
|
|
149
156
|
*/
|
|
150
157
|
connect(connectCallback) {
|
|
151
158
|
if (typeof connectCallback === 'function') {
|
|
159
|
+
this._connectCallback = connectCallback;
|
|
152
160
|
this.once('connect', () => {
|
|
161
|
+
this._connectCallback = false;
|
|
153
162
|
this.logger.debug({
|
|
154
163
|
tnx: 'smtp'
|
|
155
164
|
}, 'SMTP handshake finished');
|
|
@@ -381,6 +390,16 @@ class SMTPConnection extends EventEmitter {
|
|
|
381
390
|
}
|
|
382
391
|
this._currentDataStream = false;
|
|
383
392
|
}
|
|
393
|
+
// Detach from the message stream as well. The listener is swapped for a no-op rather than
|
|
394
|
+
// removed, a stream destroyed with an error later on would otherwise throw it as unhandled
|
|
395
|
+
if (this._pendingSend) {
|
|
396
|
+
const { stream, onStreamError } = this._pendingSend;
|
|
397
|
+
if (stream) {
|
|
398
|
+
stream.removeListener('error', onStreamError);
|
|
399
|
+
stream.on('error', TEARDOWN_NOOP);
|
|
400
|
+
}
|
|
401
|
+
this._pendingSend = false;
|
|
402
|
+
}
|
|
384
403
|
if (socket && !socket.destroyed) {
|
|
385
404
|
try {
|
|
386
405
|
// Clear socket timeout to prevent timer leaks
|
|
@@ -414,14 +433,21 @@ class SMTPConnection extends EventEmitter {
|
|
|
414
433
|
this._auth = authData || {};
|
|
415
434
|
// Select SASL authentication method
|
|
416
435
|
this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false;
|
|
436
|
+
// XOAUTH2 needs a token generator or a custom handler, without either the method
|
|
437
|
+
// can not be run even when it is the only one the server advertised
|
|
438
|
+
const canUseXOAuth2 = !!this._auth.oauth2 || this.customAuth.has('XOAUTH2');
|
|
417
439
|
if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) {
|
|
418
440
|
this._authMethod = 'XOAUTH2';
|
|
419
441
|
}
|
|
420
442
|
else if (!this._authMethod || (this._authMethod === 'XOAUTH2' && !this._auth.oauth2)) {
|
|
421
|
-
// use first supported
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
443
|
+
// use the first supported method that can be run
|
|
444
|
+
const supported = this._supportedAuth.find(method => method !== 'XOAUTH2' || canUseXOAuth2);
|
|
445
|
+
this._authMethod = (supported || 'PLAIN').toUpperCase().trim();
|
|
446
|
+
}
|
|
447
|
+
// a token login needs no credentials, every other method and every custom handler
|
|
448
|
+
// gets them filled in from the user and pass values
|
|
449
|
+
if ((this._authMethod !== 'XOAUTH2' || this.customAuth.has('XOAUTH2')) &&
|
|
450
|
+
(!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) {
|
|
425
451
|
if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) {
|
|
426
452
|
this._auth.credentials = {
|
|
427
453
|
user: this._auth.user,
|
|
@@ -458,42 +484,45 @@ class SMTPConnection extends EventEmitter {
|
|
|
458
484
|
returned = true;
|
|
459
485
|
callback(this._formatError(err, 'EAUTH', lastResponse, 'AUTH ' + this._authMethod));
|
|
460
486
|
};
|
|
487
|
+
// one implementation serves both sendCommand overloads, the promise is returned
|
|
488
|
+
// exactly when no callback was given
|
|
489
|
+
const sendCommand = (cmd, done) => {
|
|
490
|
+
let promise;
|
|
491
|
+
if (!done) {
|
|
492
|
+
promise = new Promise((resolve, reject) => {
|
|
493
|
+
done = shared.callbackPromise(resolve, reject);
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
this._responseActions.push(str => {
|
|
497
|
+
lastResponse = str;
|
|
498
|
+
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
|
499
|
+
let data = {
|
|
500
|
+
command: cmd,
|
|
501
|
+
response: str
|
|
502
|
+
};
|
|
503
|
+
if (codes) {
|
|
504
|
+
data.status = Number(codes[1]) || 0;
|
|
505
|
+
if (codes[2]) {
|
|
506
|
+
data.code = codes[2];
|
|
507
|
+
}
|
|
508
|
+
data.text = str.substr(codes[0].length);
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
data.text = str;
|
|
512
|
+
data.status = 0; // just in case we need to perform numeric comparisons
|
|
513
|
+
}
|
|
514
|
+
done(null, data);
|
|
515
|
+
});
|
|
516
|
+
setImmediate(() => this._sendCommand(cmd));
|
|
517
|
+
return promise;
|
|
518
|
+
};
|
|
461
519
|
const handlerResponse = handler({
|
|
462
520
|
auth: this._auth,
|
|
463
521
|
method: this._authMethod,
|
|
464
522
|
extensions: [].concat(this._supportedExtensions),
|
|
465
523
|
authMethods: [].concat(this._supportedAuth),
|
|
466
524
|
maxAllowedSize: this._maxAllowedSize || false,
|
|
467
|
-
sendCommand:
|
|
468
|
-
let promise;
|
|
469
|
-
if (!done) {
|
|
470
|
-
promise = new Promise((resolve, reject) => {
|
|
471
|
-
done = shared.callbackPromise(resolve, reject);
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
this._responseActions.push(str => {
|
|
475
|
-
lastResponse = str;
|
|
476
|
-
let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/);
|
|
477
|
-
let data = {
|
|
478
|
-
command: cmd,
|
|
479
|
-
response: str
|
|
480
|
-
};
|
|
481
|
-
if (codes) {
|
|
482
|
-
data.status = Number(codes[1]) || 0;
|
|
483
|
-
if (codes[2]) {
|
|
484
|
-
data.code = codes[2];
|
|
485
|
-
}
|
|
486
|
-
data.text = str.substr(codes[0].length);
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
489
|
-
data.text = str;
|
|
490
|
-
data.status = 0; // just in case we need to perform numeric comparisons
|
|
491
|
-
}
|
|
492
|
-
done(null, data);
|
|
493
|
-
});
|
|
494
|
-
setImmediate(() => this._sendCommand(cmd));
|
|
495
|
-
return promise;
|
|
496
|
-
},
|
|
525
|
+
sendCommand: sendCommand,
|
|
497
526
|
resolve,
|
|
498
527
|
reject
|
|
499
528
|
});
|
|
@@ -547,35 +576,46 @@ class SMTPConnection extends EventEmitter {
|
|
|
547
576
|
*
|
|
548
577
|
* @param envelope Envelope object, {from: addr, to: [addr]}
|
|
549
578
|
* @param message String, Buffer or a Stream
|
|
550
|
-
* @param
|
|
579
|
+
* @param done Callback to return once sending is completed
|
|
551
580
|
*/
|
|
552
581
|
send(envelope, message, done) {
|
|
582
|
+
// ensure that the callback is only called once. The public callback type has a
|
|
583
|
+
// required result, the error paths hand over the error alone
|
|
584
|
+
let returned = false;
|
|
585
|
+
const callback = (err, info) => {
|
|
586
|
+
if (returned) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
returned = true;
|
|
590
|
+
if (this._pendingSend && this._pendingSend.callback === callback) {
|
|
591
|
+
this._pendingSend = false;
|
|
592
|
+
}
|
|
593
|
+
done(err, info);
|
|
594
|
+
};
|
|
553
595
|
if (!message) {
|
|
554
|
-
return
|
|
596
|
+
return callback(this._formatError('Empty message', 'EMESSAGE', false, 'API'));
|
|
555
597
|
}
|
|
556
598
|
const isDestroyedMessage = this._isDestroyedMessage('send message');
|
|
557
599
|
if (isDestroyedMessage) {
|
|
558
|
-
return
|
|
600
|
+
return callback(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API'));
|
|
559
601
|
}
|
|
560
602
|
// reject larger messages than allowed
|
|
561
603
|
if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) {
|
|
562
604
|
setImmediate(() => {
|
|
563
|
-
|
|
605
|
+
callback(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM'));
|
|
564
606
|
});
|
|
565
607
|
return;
|
|
566
608
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
returned = true;
|
|
574
|
-
done(...args);
|
|
609
|
+
const pendingSend = {
|
|
610
|
+
callback,
|
|
611
|
+
stream: false,
|
|
612
|
+
onStreamError: err => callback(this._formatError(err, 'ESTREAM', false, 'API'))
|
|
575
613
|
};
|
|
576
614
|
if (typeof message.on === 'function') {
|
|
577
|
-
|
|
615
|
+
pendingSend.stream = message;
|
|
616
|
+
pendingSend.stream.on('error', pendingSend.onStreamError);
|
|
578
617
|
}
|
|
618
|
+
this._pendingSend = pendingSend;
|
|
579
619
|
const startTime = Date.now();
|
|
580
620
|
this._setEnvelope(envelope, (err, info) => {
|
|
581
621
|
if (err) {
|
|
@@ -595,11 +635,13 @@ class SMTPConnection extends EventEmitter {
|
|
|
595
635
|
if (err) {
|
|
596
636
|
return callback(err);
|
|
597
637
|
}
|
|
598
|
-
info
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
638
|
+
// the envelope info becomes the send result once the timings are on it
|
|
639
|
+
const result = info;
|
|
640
|
+
result.envelopeTime = envelopeTime - startTime;
|
|
641
|
+
result.messageTime = Date.now() - envelopeTime;
|
|
642
|
+
result.messageSize = stream.outByteCount;
|
|
643
|
+
result.response = str;
|
|
644
|
+
return callback(null, result);
|
|
603
645
|
});
|
|
604
646
|
if (typeof message.pipe === 'function') {
|
|
605
647
|
message.pipe(stream);
|
|
@@ -747,6 +789,8 @@ class SMTPConnection extends EventEmitter {
|
|
|
747
789
|
* @event
|
|
748
790
|
* @param err Error object
|
|
749
791
|
* @param type Error name
|
|
792
|
+
* @param data Server response that triggered the error, false if there is none
|
|
793
|
+
* @param command SMTP command that was in flight
|
|
750
794
|
* @internal
|
|
751
795
|
*/
|
|
752
796
|
_onError(err, type, data, command) {
|
|
@@ -766,8 +810,14 @@ class SMTPConnection extends EventEmitter {
|
|
|
766
810
|
else {
|
|
767
811
|
this.logger.error(data, err.message);
|
|
768
812
|
}
|
|
813
|
+
// close() forgets the send in flight, it is completed with this same error afterwards so
|
|
814
|
+
// a late message stream error has nothing left to report
|
|
815
|
+
const pendingSend = this._pendingSend;
|
|
769
816
|
this.emit('error', err);
|
|
770
817
|
this.close();
|
|
818
|
+
if (pendingSend) {
|
|
819
|
+
pendingSend.callback(err);
|
|
820
|
+
}
|
|
771
821
|
}
|
|
772
822
|
/** @internal */
|
|
773
823
|
_formatError(message, type, response, command) {
|
|
@@ -813,14 +863,25 @@ class SMTPConnection extends EventEmitter {
|
|
|
813
863
|
this.logger.info({
|
|
814
864
|
tnx: 'network'
|
|
815
865
|
}, 'Connection closed');
|
|
866
|
+
// the unterminated remainder is only reported as a reply (and so gives the error a responseCode)
|
|
867
|
+
// when it starts like a complete failure reply, not for a fragment such as "55" or a 250
|
|
868
|
+
const failureResponse = typeof serverResponse === 'string' && /^[45]\d{2}[ -]/.test(serverResponse) ? serverResponse : false;
|
|
816
869
|
if (this.upgrading && !this._destroyed) {
|
|
817
|
-
return this._onError(new Error('Connection closed unexpectedly'), 'ETLS',
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
|
|
870
|
+
return this._onError(new Error('Connection closed unexpectedly'), 'ETLS', failureResponse, 'CONN');
|
|
871
|
+
}
|
|
872
|
+
if (!failureResponse && this._responseActions[0] === this._actionGreeting && this._connectCallback && !this._destroyed) {
|
|
873
|
+
// A silent close before the greeting is handed to the connect() callback rather than
|
|
874
|
+
// emitted as 'error', callers that never saw an error for it must not start throwing one
|
|
875
|
+
const connectCallback = this._connectCallback;
|
|
876
|
+
this._connectCallback = false;
|
|
877
|
+
const err = this._formatError(new Error('Connection closed unexpectedly'), 'ECONNECTION', false, 'CONN');
|
|
878
|
+
this.logger.warn({ tnx: 'network' }, err.message);
|
|
879
|
+
connectCallback(err);
|
|
880
|
+
this.close();
|
|
881
|
+
return;
|
|
821
882
|
}
|
|
822
|
-
|
|
823
|
-
return this._onError(new Error('Connection closed unexpectedly'), 'ECONNECTION',
|
|
883
|
+
if (failureResponse || (this._responseActions[0] !== this.close && !this._destroyed)) {
|
|
884
|
+
return this._onError(new Error('Connection closed unexpectedly'), 'ECONNECTION', failureResponse, 'CONN');
|
|
824
885
|
}
|
|
825
886
|
this._destroy();
|
|
826
887
|
}
|
|
@@ -998,6 +1059,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
998
1059
|
* {from:'...', to:['...']}
|
|
999
1060
|
* or
|
|
1000
1061
|
* {from:{address:'...',name:'...'}, to:[address:'...',name:'...']}
|
|
1062
|
+
* @param callback Callback to run once the envelope is processed
|
|
1001
1063
|
* @internal
|
|
1002
1064
|
*/
|
|
1003
1065
|
_setEnvelope(envelope, callback) {
|
|
@@ -1297,21 +1359,25 @@ class SMTPConnection extends EventEmitter {
|
|
|
1297
1359
|
if (/[ -]AUTH\b/i.test(str)) {
|
|
1298
1360
|
this.allowsAuth = true;
|
|
1299
1361
|
}
|
|
1300
|
-
// Detect
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
//
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1362
|
+
// Detect the advertised SASL mechanisms. The list is split into whole tokens rather
|
|
1363
|
+
// than searched for each name with a pattern: the patterns this replaced let two
|
|
1364
|
+
// whitespace runs overlap and backtracked quadratically over an AUTH line padded with
|
|
1365
|
+
// spaces, so a hostile server could stall the event loop from its EHLO reply
|
|
1366
|
+
// (GHSA-4ffr-jq9g-5ffx).
|
|
1367
|
+
const authMechanisms = new Set();
|
|
1368
|
+
for (const line of this._ehloLines) {
|
|
1369
|
+
const authMatch = /^AUTH[\s=](.*)/i.exec(line);
|
|
1370
|
+
if (authMatch) {
|
|
1371
|
+
for (const mechanism of authMatch[1].split(/[\s=]+/)) {
|
|
1372
|
+
authMechanisms.add(mechanism.toUpperCase());
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1311
1375
|
}
|
|
1312
|
-
//
|
|
1313
|
-
|
|
1314
|
-
|
|
1376
|
+
// listed in order of preference, the first one the credentials allow is used
|
|
1377
|
+
for (const mechanism of ['PLAIN', 'LOGIN', 'CRAM-MD5', 'XOAUTH2']) {
|
|
1378
|
+
if (authMechanisms.has(mechanism)) {
|
|
1379
|
+
this._supportedAuth.push(mechanism);
|
|
1380
|
+
}
|
|
1315
1381
|
}
|
|
1316
1382
|
// Detect if the server supports SIZE extensions (and the max allowed size)
|
|
1317
1383
|
if ((match = str.match(/[ -]SIZE(?:[ \t]+(\d+))?/im))) {
|
|
@@ -1388,6 +1454,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1388
1454
|
* hosts invalidly use a longer message than VXNlcm5hbWU6
|
|
1389
1455
|
*
|
|
1390
1456
|
* @param str Message from the server
|
|
1457
|
+
* @param callback Callback to run once the authentication sequence completes
|
|
1391
1458
|
* @internal
|
|
1392
1459
|
*/
|
|
1393
1460
|
_actionAUTH_LOGIN_USER(str, callback) {
|
|
@@ -1409,6 +1476,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1409
1476
|
* base64 encoded again.
|
|
1410
1477
|
*
|
|
1411
1478
|
* @param str Message from the server
|
|
1479
|
+
* @param callback Callback to run once the authentication sequence completes
|
|
1412
1480
|
* @internal
|
|
1413
1481
|
*/
|
|
1414
1482
|
_actionAUTH_CRAM_MD5(str, callback) {
|
|
@@ -1433,6 +1501,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1433
1501
|
* the user can be considered logged in. Start waiting for a message to send
|
|
1434
1502
|
*
|
|
1435
1503
|
* @param str Message from the server
|
|
1504
|
+
* @param callback Callback to run once the authentication sequence completes
|
|
1436
1505
|
* @internal
|
|
1437
1506
|
*/
|
|
1438
1507
|
_actionAUTH_CRAM_MD5_PASS(str, callback) {
|
|
@@ -1454,6 +1523,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1454
1523
|
* response needs to be base64 encoded password.
|
|
1455
1524
|
*
|
|
1456
1525
|
* @param str Message from the server
|
|
1526
|
+
* @param callback Callback to run once the authentication sequence completes
|
|
1457
1527
|
* @internal
|
|
1458
1528
|
*/
|
|
1459
1529
|
_actionAUTH_LOGIN_PASS(str, callback) {
|
|
@@ -1473,6 +1543,8 @@ class SMTPConnection extends EventEmitter {
|
|
|
1473
1543
|
* the user can be considered logged in. Start waiting for a message to send
|
|
1474
1544
|
*
|
|
1475
1545
|
* @param str Message from the server
|
|
1546
|
+
* @param isRetry True if this is a retry after a failed login, or the callback itself
|
|
1547
|
+
* @param [callback] Callback to run once the authentication sequence completes
|
|
1476
1548
|
* @internal
|
|
1477
1549
|
*/
|
|
1478
1550
|
_actionAUTHComplete(str, isRetry, callback) {
|
|
@@ -1515,6 +1587,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1515
1587
|
* Handle response for a MAIL FROM: command
|
|
1516
1588
|
*
|
|
1517
1589
|
* @param str Message from the server
|
|
1590
|
+
* @param callback Callback to run once the envelope is processed
|
|
1518
1591
|
* @internal
|
|
1519
1592
|
*/
|
|
1520
1593
|
_actionMAIL(str, callback) {
|
|
@@ -1543,6 +1616,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1543
1616
|
* Handle response for a RCPT TO: command
|
|
1544
1617
|
*
|
|
1545
1618
|
* @param str Message from the server
|
|
1619
|
+
* @param callback Callback to run once the envelope is processed
|
|
1546
1620
|
* @internal
|
|
1547
1621
|
*/
|
|
1548
1622
|
_actionRCPT(str, callback) {
|
|
@@ -1571,7 +1645,11 @@ class SMTPConnection extends EventEmitter {
|
|
|
1571
1645
|
this._sendCommand('DATA');
|
|
1572
1646
|
}
|
|
1573
1647
|
else {
|
|
1574
|
-
|
|
1648
|
+
// report a temporary rejection when there is one, taking the last reply would mark the
|
|
1649
|
+
// whole message as permanently failed although some recipients were only deferred
|
|
1650
|
+
const deferred = envelope.rejectedErrors.find(rejectedErr => rejectedErr.responseCode && rejectedErr.responseCode < 500);
|
|
1651
|
+
const reply = deferred?.response ?? str;
|
|
1652
|
+
err = this._formatError("Can't send mail - all recipients were rejected", 'EENVELOPE', reply, 'RCPT TO');
|
|
1575
1653
|
err.rejected = envelope.rejected;
|
|
1576
1654
|
err.rejectedErrors = envelope.rejectedErrors;
|
|
1577
1655
|
return callback(err);
|
|
@@ -1590,6 +1668,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1590
1668
|
* Handle response for a DATA command
|
|
1591
1669
|
*
|
|
1592
1670
|
* @param str Message from the server
|
|
1671
|
+
* @param callback Callback to run once the envelope is processed
|
|
1593
1672
|
* @internal
|
|
1594
1673
|
*/
|
|
1595
1674
|
_actionDATA(str, callback) {
|
|
@@ -1616,6 +1695,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1616
1695
|
* We expect a single response that defines if the sending succeeded or failed
|
|
1617
1696
|
*
|
|
1618
1697
|
* @param str Message from the server
|
|
1698
|
+
* @param callback Callback to run with the final send result
|
|
1619
1699
|
* @internal
|
|
1620
1700
|
*/
|
|
1621
1701
|
_actionSMTPStream(str, callback) {
|
|
@@ -1632,6 +1712,7 @@ class SMTPConnection extends EventEmitter {
|
|
|
1632
1712
|
* @param recipient The recipient this response applies to
|
|
1633
1713
|
* @param final Is this the final recipient?
|
|
1634
1714
|
* @param str Message from the server
|
|
1715
|
+
* @param callback Callback to run with the final send result
|
|
1635
1716
|
* @internal
|
|
1636
1717
|
*/
|
|
1637
1718
|
_actionLMTPStream(recipient, final, str, callback) {
|
|
@@ -17,7 +17,7 @@ export interface SMTPPoolOptions extends SMTPTransportOptions {
|
|
|
17
17
|
rateLimit?: number | undefined;
|
|
18
18
|
/** Time window for rateLimit in milliseconds, defaults to 1000 */
|
|
19
19
|
rateDelta?: number | undefined;
|
|
20
|
-
/** How many times a message is requeued when its connection closes while sending,
|
|
20
|
+
/** How many times a message is requeued when its connection closes while sending, defaults to 5, a negative value means unlimited */
|
|
21
21
|
maxRequeues?: number | undefined;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -26,6 +26,7 @@ export interface SMTPPoolOptions extends SMTPTransportOptions {
|
|
|
26
26
|
export type SMTPPoolResolvedOptions = SMTPPoolOptions & {
|
|
27
27
|
maxConnections: number;
|
|
28
28
|
maxMessages: number;
|
|
29
|
+
maxRequeues: number;
|
|
29
30
|
};
|
|
30
31
|
/**
|
|
31
32
|
* Result of a message sent through the pool, same as for the SMTP transport
|
|
@@ -80,7 +81,7 @@ declare class SMTPPool extends EventEmitter {
|
|
|
80
81
|
/**
|
|
81
82
|
* The Mail instance using this transport, assigned by Mail
|
|
82
83
|
*/
|
|
83
|
-
mailer?: Mail<SMTPPoolSentMessageInfo> | undefined;
|
|
84
|
+
mailer?: Mail<SMTPPoolSentMessageInfo, SMTPPoolOptions> | undefined;
|
|
84
85
|
constructor(options?: SMTPPoolOptions | string);
|
|
85
86
|
/**
|
|
86
87
|
* Placeholder function for creating proxy sockets. This method immediatelly returns
|
|
@@ -96,7 +97,7 @@ declare class SMTPPool extends EventEmitter {
|
|
|
96
97
|
* @param mail Mail object
|
|
97
98
|
* @param callback Callback function
|
|
98
99
|
*/
|
|
99
|
-
send(mail: MailMessage
|
|
100
|
+
send(mail: MailMessage<SMTPPoolSentMessageInfo>, callback: SMTPPoolSendCallback): boolean;
|
|
100
101
|
/**
|
|
101
102
|
* Closes all connections in the pool. If there is a message being sent, the connection
|
|
102
103
|
* is closed later
|
|
@@ -109,9 +110,14 @@ declare class SMTPPool extends EventEmitter {
|
|
|
109
110
|
/**
|
|
110
111
|
* Verifies SMTP configuration
|
|
111
112
|
*
|
|
112
|
-
* @
|
|
113
|
+
* @returns Promise that resolves to true if the configuration is usable
|
|
113
114
|
*/
|
|
114
115
|
verify(): Promise<true>;
|
|
116
|
+
/**
|
|
117
|
+
* Verifies SMTP configuration
|
|
118
|
+
*
|
|
119
|
+
* @param callback Callback function
|
|
120
|
+
*/
|
|
115
121
|
verify(callback: VerifyCallback): void;
|
|
116
122
|
}
|
|
117
123
|
/**
|
|
@@ -122,4 +128,6 @@ declare namespace SMTPPool {
|
|
|
122
128
|
type MailOptions = SendMailOptions;
|
|
123
129
|
type SentMessageInfo = SMTPPoolSentMessageInfo;
|
|
124
130
|
}
|
|
131
|
+
/** The same aliases as module level exports, for `import * as SMTPPool` and `import SMTPPool = require()` */
|
|
132
|
+
export type { SMTPPoolOptions as Options, SendMailOptions as MailOptions, SMTPPoolSentMessageInfo as SentMessageInfo };
|
|
125
133
|
export default SMTPPool;
|
|
@@ -5,6 +5,10 @@ import wellKnown from '../well-known/index.js';
|
|
|
5
5
|
import * as shared from '../shared/index.js';
|
|
6
6
|
import * as errors from '../errors.js';
|
|
7
7
|
import * as packageData from '../package-info.js';
|
|
8
|
+
/** First delay before a requeued message is retried, doubled on every further requeue */
|
|
9
|
+
const REQUEUE_BASE_DELAY = 50;
|
|
10
|
+
/** Upper bound for the requeue delay */
|
|
11
|
+
const REQUEUE_MAX_DELAY = 2000;
|
|
8
12
|
/**
|
|
9
13
|
* Creates a SMTP pool transport object for Nodemailer
|
|
10
14
|
*
|
|
@@ -36,6 +40,8 @@ class SMTPPool extends EventEmitter {
|
|
|
36
40
|
);
|
|
37
41
|
this.options.maxConnections = this.options.maxConnections || 5;
|
|
38
42
|
this.options.maxMessages = this.options.maxMessages || 100;
|
|
43
|
+
// a default bound, a server that closes every connection before the greeting would otherwise be retried forever
|
|
44
|
+
this.options.maxRequeues = typeof this.options.maxRequeues === 'number' ? this.options.maxRequeues : 5;
|
|
39
45
|
this.logger = shared.getLogger(this.options, {
|
|
40
46
|
component: this.options.component || 'smtp-pool'
|
|
41
47
|
});
|
|
@@ -79,6 +85,10 @@ class SMTPPool extends EventEmitter {
|
|
|
79
85
|
*/
|
|
80
86
|
send(mail, callback) {
|
|
81
87
|
if (this._closed) {
|
|
88
|
+
// Mail.sendMail ignores the return value, so without a callback its promise would never settle
|
|
89
|
+
const err = new Error('Connection pool was closed');
|
|
90
|
+
err.code = errors.ECONNECTION;
|
|
91
|
+
setImmediate(() => callback(err));
|
|
82
92
|
return false;
|
|
83
93
|
}
|
|
84
94
|
this._queue.push({
|
|
@@ -292,15 +302,22 @@ class SMTPPool extends EventEmitter {
|
|
|
292
302
|
// Note that we must wait a bit.. because the callback of the 'error' handler might be called
|
|
293
303
|
// in the next event loop
|
|
294
304
|
setTimeout(() => {
|
|
305
|
+
let delay = 0;
|
|
295
306
|
if (connection.queueEntry) {
|
|
296
307
|
if (this._shouldRequeuOnConnectionClose(connection.queueEntry)) {
|
|
297
|
-
this._requeueEntryOnConnectionClose(connection);
|
|
308
|
+
delay = this._requeueEntryOnConnectionClose(connection);
|
|
298
309
|
}
|
|
299
310
|
else {
|
|
300
311
|
this._failDeliveryOnConnectionClose(connection);
|
|
301
312
|
}
|
|
302
313
|
}
|
|
303
|
-
|
|
314
|
+
if (delay) {
|
|
315
|
+
// back off, a server that keeps dropping connections is not hammered
|
|
316
|
+
setTimeout(() => this._continueProcessing(), delay);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
this._continueProcessing();
|
|
320
|
+
}
|
|
304
321
|
}, 50);
|
|
305
322
|
}
|
|
306
323
|
else {
|
|
@@ -315,7 +332,7 @@ class SMTPPool extends EventEmitter {
|
|
|
315
332
|
}
|
|
316
333
|
/** @internal */
|
|
317
334
|
_shouldRequeuOnConnectionClose(queueEntry) {
|
|
318
|
-
if (this.options.maxRequeues
|
|
335
|
+
if (this.options.maxRequeues < 0) {
|
|
319
336
|
return true;
|
|
320
337
|
}
|
|
321
338
|
return queueEntry.requeueAttempts < this.options.maxRequeues;
|
|
@@ -324,7 +341,9 @@ class SMTPPool extends EventEmitter {
|
|
|
324
341
|
_failDeliveryOnConnectionClose(connection) {
|
|
325
342
|
if (connection.queueEntry && connection.queueEntry.callback) {
|
|
326
343
|
try {
|
|
327
|
-
|
|
344
|
+
const err = new Error('Reached maximum number of retries after connection was closed');
|
|
345
|
+
err.code = errors.ECONNECTION;
|
|
346
|
+
connection.queueEntry.callback(err);
|
|
328
347
|
}
|
|
329
348
|
catch (E) {
|
|
330
349
|
this.logger.error({
|
|
@@ -339,6 +358,7 @@ class SMTPPool extends EventEmitter {
|
|
|
339
358
|
}
|
|
340
359
|
/** @internal */
|
|
341
360
|
_requeueEntryOnConnectionClose(connection) {
|
|
361
|
+
const delay = Math.min(REQUEUE_BASE_DELAY * 2 ** connection.queueEntry.requeueAttempts, REQUEUE_MAX_DELAY);
|
|
342
362
|
connection.queueEntry.requeueAttempts += 1;
|
|
343
363
|
this.logger.debug({
|
|
344
364
|
tnx: 'pool',
|
|
@@ -348,6 +368,7 @@ class SMTPPool extends EventEmitter {
|
|
|
348
368
|
}, 'Re-queued message <%s> for #%s. Attempt: #%s', connection.queueEntry.messageId, connection.id, connection.queueEntry.requeueAttempts);
|
|
349
369
|
this._queue.unshift(connection.queueEntry);
|
|
350
370
|
connection.queueEntry = false;
|
|
371
|
+
return delay;
|
|
351
372
|
}
|
|
352
373
|
/**
|
|
353
374
|
* Continue to process message if the pool hasn't closed
|
|
@@ -424,10 +445,12 @@ class SMTPPool extends EventEmitter {
|
|
|
424
445
|
callback = shared.callbackPromise(resolve, reject);
|
|
425
446
|
});
|
|
426
447
|
}
|
|
448
|
+
// the error paths hand over the error alone
|
|
449
|
+
const done = callback;
|
|
427
450
|
const auth = new PoolResource(this).auth;
|
|
428
451
|
this.getSocket(this.options, (err, socketOptions) => {
|
|
429
452
|
if (err) {
|
|
430
|
-
return
|
|
453
|
+
return done(err);
|
|
431
454
|
}
|
|
432
455
|
let options = this.options;
|
|
433
456
|
if (socketOptions && socketOptions.connection) {
|
|
@@ -449,14 +472,14 @@ class SMTPPool extends EventEmitter {
|
|
|
449
472
|
}
|
|
450
473
|
returned = true;
|
|
451
474
|
connection.close();
|
|
452
|
-
return
|
|
475
|
+
return done(err);
|
|
453
476
|
});
|
|
454
477
|
connection.once('end', () => {
|
|
455
478
|
if (returned) {
|
|
456
479
|
return;
|
|
457
480
|
}
|
|
458
481
|
returned = true;
|
|
459
|
-
return
|
|
482
|
+
return done(new Error('Connection closed'));
|
|
460
483
|
});
|
|
461
484
|
const finalize = () => {
|
|
462
485
|
if (returned) {
|
|
@@ -464,12 +487,17 @@ class SMTPPool extends EventEmitter {
|
|
|
464
487
|
}
|
|
465
488
|
returned = true;
|
|
466
489
|
connection.quit();
|
|
467
|
-
return
|
|
490
|
+
return done(null, true);
|
|
468
491
|
};
|
|
469
|
-
connection.connect(
|
|
492
|
+
connection.connect(err => {
|
|
470
493
|
if (returned) {
|
|
471
494
|
return;
|
|
472
495
|
}
|
|
496
|
+
if (err) {
|
|
497
|
+
returned = true;
|
|
498
|
+
connection.close();
|
|
499
|
+
return done(err);
|
|
500
|
+
}
|
|
473
501
|
if (auth && (connection.allowsAuth || options.forceAuth)) {
|
|
474
502
|
connection.login(auth, err => {
|
|
475
503
|
if (returned) {
|
|
@@ -478,7 +506,7 @@ class SMTPPool extends EventEmitter {
|
|
|
478
506
|
if (err) {
|
|
479
507
|
returned = true;
|
|
480
508
|
connection.close();
|
|
481
|
-
return
|
|
509
|
+
return done(err);
|
|
482
510
|
}
|
|
483
511
|
finalize();
|
|
484
512
|
});
|
|
@@ -488,7 +516,7 @@ class SMTPPool extends EventEmitter {
|
|
|
488
516
|
err.code = errors.ENOAUTH;
|
|
489
517
|
returned = true;
|
|
490
518
|
connection.close();
|
|
491
|
-
return
|
|
519
|
+
return done(err);
|
|
492
520
|
}
|
|
493
521
|
else {
|
|
494
522
|
finalize();
|