@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.
Files changed (53) hide show
  1. package/dist/externalVersion.js +6 -6
  2. package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
  3. package/dist/node_modules/joi/lib/index.js +1 -1
  4. package/dist/node_modules/joi/lib/messages.js +35 -6
  5. package/dist/node_modules/joi/lib/types/keys.js +18 -1
  6. package/dist/node_modules/joi/lib/types/link.js +18 -2
  7. package/dist/node_modules/joi/lib/types/string.js +2 -2
  8. package/dist/node_modules/joi/package.json +1 -1
  9. package/dist/node_modules/nodemailer/.ncurc.js +2 -0
  10. package/dist/node_modules/nodemailer/.prettierignore +8 -0
  11. package/dist/node_modules/nodemailer/.prettierrc +12 -0
  12. package/dist/node_modules/nodemailer/.prettierrc.js +2 -0
  13. package/dist/node_modules/nodemailer/.release-please-config.json +9 -0
  14. package/dist/node_modules/nodemailer/eslint.config.js +88 -0
  15. package/dist/node_modules/nodemailer/lib/addressparser/index.js +314 -71
  16. package/dist/node_modules/nodemailer/lib/base64/index.js +9 -13
  17. package/dist/node_modules/nodemailer/lib/dkim/index.js +17 -18
  18. package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +12 -13
  19. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +3 -3
  20. package/dist/node_modules/nodemailer/lib/dkim/sign.js +22 -18
  21. package/dist/node_modules/nodemailer/lib/errors.js +59 -0
  22. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +14 -19
  23. package/dist/node_modules/nodemailer/lib/fetch/index.js +164 -27
  24. package/dist/node_modules/nodemailer/lib/json-transport/index.js +4 -4
  25. package/dist/node_modules/nodemailer/lib/mail-composer/index.js +229 -155
  26. package/dist/node_modules/nodemailer/lib/mailer/index.js +106 -54
  27. package/dist/node_modules/nodemailer/lib/mailer/mail-message.js +106 -68
  28. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +105 -59
  29. package/dist/node_modules/nodemailer/lib/mime-funcs/mime-types.js +21 -14
  30. package/dist/node_modules/nodemailer/lib/mime-node/index.js +389 -137
  31. package/dist/node_modules/nodemailer/lib/mime-node/last-newline.js +1 -1
  32. package/dist/node_modules/nodemailer/lib/mime-node/le-unix.js +4 -7
  33. package/dist/node_modules/nodemailer/lib/mime-node/le-windows.js +1 -4
  34. package/dist/node_modules/nodemailer/lib/nodemailer.js +1 -1
  35. package/dist/node_modules/nodemailer/lib/punycode/index.js +1 -1
  36. package/dist/node_modules/nodemailer/lib/qp/index.js +33 -22
  37. package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +54 -44
  38. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +110 -193
  39. package/dist/node_modules/nodemailer/lib/shared/index.js +299 -240
  40. package/dist/node_modules/nodemailer/lib/shared/objects.js +42 -0
  41. package/dist/node_modules/nodemailer/lib/shared/url.js +151 -0
  42. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +3 -6
  43. package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +50 -19
  44. package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +415 -223
  45. package/dist/node_modules/nodemailer/lib/smtp-pool/index.js +27 -34
  46. package/dist/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +19 -16
  47. package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +66 -53
  48. package/dist/node_modules/nodemailer/lib/stream-transport/index.js +16 -7
  49. package/dist/node_modules/nodemailer/lib/well-known/index.js +7 -7
  50. package/dist/node_modules/nodemailer/lib/well-known/services.json +328 -38
  51. package/dist/node_modules/nodemailer/lib/xoauth2/index.js +105 -33
  52. package/dist/node_modules/nodemailer/package.json +1 -1
  53. 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:' + connection.version + ']';
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
- let len = this._connections.length;
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
- let invokeCallbacks = () => {
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
- let entry = this._queue.shift();
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
- for (i = 0, len = this._connections.length; i < len; i++) {
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
- let entry = (connection.queueEntry = this._queue.shift());
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
- let connection = new PoolResource(this);
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 !== 'EMAXLIMIT') {
334
- this.logger.error(
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 = connection.queueEntry.requeueAttempts + 1;
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
- let index = this._connections.indexOf(connection);
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
- let now = Date.now();
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
- } else if (!this._rateLimit.timeout) {
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
- let cb = this._rateLimit.waiting.shift();
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
- let auth = new PoolResource(this).auth;
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
- let connection = new SMTPConnection(options);
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
- let finalize = () => {
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
- let err = new Error('Authentication info was not provided');
632
- err.code = 'NoAuth';
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
- let oauth2 = new XOAuth2(this.options.auth, this.logger);
26
- oauth2.provisionCallback = (this.pool.mailer && this.pool.mailer.get('oauth2_provision_cb')) || 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
- let timer = setTimeout(() => {
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
- let err = new Error('Unexpected socket close');
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 = 'ETLS';
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 (E) {
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
- let envelope = mail.message.getEnvelope();
182
- let messageId = mail.message.messageId();
180
+ const envelope = mail.message.getEnvelope();
181
+ const messageId = mail.message.messageId();
183
182
 
184
- let recipients = [].concat(envelope.to || []);
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 = 'EMAXLIMIT';
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:' + connection.version + ']';
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
- let hasAuth = false;
80
- let authData = {};
81
-
82
- if (this.options.auth && typeof this.options.auth === 'object') {
83
- Object.keys(this.options.auth).forEach(key => {
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 (!hasAuth) {
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
- let oauth2 = new XOAuth2(authData, this.logger);
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
- let connection = new SMTPConnection(options);
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
- let timer = setTimeout(() => {
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
- let err = new Error('Unexpected socket close');
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 = 'ETLS';
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 (E) {
200
+ } catch (_E) {
201
201
  // Ignore. Happens on envs with non-node timer implementation
202
202
  }
203
203
  });
204
204
 
205
- let sendMessage = () => {
206
- let envelope = mail.message.getEnvelope();
207
- let messageId = mail.message.messageId();
205
+ const sendMessage = () => {
206
+ const envelope = mail.message.getEnvelope();
207
+ const messageId = mail.message.messageId();
208
208
 
209
- let recipients = [].concat(envelope.to || []);
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
- let auth = this.getAuth(mail.data.auth);
275
+ perCallAuth = this.getAuth(mail.data.auth);
270
276
 
271
- if (auth && (connection.allowsAuth || options.forceAuth)) {
272
- connection.login(auth, err => {
273
- if (auth && auth !== this.auth && auth.oauth2) {
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
- let connection = new SMTPConnection(options);
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
- let finalize = () => {
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
- let authData = this.getAuth({});
383
+ perCallAuth = this.getAuth({});
373
384
 
374
- if (authData && (connection.allowsAuth || options.forceAuth)) {
375
- connection.login(authData, err => {
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 (!authData && connection.allowsAuth && options.forceAuth) {
389
- let err = new Error('Authentication info was not provided');
390
- err.code = 'NoAuth';
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
- let envelope = mail.data.envelope || mail.message.getEnvelope();
44
- let messageId = mail.message.messageId();
45
+ const envelope = mail.message.getEnvelope();
46
+ const messageId = mail.message.messageId();
45
47
 
46
- let recipients = [].concat(envelope.to || []);
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: mail.data.envelope || mail.message.getEnvelope(),
103
+ envelope,
95
104
  messageId,
96
105
  message: stream
97
106
  });
98
107
  }
99
108
 
100
- let chunks = [];
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: mail.data.envelope || mail.message.getEnvelope(),
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
- let service = services[key];
7
+ const service = services[key];
8
+ const normalizedService = normalizeService(service);
8
9
 
9
- normalized[normalizeKey(key)] = normalizeService(service);
10
+ normalized[normalizeKey(key)] = normalizedService;
10
11
 
11
12
  [].concat(service.aliases || []).forEach(alias => {
12
- normalized[normalizeKey(alias)] = normalizeService(service);
13
+ normalized[normalizeKey(alias)] = normalizedService;
13
14
  });
14
15
 
15
16
  [].concat(service.domains || []).forEach(domain => {
16
- normalized[normalizeKey(domain)] = normalizeService(service);
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
- let filter = ['domains', 'aliases'];
26
- let response = {};
26
+ const response = {};
27
27
 
28
28
  Object.keys(service).forEach(key => {
29
- if (filter.indexOf(key) < 0) {
29
+ if (!['domains', 'aliases'].includes(key)) {
30
30
  response[key] = service[key];
31
31
  }
32
32
  });