@mavogel/awscdk-rootmail 0.1.7 → 0.1.9

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 (167) hide show
  1. package/.jsii +10 -10
  2. package/lib/rootmail.js +1 -1
  3. package/lib/ses-receive.js +1 -1
  4. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +5 -5
  5. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-es/schemas/schemas_0.js +4 -4
  6. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/DescribeDeliveryDestinationsCommand.d.ts +1 -0
  7. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/GetDeliveryDestinationCommand.d.ts +1 -0
  8. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutAccountPolicyCommand.d.ts +4 -1
  9. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutDeliveryDestinationCommand.d.ts +2 -0
  10. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/models/models_0.d.ts +80 -36
  11. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/ts3.4/models/models_0.d.ts +2 -0
  12. package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +1 -1
  13. package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
  14. package/node_modules/@aws-sdk/client-route-53/package.json +1 -1
  15. package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +2 -1
  16. package/node_modules/@aws-sdk/client-s3/dist-es/models/enums.js +1 -0
  17. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetBucketInventoryConfigurationCommand.d.ts +1 -1
  18. package/node_modules/@aws-sdk/client-s3/dist-types/commands/ListBucketInventoryConfigurationsCommand.d.ts +1 -1
  19. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutBucketInventoryConfigurationCommand.d.ts +1 -1
  20. package/node_modules/@aws-sdk/client-s3/dist-types/models/enums.d.ts +1 -0
  21. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/enums.d.ts +1 -0
  22. package/node_modules/@aws-sdk/client-s3/package.json +2 -2
  23. package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
  24. package/node_modules/@aws-sdk/client-ses/package.json +1 -1
  25. package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +9 -3
  26. package/node_modules/@aws-sdk/client-ssm/dist-es/models/enums.js +4 -0
  27. package/node_modules/@aws-sdk/client-ssm/dist-es/schemas/schemas_0.js +3 -2
  28. package/node_modules/@aws-sdk/client-ssm/dist-types/commands/DeleteResourcePolicyCommand.d.ts +6 -0
  29. package/node_modules/@aws-sdk/client-ssm/dist-types/commands/PutResourcePolicyCommand.d.ts +12 -0
  30. package/node_modules/@aws-sdk/client-ssm/dist-types/models/enums.d.ts +12 -0
  31. package/node_modules/@aws-sdk/client-ssm/dist-types/models/models_0.d.ts +20 -1
  32. package/node_modules/@aws-sdk/client-ssm/dist-types/models/models_1.d.ts +2 -2
  33. package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/enums.d.ts +5 -0
  34. package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/models_0.d.ts +2 -0
  35. package/node_modules/@aws-sdk/client-ssm/package.json +1 -1
  36. package/node_modules/@zone-eu/mailsplit/lib/flowed-decoder.js +1 -5
  37. package/node_modules/@zone-eu/mailsplit/lib/headers.js +35 -25
  38. package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +126 -79
  39. package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +27 -5
  40. package/node_modules/@zone-eu/mailsplit/lib/node-rewriter.js +3 -2
  41. package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +0 -3
  42. package/node_modules/@zone-eu/mailsplit/package.json +5 -5
  43. package/node_modules/libbase64/.github/workflows/release.yaml +12 -10
  44. package/node_modules/libbase64/.ncurc.js +7 -1
  45. package/node_modules/libbase64/CHANGELOG.md +7 -0
  46. package/node_modules/libbase64/lib/libbase64.js +27 -0
  47. package/node_modules/libbase64/package.json +4 -4
  48. package/node_modules/libmime/CHANGELOG.md +14 -0
  49. package/node_modules/libmime/lib/libmime.js +41 -21
  50. package/node_modules/libmime/package.json +3 -3
  51. package/node_modules/libqp/.github/workflows/release.yaml +12 -10
  52. package/node_modules/libqp/CHANGELOG.md +7 -0
  53. package/node_modules/libqp/lib/libqp.js +6 -4
  54. package/node_modules/libqp/package.json +2 -2
  55. package/node_modules/libqp/test/libqp-test.js +71 -14
  56. package/node_modules/mailparser/.release-please-manifest.json +1 -1
  57. package/node_modules/mailparser/CHANGELOG.md +42 -0
  58. package/node_modules/mailparser/README.md +5 -0
  59. package/node_modules/mailparser/lib/mail-parser.js +107 -32
  60. package/node_modules/mailparser/lib/simple-parser.js +12 -0
  61. package/node_modules/mailparser/lib/stream-hash.js +1 -1
  62. package/node_modules/mailparser/package.json +6 -6
  63. package/node_modules/nodemailer/CHANGELOG.md +38 -0
  64. package/node_modules/nodemailer/README.md +1 -1
  65. package/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +16 -2
  66. package/node_modules/nodemailer/dist/cjs/addressparser/index.js +147 -28
  67. package/node_modules/nodemailer/dist/cjs/base64/index.js +2 -1
  68. package/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +13 -1
  69. package/node_modules/nodemailer/dist/cjs/dkim/index.js +25 -8
  70. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +10 -1
  71. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +28 -4
  72. package/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +10 -1
  73. package/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +3 -0
  74. package/node_modules/nodemailer/dist/cjs/dkim/sign.js +18 -1
  75. package/node_modules/nodemailer/dist/cjs/errors.d.ts +3 -2
  76. package/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +12 -1
  77. package/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +15 -1
  78. package/node_modules/nodemailer/dist/cjs/fetch/index.js +39 -64
  79. package/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +14 -4
  80. package/node_modules/nodemailer/dist/cjs/json-transport/index.js +2 -0
  81. package/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +8 -3
  82. package/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +43 -25
  83. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +11 -4
  84. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +7 -3
  85. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +198 -84
  86. package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +5 -2
  87. package/node_modules/nodemailer/dist/cjs/mime-node/index.js +2 -1
  88. package/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +38 -16
  89. package/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
  90. package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
  91. package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
  92. package/node_modules/nodemailer/dist/cjs/punycode/index.js +1 -0
  93. package/node_modules/nodemailer/dist/cjs/qp/index.d.ts +2 -0
  94. package/node_modules/nodemailer/dist/cjs/qp/index.js +10 -1
  95. package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +2 -0
  96. package/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +39 -2
  97. package/node_modules/nodemailer/dist/cjs/shared/index.d.ts +43 -7
  98. package/node_modules/nodemailer/dist/cjs/shared/index.js +5 -2
  99. package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +2 -1
  100. package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +32 -24
  101. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +13 -5
  102. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +23 -11
  103. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +59 -24
  104. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +156 -75
  105. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +12 -4
  106. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +39 -11
  107. package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +27 -31
  108. package/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +19 -6
  109. package/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +25 -33
  110. package/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +2 -0
  111. package/node_modules/nodemailer/dist/cjs/well-known/services.js +6 -0
  112. package/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +13 -3
  113. package/node_modules/nodemailer/dist/cjs/xoauth2/index.js +25 -13
  114. package/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +16 -2
  115. package/node_modules/nodemailer/dist/esm/addressparser/index.js +147 -27
  116. package/node_modules/nodemailer/dist/esm/base64/index.js +2 -1
  117. package/node_modules/nodemailer/dist/esm/dkim/index.d.ts +13 -1
  118. package/node_modules/nodemailer/dist/esm/dkim/index.js +25 -8
  119. package/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +10 -1
  120. package/node_modules/nodemailer/dist/esm/dkim/message-parser.js +30 -5
  121. package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +10 -1
  122. package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +2 -1
  123. package/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +3 -0
  124. package/node_modules/nodemailer/dist/esm/dkim/sign.js +18 -1
  125. package/node_modules/nodemailer/dist/esm/errors.d.ts +3 -2
  126. package/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +12 -1
  127. package/node_modules/nodemailer/dist/esm/fetch/cookies.js +2 -1
  128. package/node_modules/nodemailer/dist/esm/fetch/index.d.ts +15 -1
  129. package/node_modules/nodemailer/dist/esm/fetch/index.js +39 -64
  130. package/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +14 -4
  131. package/node_modules/nodemailer/dist/esm/json-transport/index.js +2 -0
  132. package/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +8 -3
  133. package/node_modules/nodemailer/dist/esm/mailer/index.d.ts +43 -25
  134. package/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +11 -4
  135. package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +7 -3
  136. package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +198 -84
  137. package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +5 -2
  138. package/node_modules/nodemailer/dist/esm/mime-node/index.js +2 -1
  139. package/node_modules/nodemailer/dist/esm/nodemailer.d.ts +38 -16
  140. package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
  141. package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
  142. package/node_modules/nodemailer/dist/esm/punycode/index.js +1 -0
  143. package/node_modules/nodemailer/dist/esm/qp/index.d.ts +2 -0
  144. package/node_modules/nodemailer/dist/esm/qp/index.js +10 -1
  145. package/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +2 -0
  146. package/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +39 -2
  147. package/node_modules/nodemailer/dist/esm/shared/index.d.ts +43 -7
  148. package/node_modules/nodemailer/dist/esm/shared/index.js +5 -2
  149. package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +2 -1
  150. package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +32 -24
  151. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +13 -5
  152. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +23 -11
  153. package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +59 -24
  154. package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +156 -75
  155. package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +12 -4
  156. package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +39 -11
  157. package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +27 -31
  158. package/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +19 -6
  159. package/node_modules/nodemailer/dist/esm/smtp-transport/index.js +25 -33
  160. package/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +2 -0
  161. package/node_modules/nodemailer/dist/esm/well-known/services.js +6 -0
  162. package/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +13 -3
  163. package/node_modules/nodemailer/dist/esm/xoauth2/index.js +25 -13
  164. package/node_modules/nodemailer/dist/well-known/services.json +7 -0
  165. package/node_modules/nodemailer/package.json +16 -12
  166. package/package.json +18 -16
  167. package/renovate.json5 +59 -0
@@ -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, unlimited when not set or negative */
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, callback: SMTPPoolSendCallback): boolean;
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
- * @param callback Callback function
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;
@@ -43,6 +43,10 @@ const index_js_2 = __importDefault(require("../well-known/index.js"));
43
43
  const shared = __importStar(require("../shared/index.js"));
44
44
  const errors = __importStar(require("../errors.js"));
45
45
  const packageData = __importStar(require("../package-info.js"));
46
+ /** First delay before a requeued message is retried, doubled on every further requeue */
47
+ const REQUEUE_BASE_DELAY = 50;
48
+ /** Upper bound for the requeue delay */
49
+ const REQUEUE_MAX_DELAY = 2000;
46
50
  /**
47
51
  * Creates a SMTP pool transport object for Nodemailer
48
52
  *
@@ -74,6 +78,8 @@ class SMTPPool extends node_events_1.EventEmitter {
74
78
  );
75
79
  this.options.maxConnections = this.options.maxConnections || 5;
76
80
  this.options.maxMessages = this.options.maxMessages || 100;
81
+ // a default bound, a server that closes every connection before the greeting would otherwise be retried forever
82
+ this.options.maxRequeues = typeof this.options.maxRequeues === 'number' ? this.options.maxRequeues : 5;
77
83
  this.logger = shared.getLogger(this.options, {
78
84
  component: this.options.component || 'smtp-pool'
79
85
  });
@@ -117,6 +123,10 @@ class SMTPPool extends node_events_1.EventEmitter {
117
123
  */
118
124
  send(mail, callback) {
119
125
  if (this._closed) {
126
+ // Mail.sendMail ignores the return value, so without a callback its promise would never settle
127
+ const err = new Error('Connection pool was closed');
128
+ err.code = errors.ECONNECTION;
129
+ setImmediate(() => callback(err));
120
130
  return false;
121
131
  }
122
132
  this._queue.push({
@@ -330,15 +340,22 @@ class SMTPPool extends node_events_1.EventEmitter {
330
340
  // Note that we must wait a bit.. because the callback of the 'error' handler might be called
331
341
  // in the next event loop
332
342
  setTimeout(() => {
343
+ let delay = 0;
333
344
  if (connection.queueEntry) {
334
345
  if (this._shouldRequeuOnConnectionClose(connection.queueEntry)) {
335
- this._requeueEntryOnConnectionClose(connection);
346
+ delay = this._requeueEntryOnConnectionClose(connection);
336
347
  }
337
348
  else {
338
349
  this._failDeliveryOnConnectionClose(connection);
339
350
  }
340
351
  }
341
- this._continueProcessing();
352
+ if (delay) {
353
+ // back off, a server that keeps dropping connections is not hammered
354
+ setTimeout(() => this._continueProcessing(), delay);
355
+ }
356
+ else {
357
+ this._continueProcessing();
358
+ }
342
359
  }, 50);
343
360
  }
344
361
  else {
@@ -353,7 +370,7 @@ class SMTPPool extends node_events_1.EventEmitter {
353
370
  }
354
371
  /** @internal */
355
372
  _shouldRequeuOnConnectionClose(queueEntry) {
356
- if (this.options.maxRequeues === undefined || this.options.maxRequeues < 0) {
373
+ if (this.options.maxRequeues < 0) {
357
374
  return true;
358
375
  }
359
376
  return queueEntry.requeueAttempts < this.options.maxRequeues;
@@ -362,7 +379,9 @@ class SMTPPool extends node_events_1.EventEmitter {
362
379
  _failDeliveryOnConnectionClose(connection) {
363
380
  if (connection.queueEntry && connection.queueEntry.callback) {
364
381
  try {
365
- connection.queueEntry.callback(new Error('Reached maximum number of retries after connection was closed'));
382
+ const err = new Error('Reached maximum number of retries after connection was closed');
383
+ err.code = errors.ECONNECTION;
384
+ connection.queueEntry.callback(err);
366
385
  }
367
386
  catch (E) {
368
387
  this.logger.error({
@@ -377,6 +396,7 @@ class SMTPPool extends node_events_1.EventEmitter {
377
396
  }
378
397
  /** @internal */
379
398
  _requeueEntryOnConnectionClose(connection) {
399
+ const delay = Math.min(REQUEUE_BASE_DELAY * 2 ** connection.queueEntry.requeueAttempts, REQUEUE_MAX_DELAY);
380
400
  connection.queueEntry.requeueAttempts += 1;
381
401
  this.logger.debug({
382
402
  tnx: 'pool',
@@ -386,6 +406,7 @@ class SMTPPool extends node_events_1.EventEmitter {
386
406
  }, 'Re-queued message <%s> for #%s. Attempt: #%s', connection.queueEntry.messageId, connection.id, connection.queueEntry.requeueAttempts);
387
407
  this._queue.unshift(connection.queueEntry);
388
408
  connection.queueEntry = false;
409
+ return delay;
389
410
  }
390
411
  /**
391
412
  * Continue to process message if the pool hasn't closed
@@ -462,10 +483,12 @@ class SMTPPool extends node_events_1.EventEmitter {
462
483
  callback = shared.callbackPromise(resolve, reject);
463
484
  });
464
485
  }
486
+ // the error paths hand over the error alone
487
+ const done = callback;
465
488
  const auth = new pool_resource_js_1.default(this).auth;
466
489
  this.getSocket(this.options, (err, socketOptions) => {
467
490
  if (err) {
468
- return callback(err);
491
+ return done(err);
469
492
  }
470
493
  let options = this.options;
471
494
  if (socketOptions && socketOptions.connection) {
@@ -487,14 +510,14 @@ class SMTPPool extends node_events_1.EventEmitter {
487
510
  }
488
511
  returned = true;
489
512
  connection.close();
490
- return callback(err);
513
+ return done(err);
491
514
  });
492
515
  connection.once('end', () => {
493
516
  if (returned) {
494
517
  return;
495
518
  }
496
519
  returned = true;
497
- return callback(new Error('Connection closed'));
520
+ return done(new Error('Connection closed'));
498
521
  });
499
522
  const finalize = () => {
500
523
  if (returned) {
@@ -502,12 +525,17 @@ class SMTPPool extends node_events_1.EventEmitter {
502
525
  }
503
526
  returned = true;
504
527
  connection.quit();
505
- return callback(null, true);
528
+ return done(null, true);
506
529
  };
507
- connection.connect(() => {
530
+ connection.connect(err => {
508
531
  if (returned) {
509
532
  return;
510
533
  }
534
+ if (err) {
535
+ returned = true;
536
+ connection.close();
537
+ return done(err);
538
+ }
511
539
  if (auth && (connection.allowsAuth || options.forceAuth)) {
512
540
  connection.login(auth, err => {
513
541
  if (returned) {
@@ -516,7 +544,7 @@ class SMTPPool extends node_events_1.EventEmitter {
516
544
  if (err) {
517
545
  returned = true;
518
546
  connection.close();
519
- return callback(err);
547
+ return done(err);
520
548
  }
521
549
  finalize();
522
550
  });
@@ -526,7 +554,7 @@ class SMTPPool extends node_events_1.EventEmitter {
526
554
  err.code = errors.ENOAUTH;
527
555
  returned = true;
528
556
  connection.close();
529
- return callback(err);
557
+ return done(err);
530
558
  }
531
559
  else {
532
560
  finalize();
@@ -66,7 +66,7 @@ class PoolResource extends node_events_1.EventEmitter {
66
66
  method: 'XOAUTH2'
67
67
  };
68
68
  oauth2.on('token', (token) => this.pool.mailer.emit('token', token));
69
- oauth2.on('error', err => this.emit('error', err));
69
+ oauth2.on('error', err => this._fail(err));
70
70
  break;
71
71
  }
72
72
  default:
@@ -89,6 +89,19 @@ class PoolResource extends node_events_1.EventEmitter {
89
89
  this._connected = false;
90
90
  this.messages = 0;
91
91
  this.available = true;
92
+ this._failed = false;
93
+ }
94
+ /**
95
+ * Emits 'error' for the first failure only. A dead resource can report the same failure more
96
+ * than once (the connection error, then the send callback), the pool handles it once
97
+ * @internal
98
+ */
99
+ _fail(err) {
100
+ if (this._failed) {
101
+ return;
102
+ }
103
+ this._failed = true;
104
+ this.emit('error', err);
92
105
  }
93
106
  /**
94
107
  * Initiates a connection to the SMTP server
@@ -101,7 +114,7 @@ class PoolResource extends node_events_1.EventEmitter {
101
114
  // nothing was connected, so no 'close' event is coming that would free the
102
115
  // slot this resource holds in the pool, report the failure the way a failed
103
116
  // login does
104
- this.emit('error', err);
117
+ this._fail(err);
105
118
  return callback(err);
106
119
  }
107
120
  let returned = false;
@@ -118,8 +131,8 @@ class PoolResource extends node_events_1.EventEmitter {
118
131
  options = Object.assign((0, index_js_2.assign)(false, options), socketOptions);
119
132
  }
120
133
  this.connection = new index_js_1.default(options);
121
- this.connection.once('error', err => {
122
- this.emit('error', err);
134
+ this.connection.on('error', err => {
135
+ this._fail(err);
123
136
  if (returned) {
124
137
  return;
125
138
  }
@@ -128,35 +141,18 @@ class PoolResource extends node_events_1.EventEmitter {
128
141
  });
129
142
  this.connection.once('end', () => {
130
143
  this.close();
131
- if (returned) {
132
- return;
133
- }
134
144
  returned = true;
135
- const timer = setTimeout(() => {
136
- if (returned) {
137
- return;
138
- }
139
- // still have not returned, this means we have an unexpected connection close
140
- const err = new Error('Unexpected socket close');
141
- if (this.connection &&
142
- this.connection._socket &&
143
- this.connection._socket.upgrading) {
144
- // starttls connection errors
145
- err.code = errors.ETLS;
146
- }
147
- callback(err);
148
- }, 1000);
149
- try {
150
- timer.unref();
151
- }
152
- catch (_E) {
153
- // Ignore. Happens on envs with non-node timer implementation
154
- }
155
145
  });
156
- this.connection.connect(() => {
146
+ this.connection.connect(err => {
157
147
  if (returned) {
158
148
  return;
159
149
  }
150
+ if (err) {
151
+ // a close before the greeting, the 'end' that follows closes this resource
152
+ // and the pool requeues or fails the entry, bounded by maxRequeues
153
+ returned = true;
154
+ return;
155
+ }
160
156
  if (this.auth && (this.connection.allowsAuth || options.forceAuth)) {
161
157
  this.connection.login(this.auth, err => {
162
158
  if (returned) {
@@ -165,7 +161,7 @@ class PoolResource extends node_events_1.EventEmitter {
165
161
  returned = true;
166
162
  if (err) {
167
163
  this.connection.close();
168
- this.emit('error', err);
164
+ this._fail(err);
169
165
  return callback(err);
170
166
  }
171
167
  this._connected = true;
@@ -217,7 +213,7 @@ class PoolResource extends node_events_1.EventEmitter {
217
213
  this.messages++;
218
214
  if (err) {
219
215
  this.connection.close();
220
- this.emit('error', err);
216
+ this._fail(err);
221
217
  return callback(err);
222
218
  }
223
219
  info.envelope = {
@@ -230,7 +226,7 @@ class PoolResource extends node_events_1.EventEmitter {
230
226
  const err = new Error('Resource exhausted');
231
227
  err.code = errors.EMAXLIMIT;
232
228
  this.connection.close();
233
- this.emit('error', err);
229
+ this._fail(err);
234
230
  }
235
231
  else {
236
232
  this.pool._checkRateLimit(() => {
@@ -4,7 +4,7 @@ import * as shared from '../shared/index.js';
4
4
  import { type XOAuth2Options } from '../xoauth2/index.js';
5
5
  import type { ResultCallback } from '../errors.js';
6
6
  import type MailMessage from '../mailer/mail-message.js';
7
- import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js';
7
+ import type { default as Mail, GetSocketCallback, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js';
8
8
  import type { MimeNodeEnvelope } from '../mime-node/index.js';
9
9
  /**
10
10
  * Authentication settings, either from the transport options or from the message data.
@@ -38,9 +38,10 @@ export interface SMTPTransportAuth extends SMTPConnectionAuth {
38
38
  /**
39
39
  * Receives the socket details from getSocket, false when a new socket should be opened. The
40
40
  * object is merged into the connection options, a proxy handler provides the connected socket
41
- * as `connection`
41
+ * as `connection`. The same callback type Mail hands to a transport, so that the SMTP
42
+ * transports stay assignable to the Transport interface
42
43
  */
43
- export type SMTPTransportGetSocketCallback = (err: Error | null, socketOptions?: SMTPConnectionOptions | false) => void;
44
+ export type SMTPTransportGetSocketCallback = GetSocketCallback;
44
45
  /**
45
46
  * Custom socket provider, replaces the getSocket method of the transport
46
47
  */
@@ -78,6 +79,8 @@ export interface SMTPSentMessageInfo extends SMTPConnectionSendInfo, SentMessage
78
79
  accepted: string[];
79
80
  /** Recipients the server rejected */
80
81
  rejected: string[];
82
+ /** Final server response for the message */
83
+ response: string;
81
84
  }
82
85
  /**
83
86
  * Callback for send()
@@ -101,7 +104,7 @@ declare class SMTPTransport extends EventEmitter {
101
104
  /**
102
105
  * The Mail instance using this transport, assigned by Mail
103
106
  */
104
- mailer?: Mail<SMTPSentMessageInfo> | undefined;
107
+ mailer?: Mail<SMTPSentMessageInfo, SMTPTransportOptions> | undefined;
105
108
  constructor(options?: SMTPTransportOptions | string);
106
109
  /**
107
110
  * Placeholder function for creating proxy sockets. This method immediatelly returns
@@ -118,13 +121,18 @@ declare class SMTPTransport extends EventEmitter {
118
121
  * @param mail Mail object
119
122
  * @param callback Callback function
120
123
  */
121
- send(mail: MailMessage, callback: SMTPTransportSendCallback): void;
124
+ send(mail: MailMessage<SMTPSentMessageInfo>, callback: SMTPTransportSendCallback): void;
122
125
  /**
123
126
  * Verifies SMTP configuration
124
127
  *
125
- * @param callback Callback function
128
+ * @returns Promise that resolves to true if the configuration is usable
126
129
  */
127
130
  verify(): Promise<true>;
131
+ /**
132
+ * Verifies SMTP configuration
133
+ *
134
+ * @param callback Callback function
135
+ */
128
136
  verify(callback: VerifyCallback): void;
129
137
  /**
130
138
  * Releases resources
@@ -139,5 +147,10 @@ declare namespace SMTPTransport {
139
147
  type MailOptions = SendMailOptions;
140
148
  type SentMessageInfo = SMTPSentMessageInfo;
141
149
  type AuthenticationType = SMTPTransportAuth;
150
+ type AuthenticationTypeLogin = SMTPTransportAuth;
151
+ type AuthenticationTypeOAuth2 = SMTPTransportAuth;
152
+ type AuthenticationTypeCustom = SMTPTransportAuth;
142
153
  }
154
+ /** The same aliases as module level exports, for `import * as SMTPTransport` and `import SMTPTransport = require()` */
155
+ export type { SMTPTransportOptions as Options, SendMailOptions as MailOptions, SMTPSentMessageInfo as SentMessageInfo, SMTPTransportAuth as AuthenticationType, SMTPTransportAuth as AuthenticationTypeLogin, SMTPTransportAuth as AuthenticationTypeOAuth2, SMTPTransportAuth as AuthenticationTypeCustom };
143
156
  export default SMTPTransport;
@@ -177,31 +177,6 @@ class SMTPTransport extends node_events_1.EventEmitter {
177
177
  connection.close();
178
178
  return callback(err);
179
179
  });
180
- connection.once('end', () => {
181
- if (returned) {
182
- return;
183
- }
184
- const timer = setTimeout(() => {
185
- if (returned) {
186
- return;
187
- }
188
- returned = true;
189
- cleanupPerCallAuth();
190
- // still have not returned, this means we have an unexpected connection close
191
- const err = new Error('Unexpected socket close');
192
- if (connection && connection._socket && connection._socket.upgrading) {
193
- // starttls connection errors
194
- err.code = errors.ETLS;
195
- }
196
- callback(err);
197
- }, 1000);
198
- try {
199
- timer.unref();
200
- }
201
- catch (_E) {
202
- // Ignore. Happens on envs with non-node timer implementation
203
- }
204
- });
205
180
  const sendMessage = () => {
206
181
  const envelope = mail.message.getEnvelope();
207
182
  const messageId = mail.message.messageId();
@@ -221,6 +196,10 @@ class SMTPTransport extends node_events_1.EventEmitter {
221
196
  messageId
222
197
  }, 'Sending message %s to <%s>', messageId, recipients.join(', '));
223
198
  connection.send(envelope, mail.message.createReadStream(), (err, info) => {
199
+ if (returned) {
200
+ // the connection error handler has already reported this send
201
+ return;
202
+ }
224
203
  returned = true;
225
204
  cleanupPerCallAuth();
226
205
  connection.close();
@@ -247,10 +226,16 @@ class SMTPTransport extends node_events_1.EventEmitter {
247
226
  }
248
227
  });
249
228
  };
250
- connection.connect(() => {
229
+ connection.connect(err => {
251
230
  if (returned) {
252
231
  return;
253
232
  }
233
+ if (err) {
234
+ // the server closed the connection before the greeting
235
+ returned = true;
236
+ connection.close();
237
+ return callback(err);
238
+ }
254
239
  perCallAuth = this.getAuth(mail.data.auth);
255
240
  if (perCallAuth && (connection.allowsAuth || options.forceAuth)) {
256
241
  connection.login(perCallAuth, err => {
@@ -279,9 +264,11 @@ class SMTPTransport extends node_events_1.EventEmitter {
279
264
  callback = shared.callbackPromise(resolve, reject);
280
265
  });
281
266
  }
267
+ // the error paths hand over the error alone
268
+ const done = callback;
282
269
  this.getSocket(this.options, (err, socketOptions) => {
283
270
  if (err) {
284
- return callback(err);
271
+ return done(err);
285
272
  }
286
273
  let options = this.options;
287
274
  if (socketOptions && socketOptions.connection) {
@@ -311,7 +298,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
311
298
  returned = true;
312
299
  cleanupPerCallAuth();
313
300
  connection.close();
314
- return callback(err);
301
+ return done(err);
315
302
  });
316
303
  connection.once('end', () => {
317
304
  if (returned) {
@@ -319,7 +306,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
319
306
  }
320
307
  returned = true;
321
308
  cleanupPerCallAuth();
322
- return callback(new Error('Connection closed'));
309
+ return done(new Error('Connection closed'));
323
310
  });
324
311
  const finalize = () => {
325
312
  if (returned) {
@@ -328,12 +315,17 @@ class SMTPTransport extends node_events_1.EventEmitter {
328
315
  returned = true;
329
316
  cleanupPerCallAuth();
330
317
  connection.quit();
331
- return callback(null, true);
318
+ return done(null, true);
332
319
  };
333
- connection.connect(() => {
320
+ connection.connect(err => {
334
321
  if (returned) {
335
322
  return;
336
323
  }
324
+ if (err) {
325
+ returned = true;
326
+ connection.close();
327
+ return done(err);
328
+ }
337
329
  perCallAuth = this.getAuth({});
338
330
  if (perCallAuth && (connection.allowsAuth || options.forceAuth)) {
339
331
  connection.login(perCallAuth, err => {
@@ -344,7 +336,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
344
336
  if (err) {
345
337
  returned = true;
346
338
  connection.close();
347
- return callback(err);
339
+ return done(err);
348
340
  }
349
341
  finalize();
350
342
  });
@@ -355,7 +347,7 @@ class SMTPTransport extends node_events_1.EventEmitter {
355
347
  returned = true;
356
348
  cleanupPerCallAuth();
357
349
  connection.close();
358
- return callback(err);
350
+ return done(err);
359
351
  }
360
352
  else {
361
353
  finalize();
@@ -60,4 +60,6 @@ declare namespace StreamTransport {
60
60
  type MailOptions = SendMailOptions;
61
61
  type SentMessageInfo = StreamSentMessageInfo;
62
62
  }
63
+ /** The same aliases as module level exports, for `import * as StreamTransport` and `import StreamTransport = require()` */
64
+ export type { StreamTransportOptions as Options, SendMailOptions as MailOptions, StreamSentMessageInfo as SentMessageInfo };
63
65
  export default StreamTransport;
@@ -314,6 +314,12 @@ exports.services = {
314
314
  "host": "mailosaur.io",
315
315
  "port": 25
316
316
  },
317
+ "MailSenpai": {
318
+ "description": "MailSenpai (SMTP Senpai, EU)",
319
+ "host": "relay.mailsenpai.com",
320
+ "port": 2525,
321
+ "secure": false
322
+ },
317
323
  "Mailtrap": {
318
324
  "description": "Mailtrap",
319
325
  "host": "live.smtp.mailtrap.io",
@@ -1,6 +1,7 @@
1
1
  import { Stream } from 'node:stream';
2
2
  import crypto from 'node:crypto';
3
3
  import * as shared from '../shared/index.js';
4
+ import type { ResultCallback } from '../errors.js';
4
5
  import type { OutgoingHttpHeaders } from 'node:http';
5
6
  /**
6
7
  * Receives the result of a provisionCallback run: an error, or the new access token and
@@ -13,9 +14,11 @@ export type XOAuth2ProvisionResultCallback = (err: Error | null, accessToken?: s
13
14
  */
14
15
  export type XOAuth2ProvisionCallback = (user: string, renew: boolean, callback: XOAuth2ProvisionResultCallback) => void;
15
16
  /**
16
- * Receives an access token, or the error that prevented generating one
17
+ * Receives an access token, or the error that prevented generating one. Declared with a
18
+ * required token, the way @types/nodemailer declared it, the error path hands over the
19
+ * error alone
17
20
  */
18
- export type XOAuth2TokenCallback = (err: Error | null, accessToken?: string) => void;
21
+ export type XOAuth2TokenCallback = (err: Error | null, accessToken: string) => void;
19
22
  /**
20
23
  * A private key accepted by crypto.createSign().sign()
21
24
  */
@@ -58,6 +61,8 @@ export interface XOAuth2Options {
58
61
  component?: string | undefined;
59
62
  /** Extra headers for the token request */
60
63
  customHeaders?: OutgoingHttpHeaders | undefined;
64
+ /** Timeout for the token request in milliseconds, defaults to 60000, 0 disables it */
65
+ requestTimeout?: number | undefined;
61
66
  /** Extra form fields for the token request */
62
67
  customParams?: {
63
68
  [key: string]: any;
@@ -79,7 +84,7 @@ export interface XOAuth2Token {
79
84
  */
80
85
  export interface XOAuth2QueuedRequest {
81
86
  renew: boolean;
82
- callback: XOAuth2TokenCallback;
87
+ callback: ResultCallback<string>;
83
88
  }
84
89
  /**
85
90
  * XOAUTH2 access_token generator for Gmail.
@@ -181,11 +186,16 @@ declare class XOAuth2 extends Stream {
181
186
  [key: string]: any;
182
187
  }): string;
183
188
  }
189
+ /** The extra request settings of the token request, the customHeaders and customParams options */
190
+ export type XOAuth2RequestParams = Pick<XOAuth2Options, 'customHeaders' | 'customParams'>;
184
191
  /**
185
192
  * Type aliases in the layout of @types/nodemailer, so `XOAuth2.Options` style references keep working
186
193
  */
187
194
  declare namespace XOAuth2 {
188
195
  type Options = XOAuth2Options;
189
196
  type Token = XOAuth2Token;
197
+ type RequestParams = XOAuth2RequestParams;
190
198
  }
199
+ /** The same aliases as module level exports, for `import * as XOAuth2` and `import XOAuth2 = require()` */
200
+ export type { XOAuth2Options as Options, XOAuth2Token as Token, XOAuth2RequestParams as RequestParams };
191
201
  export default XOAuth2;