@nocobase/plugin-workflow-mailer 2.2.16 → 2.2.18
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/dist/externalVersion.js +6 -6
- package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
- package/dist/node_modules/joi/lib/index.js +1 -1
- package/dist/node_modules/joi/lib/messages.js +35 -6
- package/dist/node_modules/joi/lib/types/keys.js +18 -1
- package/dist/node_modules/joi/lib/types/link.js +18 -2
- package/dist/node_modules/joi/lib/types/string.js +2 -2
- package/dist/node_modules/joi/package.json +1 -1
- package/dist/node_modules/nodemailer/.ncurc.js +2 -0
- package/dist/node_modules/nodemailer/.prettierignore +8 -0
- package/dist/node_modules/nodemailer/.prettierrc +12 -0
- package/dist/node_modules/nodemailer/.prettierrc.js +2 -0
- package/dist/node_modules/nodemailer/.release-please-config.json +9 -0
- package/dist/node_modules/nodemailer/eslint.config.js +88 -0
- package/dist/node_modules/nodemailer/lib/addressparser/index.js +314 -71
- package/dist/node_modules/nodemailer/lib/base64/index.js +9 -13
- package/dist/node_modules/nodemailer/lib/dkim/index.js +17 -18
- package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +12 -13
- package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +3 -3
- package/dist/node_modules/nodemailer/lib/dkim/sign.js +22 -18
- package/dist/node_modules/nodemailer/lib/errors.js +59 -0
- package/dist/node_modules/nodemailer/lib/fetch/cookies.js +14 -19
- package/dist/node_modules/nodemailer/lib/fetch/index.js +164 -27
- package/dist/node_modules/nodemailer/lib/json-transport/index.js +4 -4
- package/dist/node_modules/nodemailer/lib/mail-composer/index.js +229 -155
- package/dist/node_modules/nodemailer/lib/mailer/index.js +106 -54
- package/dist/node_modules/nodemailer/lib/mailer/mail-message.js +106 -68
- package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +105 -59
- package/dist/node_modules/nodemailer/lib/mime-funcs/mime-types.js +21 -14
- package/dist/node_modules/nodemailer/lib/mime-node/index.js +389 -137
- package/dist/node_modules/nodemailer/lib/mime-node/last-newline.js +1 -1
- package/dist/node_modules/nodemailer/lib/mime-node/le-unix.js +4 -7
- package/dist/node_modules/nodemailer/lib/mime-node/le-windows.js +1 -4
- package/dist/node_modules/nodemailer/lib/nodemailer.js +1 -1
- package/dist/node_modules/nodemailer/lib/punycode/index.js +1 -1
- package/dist/node_modules/nodemailer/lib/qp/index.js +33 -22
- package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +54 -44
- package/dist/node_modules/nodemailer/lib/ses-transport/index.js +110 -193
- package/dist/node_modules/nodemailer/lib/shared/index.js +299 -240
- package/dist/node_modules/nodemailer/lib/shared/objects.js +42 -0
- package/dist/node_modules/nodemailer/lib/shared/url.js +151 -0
- package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +3 -6
- package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +50 -19
- package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +415 -223
- package/dist/node_modules/nodemailer/lib/smtp-pool/index.js +27 -34
- package/dist/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +19 -16
- package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +66 -53
- package/dist/node_modules/nodemailer/lib/stream-transport/index.js +16 -7
- package/dist/node_modules/nodemailer/lib/well-known/index.js +7 -7
- package/dist/node_modules/nodemailer/lib/well-known/services.json +328 -38
- package/dist/node_modules/nodemailer/lib/xoauth2/index.js +105 -33
- package/dist/node_modules/nodemailer/package.json +1 -1
- package/package.json +4 -4
|
@@ -5,6 +5,7 @@ const PoolResource = require('./pool-resource');
|
|
|
5
5
|
const SMTPConnection = require('../smtp-connection');
|
|
6
6
|
const wellKnown = require('../well-known');
|
|
7
7
|
const shared = require('../shared');
|
|
8
|
+
const errors = require('../errors');
|
|
8
9
|
const packageData = require('../../package.json');
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -50,11 +51,8 @@ class SMTPPool extends EventEmitter {
|
|
|
50
51
|
component: this.options.component || 'smtp-pool'
|
|
51
52
|
});
|
|
52
53
|
|
|
53
|
-
// temporary object
|
|
54
|
-
let connection = new SMTPConnection(this.options);
|
|
55
|
-
|
|
56
54
|
this.name = 'SMTP (pool)';
|
|
57
|
-
this.version = packageData.version + '[client:' +
|
|
55
|
+
this.version = packageData.version + '[client:' + packageData.version + ']';
|
|
58
56
|
|
|
59
57
|
this._rateLimit = {
|
|
60
58
|
counter: 0,
|
|
@@ -122,7 +120,7 @@ class SMTPPool extends EventEmitter {
|
|
|
122
120
|
*/
|
|
123
121
|
close() {
|
|
124
122
|
let connection;
|
|
125
|
-
|
|
123
|
+
const len = this._connections.length;
|
|
126
124
|
this._closed = true;
|
|
127
125
|
|
|
128
126
|
// clear rate limit timer if it exists
|
|
@@ -163,7 +161,7 @@ class SMTPPool extends EventEmitter {
|
|
|
163
161
|
}
|
|
164
162
|
|
|
165
163
|
// make sure that entire queue would be cleaned
|
|
166
|
-
|
|
164
|
+
const invokeCallbacks = () => {
|
|
167
165
|
if (!this._queue.length) {
|
|
168
166
|
this.logger.debug(
|
|
169
167
|
{
|
|
@@ -173,7 +171,7 @@ class SMTPPool extends EventEmitter {
|
|
|
173
171
|
);
|
|
174
172
|
return;
|
|
175
173
|
}
|
|
176
|
-
|
|
174
|
+
const entry = this._queue.shift();
|
|
177
175
|
if (entry && typeof entry.callback === 'function') {
|
|
178
176
|
try {
|
|
179
177
|
entry.callback(new Error('Connection pool was closed'));
|
|
@@ -200,9 +198,6 @@ class SMTPPool extends EventEmitter {
|
|
|
200
198
|
* an available connection, then use this connection to send the mail
|
|
201
199
|
*/
|
|
202
200
|
_processMessages() {
|
|
203
|
-
let connection;
|
|
204
|
-
let i, len;
|
|
205
|
-
|
|
206
201
|
// do nothing if already closed
|
|
207
202
|
if (this._closed) {
|
|
208
203
|
return;
|
|
@@ -219,12 +214,7 @@ class SMTPPool extends EventEmitter {
|
|
|
219
214
|
}
|
|
220
215
|
|
|
221
216
|
// find first available connection
|
|
222
|
-
|
|
223
|
-
if (this._connections[i].available) {
|
|
224
|
-
connection = this._connections[i];
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
217
|
+
let connection = this._connections.find(c => c.available);
|
|
228
218
|
|
|
229
219
|
if (!connection && this._connections.length < this.options.maxConnections) {
|
|
230
220
|
connection = this._createConnection();
|
|
@@ -242,7 +232,7 @@ class SMTPPool extends EventEmitter {
|
|
|
242
232
|
this.emit('idle');
|
|
243
233
|
}
|
|
244
234
|
|
|
245
|
-
|
|
235
|
+
const entry = (connection.queueEntry = this._queue.shift());
|
|
246
236
|
entry.messageId = (connection.queueEntry.mail.message.getHeader('message-id') || '').replace(/[<>\s]/g, '');
|
|
247
237
|
|
|
248
238
|
connection.available = false;
|
|
@@ -293,7 +283,7 @@ class SMTPPool extends EventEmitter {
|
|
|
293
283
|
* Creates a new pool resource
|
|
294
284
|
*/
|
|
295
285
|
_createConnection() {
|
|
296
|
-
|
|
286
|
+
const connection = new PoolResource(this);
|
|
297
287
|
|
|
298
288
|
connection.id = ++this._connectionCounter;
|
|
299
289
|
|
|
@@ -330,8 +320,8 @@ class SMTPPool extends EventEmitter {
|
|
|
330
320
|
|
|
331
321
|
// resource is terminated with an error
|
|
332
322
|
connection.once('error', err => {
|
|
333
|
-
if (err.code !==
|
|
334
|
-
this.logger.
|
|
323
|
+
if (err.code !== errors.EMAXLIMIT) {
|
|
324
|
+
this.logger.warn(
|
|
335
325
|
{
|
|
336
326
|
err,
|
|
337
327
|
tnx: 'pool',
|
|
@@ -406,6 +396,10 @@ class SMTPPool extends EventEmitter {
|
|
|
406
396
|
this._continueProcessing();
|
|
407
397
|
}, 50);
|
|
408
398
|
} else {
|
|
399
|
+
if (!this._closed && this.idling && !this._connections.length) {
|
|
400
|
+
this.emit('clear');
|
|
401
|
+
}
|
|
402
|
+
|
|
409
403
|
this._continueProcessing();
|
|
410
404
|
}
|
|
411
405
|
});
|
|
@@ -445,7 +439,7 @@ class SMTPPool extends EventEmitter {
|
|
|
445
439
|
}
|
|
446
440
|
|
|
447
441
|
_requeueEntryOnConnectionClose(connection) {
|
|
448
|
-
connection.queueEntry.requeueAttempts
|
|
442
|
+
connection.queueEntry.requeueAttempts += 1;
|
|
449
443
|
this.logger.debug(
|
|
450
444
|
{
|
|
451
445
|
tnx: 'pool',
|
|
@@ -479,7 +473,7 @@ class SMTPPool extends EventEmitter {
|
|
|
479
473
|
* @param {Object} connection The PoolResource to remove
|
|
480
474
|
*/
|
|
481
475
|
_removeConnection(connection) {
|
|
482
|
-
|
|
476
|
+
const index = this._connections.indexOf(connection);
|
|
483
477
|
|
|
484
478
|
if (index !== -1) {
|
|
485
479
|
this._connections.splice(index, 1);
|
|
@@ -496,7 +490,7 @@ class SMTPPool extends EventEmitter {
|
|
|
496
490
|
return callback();
|
|
497
491
|
}
|
|
498
492
|
|
|
499
|
-
|
|
493
|
+
const now = Date.now();
|
|
500
494
|
|
|
501
495
|
if (this._rateLimit.counter < this._rateLimit.limit) {
|
|
502
496
|
return callback();
|
|
@@ -506,7 +500,9 @@ class SMTPPool extends EventEmitter {
|
|
|
506
500
|
|
|
507
501
|
if (this._rateLimit.checkpoint <= now - this._rateLimit.delta) {
|
|
508
502
|
return this._clearRateLimit();
|
|
509
|
-
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (!this._rateLimit.timeout) {
|
|
510
506
|
this._rateLimit.timeout = setTimeout(() => this._clearRateLimit(), this._rateLimit.delta - (now - this._rateLimit.checkpoint));
|
|
511
507
|
this._rateLimit.checkpoint = now;
|
|
512
508
|
}
|
|
@@ -523,7 +519,7 @@ class SMTPPool extends EventEmitter {
|
|
|
523
519
|
|
|
524
520
|
// resume all paused connections
|
|
525
521
|
while (this._rateLimit.waiting.length) {
|
|
526
|
-
|
|
522
|
+
const cb = this._rateLimit.waiting.shift();
|
|
527
523
|
setImmediate(cb);
|
|
528
524
|
}
|
|
529
525
|
}
|
|
@@ -549,7 +545,7 @@ class SMTPPool extends EventEmitter {
|
|
|
549
545
|
});
|
|
550
546
|
}
|
|
551
547
|
|
|
552
|
-
|
|
548
|
+
const auth = new PoolResource(this).auth;
|
|
553
549
|
|
|
554
550
|
this.getSocket(this.options, (err, socketOptions) => {
|
|
555
551
|
if (err) {
|
|
@@ -573,13 +569,10 @@ class SMTPPool extends EventEmitter {
|
|
|
573
569
|
options.host || '',
|
|
574
570
|
options.port || ''
|
|
575
571
|
);
|
|
576
|
-
options = shared.assign(false, options);
|
|
577
|
-
Object.keys(socketOptions).forEach(key => {
|
|
578
|
-
options[key] = socketOptions[key];
|
|
579
|
-
});
|
|
572
|
+
options = Object.assign(shared.assign(false, options), socketOptions);
|
|
580
573
|
}
|
|
581
574
|
|
|
582
|
-
|
|
575
|
+
const connection = new SMTPConnection(options);
|
|
583
576
|
let returned = false;
|
|
584
577
|
|
|
585
578
|
connection.once('error', err => {
|
|
@@ -599,7 +592,7 @@ class SMTPPool extends EventEmitter {
|
|
|
599
592
|
return callback(new Error('Connection closed'));
|
|
600
593
|
});
|
|
601
594
|
|
|
602
|
-
|
|
595
|
+
const finalize = () => {
|
|
603
596
|
if (returned) {
|
|
604
597
|
return;
|
|
605
598
|
}
|
|
@@ -628,8 +621,8 @@ class SMTPPool extends EventEmitter {
|
|
|
628
621
|
finalize();
|
|
629
622
|
});
|
|
630
623
|
} else if (!auth && connection.allowsAuth && options.forceAuth) {
|
|
631
|
-
|
|
632
|
-
err.code =
|
|
624
|
+
const err = new Error('Authentication info was not provided');
|
|
625
|
+
err.code = errors.ENOAUTH;
|
|
633
626
|
|
|
634
627
|
returned = true;
|
|
635
628
|
connection.close();
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const SMTPConnection = require('../smtp-connection');
|
|
4
4
|
const assign = require('../shared').assign;
|
|
5
5
|
const XOAuth2 = require('../xoauth2');
|
|
6
|
+
const errors = require('../errors');
|
|
6
7
|
const EventEmitter = require('events');
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -22,8 +23,9 @@ class PoolResource extends EventEmitter {
|
|
|
22
23
|
if (this.options.auth) {
|
|
23
24
|
switch ((this.options.auth.type || '').toString().toUpperCase()) {
|
|
24
25
|
case 'OAUTH2': {
|
|
25
|
-
|
|
26
|
-
oauth2.provisionCallback =
|
|
26
|
+
const oauth2 = new XOAuth2(this.options.auth, this.logger);
|
|
27
|
+
oauth2.provisionCallback =
|
|
28
|
+
(this.pool.mailer && this.pool.mailer.get('oauth2_provision_cb')) || oauth2.provisionCallback;
|
|
27
29
|
this.auth = {
|
|
28
30
|
type: 'OAUTH2',
|
|
29
31
|
user: this.options.auth.user,
|
|
@@ -88,10 +90,7 @@ class PoolResource extends EventEmitter {
|
|
|
88
90
|
options.port || ''
|
|
89
91
|
);
|
|
90
92
|
|
|
91
|
-
options = assign(false, options);
|
|
92
|
-
Object.keys(socketOptions).forEach(key => {
|
|
93
|
-
options[key] = socketOptions[key];
|
|
94
|
-
});
|
|
93
|
+
options = Object.assign(assign(false, options), socketOptions);
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
this.connection = new SMTPConnection(options);
|
|
@@ -112,22 +111,22 @@ class PoolResource extends EventEmitter {
|
|
|
112
111
|
}
|
|
113
112
|
returned = true;
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
const timer = setTimeout(() => {
|
|
116
115
|
if (returned) {
|
|
117
116
|
return;
|
|
118
117
|
}
|
|
119
118
|
// still have not returned, this means we have an unexpected connection close
|
|
120
|
-
|
|
119
|
+
const err = new Error('Unexpected socket close');
|
|
121
120
|
if (this.connection && this.connection._socket && this.connection._socket.upgrading) {
|
|
122
121
|
// starttls connection errors
|
|
123
|
-
err.code =
|
|
122
|
+
err.code = errors.ETLS;
|
|
124
123
|
}
|
|
125
124
|
callback(err);
|
|
126
125
|
}, 1000);
|
|
127
126
|
|
|
128
127
|
try {
|
|
129
128
|
timer.unref();
|
|
130
|
-
} catch (
|
|
129
|
+
} catch (_E) {
|
|
131
130
|
// Ignore. Happens on envs with non-node timer implementation
|
|
132
131
|
}
|
|
133
132
|
});
|
|
@@ -178,10 +177,10 @@ class PoolResource extends EventEmitter {
|
|
|
178
177
|
});
|
|
179
178
|
}
|
|
180
179
|
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
const envelope = mail.message.getEnvelope();
|
|
181
|
+
const messageId = mail.message.messageId();
|
|
183
182
|
|
|
184
|
-
|
|
183
|
+
const recipients = [].concat(envelope.to || []);
|
|
185
184
|
if (recipients.length > 3) {
|
|
186
185
|
recipients.push('...and ' + recipients.splice(2).length + ' more');
|
|
187
186
|
}
|
|
@@ -201,6 +200,11 @@ class PoolResource extends EventEmitter {
|
|
|
201
200
|
envelope.dsn = mail.data.dsn;
|
|
202
201
|
}
|
|
203
202
|
|
|
203
|
+
// RFC 8689: Pass requireTLSExtensionEnabled to envelope for MAIL FROM parameter
|
|
204
|
+
if (mail.data.requireTLSExtensionEnabled) {
|
|
205
|
+
envelope.requireTLSExtensionEnabled = mail.data.requireTLSExtensionEnabled;
|
|
206
|
+
}
|
|
207
|
+
|
|
204
208
|
this.connection.send(envelope, mail.message.createReadStream(), (err, info) => {
|
|
205
209
|
this.messages++;
|
|
206
210
|
|
|
@@ -217,10 +221,9 @@ class PoolResource extends EventEmitter {
|
|
|
217
221
|
info.messageId = messageId;
|
|
218
222
|
|
|
219
223
|
setImmediate(() => {
|
|
220
|
-
let err;
|
|
221
224
|
if (this.messages >= this.options.maxMessages) {
|
|
222
|
-
err = new Error('Resource exhausted');
|
|
223
|
-
err.code =
|
|
225
|
+
const err = new Error('Resource exhausted');
|
|
226
|
+
err.code = errors.EMAXLIMIT;
|
|
224
227
|
this.connection.close();
|
|
225
228
|
this.emit('error', err);
|
|
226
229
|
} else {
|
|
@@ -5,6 +5,7 @@ const SMTPConnection = require('../smtp-connection');
|
|
|
5
5
|
const wellKnown = require('../well-known');
|
|
6
6
|
const shared = require('../shared');
|
|
7
7
|
const XOAuth2 = require('../xoauth2');
|
|
8
|
+
const errors = require('../errors');
|
|
8
9
|
const packageData = require('../../package.json');
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -48,11 +49,8 @@ class SMTPTransport extends EventEmitter {
|
|
|
48
49
|
component: this.options.component || 'smtp-transport'
|
|
49
50
|
});
|
|
50
51
|
|
|
51
|
-
// temporary object
|
|
52
|
-
let connection = new SMTPConnection(this.options);
|
|
53
|
-
|
|
54
52
|
this.name = 'SMTP';
|
|
55
|
-
this.version = packageData.version + '[client:' +
|
|
53
|
+
this.version = packageData.version + '[client:' + packageData.version + ']';
|
|
56
54
|
|
|
57
55
|
if (this.options.auth) {
|
|
58
56
|
this.auth = this.getAuth({});
|
|
@@ -73,27 +71,22 @@ class SMTPTransport extends EventEmitter {
|
|
|
73
71
|
|
|
74
72
|
getAuth(authOpts) {
|
|
75
73
|
if (!authOpts) {
|
|
74
|
+
if (this.auth && this.auth.oauth2 && this.mailer) {
|
|
75
|
+
// Transport-level auth is resolved in the constructor, before the Mail wrapper
|
|
76
|
+
// assigns `this.mailer`, so a provision callback registered with
|
|
77
|
+
// `transporter.set('oauth2_provision_cb', ...)` has to be re-checked here
|
|
78
|
+
this.auth.oauth2.provisionCallback = this.mailer.get('oauth2_provision_cb') || this.auth.oauth2.provisionCallback;
|
|
79
|
+
}
|
|
76
80
|
return this.auth;
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
hasAuth = true;
|
|
85
|
-
authData[key] = this.options.auth[key];
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (authOpts && typeof authOpts === 'object') {
|
|
90
|
-
Object.keys(authOpts).forEach(key => {
|
|
91
|
-
hasAuth = true;
|
|
92
|
-
authData[key] = authOpts[key];
|
|
93
|
-
});
|
|
94
|
-
}
|
|
83
|
+
const authData = Object.assign(
|
|
84
|
+
{},
|
|
85
|
+
this.options.auth && typeof this.options.auth === 'object' ? this.options.auth : {},
|
|
86
|
+
typeof authOpts === 'object' ? authOpts : {}
|
|
87
|
+
);
|
|
95
88
|
|
|
96
|
-
if (
|
|
89
|
+
if (Object.keys(authData).length === 0) {
|
|
97
90
|
return false;
|
|
98
91
|
}
|
|
99
92
|
|
|
@@ -102,7 +95,7 @@ class SMTPTransport extends EventEmitter {
|
|
|
102
95
|
if (!authData.service && !authData.user) {
|
|
103
96
|
return false;
|
|
104
97
|
}
|
|
105
|
-
|
|
98
|
+
const oauth2 = new XOAuth2(authData, this.logger);
|
|
106
99
|
oauth2.provisionCallback = (this.mailer && this.mailer.get('oauth2_provision_cb')) || oauth2.provisionCallback;
|
|
107
100
|
oauth2.on('token', token => this.mailer.emit('token', token));
|
|
108
101
|
oauth2.on('error', err => this.emit('error', err));
|
|
@@ -159,19 +152,25 @@ class SMTPTransport extends EventEmitter {
|
|
|
159
152
|
);
|
|
160
153
|
|
|
161
154
|
// only copy options if we need to modify it
|
|
162
|
-
options = shared.assign(false, options);
|
|
163
|
-
Object.keys(socketOptions).forEach(key => {
|
|
164
|
-
options[key] = socketOptions[key];
|
|
165
|
-
});
|
|
155
|
+
options = Object.assign(shared.assign(false, options), socketOptions);
|
|
166
156
|
}
|
|
167
157
|
|
|
168
|
-
|
|
158
|
+
const connection = new SMTPConnection(options);
|
|
159
|
+
|
|
160
|
+
let perCallAuth;
|
|
161
|
+
const cleanupPerCallAuth = () => {
|
|
162
|
+
if (perCallAuth && perCallAuth !== this.auth && perCallAuth.oauth2) {
|
|
163
|
+
perCallAuth.oauth2.removeAllListeners();
|
|
164
|
+
}
|
|
165
|
+
perCallAuth = null;
|
|
166
|
+
};
|
|
169
167
|
|
|
170
168
|
connection.once('error', err => {
|
|
171
169
|
if (returned) {
|
|
172
170
|
return;
|
|
173
171
|
}
|
|
174
172
|
returned = true;
|
|
173
|
+
cleanupPerCallAuth();
|
|
175
174
|
connection.close();
|
|
176
175
|
return callback(err);
|
|
177
176
|
});
|
|
@@ -181,32 +180,33 @@ class SMTPTransport extends EventEmitter {
|
|
|
181
180
|
return;
|
|
182
181
|
}
|
|
183
182
|
|
|
184
|
-
|
|
183
|
+
const timer = setTimeout(() => {
|
|
185
184
|
if (returned) {
|
|
186
185
|
return;
|
|
187
186
|
}
|
|
188
187
|
returned = true;
|
|
188
|
+
cleanupPerCallAuth();
|
|
189
189
|
// still have not returned, this means we have an unexpected connection close
|
|
190
|
-
|
|
190
|
+
const err = new Error('Unexpected socket close');
|
|
191
191
|
if (connection && connection._socket && connection._socket.upgrading) {
|
|
192
192
|
// starttls connection errors
|
|
193
|
-
err.code =
|
|
193
|
+
err.code = errors.ETLS;
|
|
194
194
|
}
|
|
195
195
|
callback(err);
|
|
196
196
|
}, 1000);
|
|
197
197
|
|
|
198
198
|
try {
|
|
199
199
|
timer.unref();
|
|
200
|
-
} catch (
|
|
200
|
+
} catch (_E) {
|
|
201
201
|
// Ignore. Happens on envs with non-node timer implementation
|
|
202
202
|
}
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
const sendMessage = () => {
|
|
206
|
+
const envelope = mail.message.getEnvelope();
|
|
207
|
+
const messageId = mail.message.messageId();
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
const recipients = [].concat(envelope.to || []);
|
|
210
210
|
if (recipients.length > 3) {
|
|
211
211
|
recipients.push('...and ' + recipients.splice(2).length + ' more');
|
|
212
212
|
}
|
|
@@ -215,6 +215,11 @@ class SMTPTransport extends EventEmitter {
|
|
|
215
215
|
envelope.dsn = mail.data.dsn;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
// RFC 8689: Pass requireTLSExtensionEnabled to envelope for MAIL FROM parameter
|
|
219
|
+
if (mail.data.requireTLSExtensionEnabled) {
|
|
220
|
+
envelope.requireTLSExtensionEnabled = mail.data.requireTLSExtensionEnabled;
|
|
221
|
+
}
|
|
222
|
+
|
|
218
223
|
this.logger.info(
|
|
219
224
|
{
|
|
220
225
|
tnx: 'send',
|
|
@@ -227,6 +232,7 @@ class SMTPTransport extends EventEmitter {
|
|
|
227
232
|
|
|
228
233
|
connection.send(envelope, mail.message.createReadStream(), (err, info) => {
|
|
229
234
|
returned = true;
|
|
235
|
+
cleanupPerCallAuth();
|
|
230
236
|
connection.close();
|
|
231
237
|
if (err) {
|
|
232
238
|
this.logger.error(
|
|
@@ -266,13 +272,11 @@ class SMTPTransport extends EventEmitter {
|
|
|
266
272
|
return;
|
|
267
273
|
}
|
|
268
274
|
|
|
269
|
-
|
|
275
|
+
perCallAuth = this.getAuth(mail.data.auth);
|
|
270
276
|
|
|
271
|
-
if (
|
|
272
|
-
connection.login(
|
|
273
|
-
|
|
274
|
-
auth.oauth2.removeAllListeners();
|
|
275
|
-
}
|
|
277
|
+
if (perCallAuth && (connection.allowsAuth || options.forceAuth)) {
|
|
278
|
+
connection.login(perCallAuth, err => {
|
|
279
|
+
cleanupPerCallAuth();
|
|
276
280
|
if (returned) {
|
|
277
281
|
return;
|
|
278
282
|
}
|
|
@@ -329,20 +333,25 @@ class SMTPTransport extends EventEmitter {
|
|
|
329
333
|
options.port || ''
|
|
330
334
|
);
|
|
331
335
|
|
|
332
|
-
options = shared.assign(false, options);
|
|
333
|
-
Object.keys(socketOptions).forEach(key => {
|
|
334
|
-
options[key] = socketOptions[key];
|
|
335
|
-
});
|
|
336
|
+
options = Object.assign(shared.assign(false, options), socketOptions);
|
|
336
337
|
}
|
|
337
338
|
|
|
338
|
-
|
|
339
|
+
const connection = new SMTPConnection(options);
|
|
339
340
|
let returned = false;
|
|
341
|
+
let perCallAuth;
|
|
342
|
+
const cleanupPerCallAuth = () => {
|
|
343
|
+
if (perCallAuth && perCallAuth !== this.auth && perCallAuth.oauth2) {
|
|
344
|
+
perCallAuth.oauth2.removeAllListeners();
|
|
345
|
+
}
|
|
346
|
+
perCallAuth = null;
|
|
347
|
+
};
|
|
340
348
|
|
|
341
349
|
connection.once('error', err => {
|
|
342
350
|
if (returned) {
|
|
343
351
|
return;
|
|
344
352
|
}
|
|
345
353
|
returned = true;
|
|
354
|
+
cleanupPerCallAuth();
|
|
346
355
|
connection.close();
|
|
347
356
|
return callback(err);
|
|
348
357
|
});
|
|
@@ -352,14 +361,16 @@ class SMTPTransport extends EventEmitter {
|
|
|
352
361
|
return;
|
|
353
362
|
}
|
|
354
363
|
returned = true;
|
|
364
|
+
cleanupPerCallAuth();
|
|
355
365
|
return callback(new Error('Connection closed'));
|
|
356
366
|
});
|
|
357
367
|
|
|
358
|
-
|
|
368
|
+
const finalize = () => {
|
|
359
369
|
if (returned) {
|
|
360
370
|
return;
|
|
361
371
|
}
|
|
362
372
|
returned = true;
|
|
373
|
+
cleanupPerCallAuth();
|
|
363
374
|
connection.quit();
|
|
364
375
|
return callback(null, true);
|
|
365
376
|
};
|
|
@@ -369,10 +380,11 @@ class SMTPTransport extends EventEmitter {
|
|
|
369
380
|
return;
|
|
370
381
|
}
|
|
371
382
|
|
|
372
|
-
|
|
383
|
+
perCallAuth = this.getAuth({});
|
|
373
384
|
|
|
374
|
-
if (
|
|
375
|
-
connection.login(
|
|
385
|
+
if (perCallAuth && (connection.allowsAuth || options.forceAuth)) {
|
|
386
|
+
connection.login(perCallAuth, err => {
|
|
387
|
+
cleanupPerCallAuth();
|
|
376
388
|
if (returned) {
|
|
377
389
|
return;
|
|
378
390
|
}
|
|
@@ -385,11 +397,12 @@ class SMTPTransport extends EventEmitter {
|
|
|
385
397
|
|
|
386
398
|
finalize();
|
|
387
399
|
});
|
|
388
|
-
} else if (!
|
|
389
|
-
|
|
390
|
-
err.code =
|
|
400
|
+
} else if (!perCallAuth && connection.allowsAuth && options.forceAuth) {
|
|
401
|
+
const err = new Error('Authentication info was not provided');
|
|
402
|
+
err.code = errors.ENOAUTH;
|
|
391
403
|
|
|
392
404
|
returned = true;
|
|
405
|
+
cleanupPerCallAuth();
|
|
393
406
|
connection.close();
|
|
394
407
|
return callback(err);
|
|
395
408
|
} else {
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const packageData = require('../../package.json');
|
|
4
4
|
const shared = require('../shared');
|
|
5
|
+
const LeWindows = require('../mime-node/le-windows');
|
|
6
|
+
const LeUnix = require('../mime-node/le-unix');
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Generates a Transport object for streaming
|
|
@@ -18,7 +20,7 @@ class StreamTransport {
|
|
|
18
20
|
constructor(options) {
|
|
19
21
|
options = options || {};
|
|
20
22
|
|
|
21
|
-
this.options = options
|
|
23
|
+
this.options = options;
|
|
22
24
|
|
|
23
25
|
this.name = 'StreamTransport';
|
|
24
26
|
this.version = packageData.version;
|
|
@@ -40,10 +42,10 @@ class StreamTransport {
|
|
|
40
42
|
// We probably need this in the output
|
|
41
43
|
mail.message.keepBcc = true;
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
const envelope = mail.message.getEnvelope();
|
|
46
|
+
const messageId = mail.message.messageId();
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
const recipients = [].concat(envelope.to || []);
|
|
47
49
|
if (recipients.length > 3) {
|
|
48
50
|
recipients.push('...and ' + recipients.splice(2).length + ' more');
|
|
49
51
|
}
|
|
@@ -63,6 +65,13 @@ class StreamTransport {
|
|
|
63
65
|
|
|
64
66
|
try {
|
|
65
67
|
stream = mail.message.createReadStream();
|
|
68
|
+
if (this.options.newline) {
|
|
69
|
+
// apply the transport-level line ending transform; the message-level
|
|
70
|
+
// `newline` option is handled by MimeNode in createReadStream()
|
|
71
|
+
const sourceStream = stream;
|
|
72
|
+
stream = sourceStream.pipe(this.winbreak ? new LeWindows() : new LeUnix());
|
|
73
|
+
sourceStream.once('error', err => stream.emit('error', err));
|
|
74
|
+
}
|
|
66
75
|
} catch (E) {
|
|
67
76
|
this.logger.error(
|
|
68
77
|
{
|
|
@@ -91,13 +100,13 @@ class StreamTransport {
|
|
|
91
100
|
);
|
|
92
101
|
});
|
|
93
102
|
return done(null, {
|
|
94
|
-
envelope
|
|
103
|
+
envelope,
|
|
95
104
|
messageId,
|
|
96
105
|
message: stream
|
|
97
106
|
});
|
|
98
107
|
}
|
|
99
108
|
|
|
100
|
-
|
|
109
|
+
const chunks = [];
|
|
101
110
|
let chunklen = 0;
|
|
102
111
|
stream.on('readable', () => {
|
|
103
112
|
let chunk;
|
|
@@ -123,7 +132,7 @@ class StreamTransport {
|
|
|
123
132
|
|
|
124
133
|
stream.on('end', () =>
|
|
125
134
|
done(null, {
|
|
126
|
-
envelope
|
|
135
|
+
envelope,
|
|
127
136
|
messageId,
|
|
128
137
|
message: Buffer.concat(chunks, chunklen)
|
|
129
138
|
})
|
|
@@ -4,16 +4,17 @@ const services = require('./services.json');
|
|
|
4
4
|
const normalized = {};
|
|
5
5
|
|
|
6
6
|
Object.keys(services).forEach(key => {
|
|
7
|
-
|
|
7
|
+
const service = services[key];
|
|
8
|
+
const normalizedService = normalizeService(service);
|
|
8
9
|
|
|
9
|
-
normalized[normalizeKey(key)] =
|
|
10
|
+
normalized[normalizeKey(key)] = normalizedService;
|
|
10
11
|
|
|
11
12
|
[].concat(service.aliases || []).forEach(alias => {
|
|
12
|
-
normalized[normalizeKey(alias)] =
|
|
13
|
+
normalized[normalizeKey(alias)] = normalizedService;
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
[].concat(service.domains || []).forEach(domain => {
|
|
16
|
-
normalized[normalizeKey(domain)] =
|
|
17
|
+
normalized[normalizeKey(domain)] = normalizedService;
|
|
17
18
|
});
|
|
18
19
|
});
|
|
19
20
|
|
|
@@ -22,11 +23,10 @@ function normalizeKey(key) {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
function normalizeService(service) {
|
|
25
|
-
|
|
26
|
-
let response = {};
|
|
26
|
+
const response = {};
|
|
27
27
|
|
|
28
28
|
Object.keys(service).forEach(key => {
|
|
29
|
-
if (
|
|
29
|
+
if (!['domains', 'aliases'].includes(key)) {
|
|
30
30
|
response[key] = service[key];
|
|
31
31
|
}
|
|
32
32
|
});
|