@nocobase/plugin-workflow-mailer 2.2.19 → 2.2.21

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 (173) hide show
  1. package/dist/externalVersion.js +6 -6
  2. package/dist/node_modules/joi/package.json +1 -1
  3. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +59 -0
  4. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.js +790 -0
  5. package/dist/node_modules/nodemailer/dist/cjs/base64/index.d.ts +36 -0
  6. package/dist/node_modules/nodemailer/dist/cjs/base64/index.js +119 -0
  7. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +52 -0
  8. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.js +228 -0
  9. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +48 -0
  10. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +180 -0
  11. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +36 -0
  12. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.js +148 -0
  13. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +52 -0
  14. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.js +165 -0
  15. package/dist/node_modules/nodemailer/dist/cjs/errors.d.ts +96 -0
  16. package/dist/node_modules/nodemailer/dist/cjs/errors.js +70 -0
  17. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +107 -0
  18. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.js +282 -0
  19. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +65 -0
  20. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.js +384 -0
  21. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +64 -0
  22. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.js +99 -0
  23. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +174 -0
  24. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.js +613 -0
  25. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +237 -0
  26. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.js +415 -0
  27. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +97 -0
  28. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +342 -0
  29. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +161 -0
  30. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +787 -0
  31. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.d.ts +2 -0
  32. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +2103 -0
  33. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +333 -0
  34. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.js +1493 -0
  35. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.d.ts +5 -0
  36. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.js +32 -0
  37. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.d.ts +9 -0
  38. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.js +40 -0
  39. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.d.ts +10 -0
  40. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.js +47 -0
  41. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +124 -0
  42. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
  43. package/dist/node_modules/nodemailer/dist/cjs/package-info.d.ts +3 -0
  44. package/dist/node_modules/nodemailer/dist/cjs/package-info.js +7 -0
  45. package/dist/node_modules/nodemailer/dist/cjs/package.json +3 -0
  46. package/dist/node_modules/nodemailer/dist/cjs/punycode/index.d.ts +73 -0
  47. package/dist/node_modules/nodemailer/{lib → dist/cjs}/punycode/index.js +62 -111
  48. package/dist/node_modules/nodemailer/dist/cjs/qp/index.d.ts +32 -0
  49. package/dist/node_modules/nodemailer/dist/cjs/qp/index.js +207 -0
  50. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +69 -0
  51. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +210 -0
  52. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +112 -0
  53. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.js +252 -0
  54. package/dist/node_modules/nodemailer/dist/cjs/shared/index.d.ts +260 -0
  55. package/dist/node_modules/nodemailer/dist/cjs/shared/index.js +680 -0
  56. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.d.ts +23 -0
  57. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.js +43 -0
  58. package/dist/node_modules/nodemailer/dist/cjs/shared/url.d.ts +21 -0
  59. package/dist/node_modules/nodemailer/dist/cjs/shared/url.js +255 -0
  60. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +15 -0
  61. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +108 -0
  62. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +47 -0
  63. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +189 -0
  64. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +416 -0
  65. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +1837 -0
  66. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +133 -0
  67. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +569 -0
  68. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.d.ts +62 -0
  69. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +257 -0
  70. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +156 -0
  71. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +371 -0
  72. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +65 -0
  73. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.js +146 -0
  74. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.d.ts +35 -0
  75. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.js +41 -0
  76. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.d.ts +2 -0
  77. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.js +674 -0
  78. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +201 -0
  79. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.js +426 -0
  80. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +59 -0
  81. package/dist/node_modules/nodemailer/{lib → dist/esm}/addressparser/index.js +361 -131
  82. package/dist/node_modules/nodemailer/dist/esm/base64/index.d.ts +36 -0
  83. package/dist/node_modules/nodemailer/{lib → dist/esm}/base64/index.js +31 -56
  84. package/dist/node_modules/nodemailer/dist/esm/dkim/index.d.ts +52 -0
  85. package/dist/node_modules/nodemailer/{lib → dist/esm}/dkim/index.js +49 -78
  86. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +48 -0
  87. package/dist/node_modules/nodemailer/{lib → dist/esm}/dkim/message-parser.js +64 -42
  88. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +36 -0
  89. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +141 -0
  90. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +52 -0
  91. package/dist/node_modules/nodemailer/{lib → dist/esm}/dkim/sign.js +50 -46
  92. package/dist/node_modules/nodemailer/dist/esm/errors.d.ts +96 -0
  93. package/dist/node_modules/nodemailer/{lib → dist/esm}/errors.js +26 -18
  94. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +107 -0
  95. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.js +242 -0
  96. package/dist/node_modules/nodemailer/dist/esm/fetch/index.d.ts +65 -0
  97. package/dist/node_modules/nodemailer/{lib → dist/esm}/fetch/index.js +80 -147
  98. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +64 -0
  99. package/dist/node_modules/nodemailer/{lib → dist/esm}/json-transport/index.js +19 -39
  100. package/dist/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +174 -0
  101. package/dist/node_modules/nodemailer/{lib → dist/esm}/mail-composer/index.js +199 -265
  102. package/dist/node_modules/nodemailer/dist/esm/mailer/index.d.ts +237 -0
  103. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/index.js +128 -234
  104. package/dist/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +97 -0
  105. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/mail-message.js +62 -114
  106. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +161 -0
  107. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.js +738 -0
  108. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.d.ts +2 -0
  109. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-funcs/mime-types.js +29 -42
  110. package/dist/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +333 -0
  111. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/index.js +259 -372
  112. package/dist/node_modules/nodemailer/dist/esm/mime-node/last-newline.d.ts +5 -0
  113. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/last-newline.js +4 -10
  114. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-unix.d.ts +9 -0
  115. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-unix.js +6 -11
  116. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-windows.d.ts +10 -0
  117. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-windows.js +6 -13
  118. package/dist/node_modules/nodemailer/dist/esm/nodemailer.d.ts +124 -0
  119. package/dist/node_modules/nodemailer/dist/esm/nodemailer.js +166 -0
  120. package/dist/node_modules/nodemailer/dist/esm/package-info.d.ts +3 -0
  121. package/dist/node_modules/nodemailer/dist/esm/package-info.js +4 -0
  122. package/dist/node_modules/nodemailer/dist/esm/package.json +3 -0
  123. package/dist/node_modules/nodemailer/dist/esm/punycode/index.d.ts +73 -0
  124. package/dist/node_modules/nodemailer/dist/esm/punycode/index.js +405 -0
  125. package/dist/node_modules/nodemailer/dist/esm/qp/index.d.ts +32 -0
  126. package/dist/node_modules/nodemailer/{lib → dist/esm}/qp/index.js +38 -67
  127. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +69 -0
  128. package/dist/node_modules/nodemailer/{lib → dist/esm}/sendmail-transport/index.js +51 -101
  129. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +112 -0
  130. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.js +212 -0
  131. package/dist/node_modules/nodemailer/dist/esm/shared/index.d.ts +260 -0
  132. package/dist/node_modules/nodemailer/{lib → dist/esm}/shared/index.js +156 -272
  133. package/dist/node_modules/nodemailer/dist/esm/shared/objects.d.ts +23 -0
  134. package/dist/node_modules/nodemailer/{lib → dist/esm}/shared/objects.js +13 -17
  135. package/dist/node_modules/nodemailer/dist/esm/shared/url.d.ts +21 -0
  136. package/dist/node_modules/nodemailer/dist/esm/shared/url.js +214 -0
  137. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +15 -0
  138. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +103 -0
  139. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +47 -0
  140. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-connection/http-proxy-client.js +49 -74
  141. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +416 -0
  142. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-connection/index.js +574 -794
  143. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +133 -0
  144. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/index.js +172 -284
  145. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.d.ts +62 -0
  146. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/pool-resource.js +57 -97
  147. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +156 -0
  148. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-transport/index.js +81 -179
  149. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +65 -0
  150. package/dist/node_modules/nodemailer/{lib → dist/esm}/stream-transport/index.js +36 -74
  151. package/dist/node_modules/nodemailer/dist/esm/well-known/index.d.ts +35 -0
  152. package/dist/node_modules/nodemailer/{lib → dist/esm}/well-known/index.js +5 -16
  153. package/dist/node_modules/nodemailer/dist/esm/well-known/services.d.ts +2 -0
  154. package/dist/node_modules/nodemailer/dist/esm/well-known/services.js +671 -0
  155. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +201 -0
  156. package/dist/node_modules/nodemailer/{lib → dist/esm}/xoauth2/index.js +125 -187
  157. package/dist/node_modules/nodemailer/{lib → dist}/well-known/services.json +9 -2
  158. package/dist/node_modules/nodemailer/package.json +1 -1
  159. package/package.json +3 -3
  160. package/dist/node_modules/nodemailer/.gitattributes +0 -6
  161. package/dist/node_modules/nodemailer/.ncurc.js +0 -9
  162. package/dist/node_modules/nodemailer/.prettierignore +0 -8
  163. package/dist/node_modules/nodemailer/.prettierrc +0 -12
  164. package/dist/node_modules/nodemailer/.prettierrc.js +0 -10
  165. package/dist/node_modules/nodemailer/.release-please-config.json +0 -9
  166. package/dist/node_modules/nodemailer/eslint.config.js +0 -88
  167. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  168. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +0 -276
  169. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +0 -671
  170. package/dist/node_modules/nodemailer/lib/nodemailer.js +0 -1
  171. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +0 -266
  172. package/dist/node_modules/nodemailer/lib/shared/url.js +0 -151
  173. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -105
@@ -1,59 +1,52 @@
1
- 'use strict';
2
-
3
- const EventEmitter = require('events');
4
- const PoolResource = require('./pool-resource');
5
- const SMTPConnection = require('../smtp-connection');
6
- const wellKnown = require('../well-known');
7
- const shared = require('../shared');
8
- const errors = require('../errors');
9
- const packageData = require('../../package.json');
10
-
1
+ import { EventEmitter } from 'node:events';
2
+ import PoolResource from './pool-resource.js';
3
+ import SMTPConnection from '../smtp-connection/index.js';
4
+ import wellKnown from '../well-known/index.js';
5
+ import * as shared from '../shared/index.js';
6
+ import * as errors from '../errors.js';
7
+ import * as packageData from '../package-info.js';
8
+ /** First delay before a requeued message is retried, doubled on every further requeue */
9
+ const REQUEUE_BASE_DELAY = 50;
10
+ /** Upper bound for the requeue delay */
11
+ const REQUEUE_MAX_DELAY = 2000;
11
12
  /**
12
13
  * Creates a SMTP pool transport object for Nodemailer
13
14
  *
14
15
  * @constructor
15
- * @param {Object} options SMTP Connection options
16
+ * @param options SMTP Connection options
16
17
  */
17
18
  class SMTPPool extends EventEmitter {
18
19
  constructor(options) {
19
20
  super();
20
-
21
21
  options = options || {};
22
22
  if (typeof options === 'string') {
23
23
  options = {
24
24
  url: options
25
25
  };
26
26
  }
27
-
28
27
  let urlData;
29
28
  let service = options.service;
30
-
31
29
  if (typeof options.getSocket === 'function') {
32
30
  this.getSocket = options.getSocket;
33
31
  }
34
-
35
32
  if (options.url) {
36
33
  urlData = shared.parseConnectionUrl(options.url);
37
34
  service = service || urlData.service;
38
35
  }
39
-
40
- this.options = shared.assign(
41
- false, // create new object
42
- options, // regular options
43
- urlData, // url options
44
- service && wellKnown(service) // wellknown options
36
+ this.options = shared.assign(false, // create new object
37
+ options, // regular options
38
+ urlData, // url options
39
+ (service && wellKnown(service)) // wellknown options
45
40
  );
46
-
47
41
  this.options.maxConnections = this.options.maxConnections || 5;
48
42
  this.options.maxMessages = this.options.maxMessages || 100;
49
-
43
+ // a default bound, a server that closes every connection before the greeting would otherwise be retried forever
44
+ this.options.maxRequeues = typeof this.options.maxRequeues === 'number' ? this.options.maxRequeues : 5;
50
45
  this.logger = shared.getLogger(this.options, {
51
46
  component: this.options.component || 'smtp-pool'
52
47
  });
53
-
54
48
  this.name = 'SMTP (pool)';
55
49
  this.version = packageData.version + '[client:' + packageData.version + ']';
56
-
57
50
  this._rateLimit = {
58
51
  counter: 0,
59
52
  timeout: null,
@@ -66,54 +59,49 @@ class SMTPPool extends EventEmitter {
66
59
  this._queue = [];
67
60
  this._connections = [];
68
61
  this._connectionCounter = 0;
69
-
70
62
  this.idling = true;
71
-
72
63
  setImmediate(() => {
73
64
  if (this.idling) {
74
65
  this.emit('idle');
75
66
  }
76
67
  });
77
68
  }
78
-
79
69
  /**
80
70
  * Placeholder function for creating proxy sockets. This method immediatelly returns
81
71
  * without a socket
82
72
  *
83
- * @param {Object} options Connection options
84
- * @param {Function} callback Callback function to run with the socket keys
73
+ * @param options Connection options
74
+ * @param callback Callback function to run with the socket keys
85
75
  */
86
76
  getSocket(options, callback) {
87
77
  // return immediatelly
88
- return setImmediate(() => callback(null, false));
78
+ setImmediate(() => callback(null, false));
89
79
  }
90
-
91
80
  /**
92
81
  * Queues an e-mail to be sent using the selected settings
93
82
  *
94
- * @param {Object} mail Mail object
95
- * @param {Function} callback Callback function
83
+ * @param mail Mail object
84
+ * @param callback Callback function
96
85
  */
97
86
  send(mail, callback) {
98
87
  if (this._closed) {
88
+ // Mail.sendMail ignores the return value, so without a callback its promise would never settle
89
+ const err = new Error('Connection pool was closed');
90
+ err.code = errors.ECONNECTION;
91
+ setImmediate(() => callback(err));
99
92
  return false;
100
93
  }
101
-
102
94
  this._queue.push({
103
95
  mail,
104
96
  requeueAttempts: 0,
105
97
  callback
106
98
  });
107
-
108
99
  if (this.idling && this._queue.length >= this.options.maxConnections) {
109
100
  this.idling = false;
110
101
  }
111
-
112
102
  setImmediate(() => this._processMessages());
113
-
114
103
  return true;
115
104
  }
116
-
117
105
  /**
118
106
  * Closes all connections in the pool. If there is a message being sent, the connection
119
107
  * is closed later
@@ -122,87 +110,68 @@ class SMTPPool extends EventEmitter {
122
110
  let connection;
123
111
  const len = this._connections.length;
124
112
  this._closed = true;
125
-
126
- // clear rate limit timer if it exists
127
- clearTimeout(this._rateLimit.timeout);
128
-
113
+ // release connections gated by the rate limiter so they become
114
+ // available and are torn down below instead of leaking with a
115
+ // cleared timer that never fires
116
+ this._clearRateLimit();
129
117
  if (!len && !this._queue.length) {
130
118
  return;
131
119
  }
132
-
133
120
  // remove all available connections
134
121
  for (let i = len - 1; i >= 0; i--) {
135
122
  if (this._connections[i] && this._connections[i].available) {
136
123
  connection = this._connections[i];
137
124
  connection.close();
138
- this.logger.info(
139
- {
140
- tnx: 'connection',
141
- cid: connection.id,
142
- action: 'removed'
143
- },
144
- 'Connection #%s removed',
145
- connection.id
146
- );
125
+ this.logger.info({
126
+ tnx: 'connection',
127
+ cid: connection.id,
128
+ action: 'removed'
129
+ }, 'Connection #%s removed', connection.id);
147
130
  }
148
131
  }
149
-
150
132
  if (len && !this._connections.length) {
151
- this.logger.debug(
152
- {
153
- tnx: 'connection'
154
- },
155
- 'All connections removed'
156
- );
133
+ this.logger.debug({
134
+ tnx: 'connection'
135
+ }, 'All connections removed');
157
136
  }
158
-
159
137
  if (!this._queue.length) {
160
138
  return;
161
139
  }
162
-
163
140
  // make sure that entire queue would be cleaned
164
141
  const invokeCallbacks = () => {
165
142
  if (!this._queue.length) {
166
- this.logger.debug(
167
- {
168
- tnx: 'connection'
169
- },
170
- 'Pending queue entries cleared'
171
- );
143
+ this.logger.debug({
144
+ tnx: 'connection'
145
+ }, 'Pending queue entries cleared');
172
146
  return;
173
147
  }
174
148
  const entry = this._queue.shift();
175
149
  if (entry && typeof entry.callback === 'function') {
176
150
  try {
177
151
  entry.callback(new Error('Connection pool was closed'));
178
- } catch (E) {
179
- this.logger.error(
180
- {
181
- err: E,
182
- tnx: 'callback',
183
- cid: connection.id
184
- },
185
- 'Callback error for #%s: %s',
186
- connection.id,
187
- E.message
188
- );
152
+ }
153
+ catch (E) {
154
+ // the queue is drained without a connection, so there is no cid to log
155
+ this.logger.error({
156
+ err: E,
157
+ tnx: 'callback'
158
+ }, 'Callback error: %s', E.message);
189
159
  }
190
160
  }
191
161
  setImmediate(invokeCallbacks);
192
162
  };
193
163
  setImmediate(invokeCallbacks);
194
164
  }
195
-
196
165
  /**
197
166
  * Check the queue and available connections. If there is a message to be sent and there is
198
167
  * an available connection, then use this connection to send the mail
168
+ * @internal
199
169
  */
200
170
  _processMessages() {
201
171
  // do nothing if already closed
202
172
  if (this._closed) {
203
173
  return;
204
174
  }
205
-
206
175
  // do nothing if queue is empty
207
176
  if (!this._queue.length) {
208
177
  if (!this.idling) {
@@ -212,430 +181,349 @@ class SMTPPool extends EventEmitter {
212
181
  }
213
182
  return;
214
183
  }
215
-
216
184
  // find first available connection
217
185
  let connection = this._connections.find(c => c.available);
218
-
219
186
  if (!connection && this._connections.length < this.options.maxConnections) {
220
187
  connection = this._createConnection();
221
188
  }
222
-
223
189
  if (!connection) {
224
190
  // no more free connection slots available
225
191
  this.idling = false;
226
192
  return;
227
193
  }
228
-
229
194
  // check if there is free space in the processing queue
230
195
  if (!this.idling && this._queue.length < this.options.maxConnections) {
231
196
  this.idling = true;
232
197
  this.emit('idle');
233
198
  }
234
-
235
199
  const entry = (connection.queueEntry = this._queue.shift());
236
200
  entry.messageId = (connection.queueEntry.mail.message.getHeader('message-id') || '').replace(/[<>\s]/g, '');
237
-
238
201
  connection.available = false;
239
-
240
- this.logger.debug(
241
- {
242
- tnx: 'pool',
243
- cid: connection.id,
244
- messageId: entry.messageId,
245
- action: 'assign'
246
- },
247
- 'Assigned message <%s> to #%s (%s)',
248
- entry.messageId,
249
- connection.id,
250
- connection.messages + 1
251
- );
252
-
202
+ this.logger.debug({
203
+ tnx: 'pool',
204
+ cid: connection.id,
205
+ messageId: entry.messageId,
206
+ action: 'assign'
207
+ }, 'Assigned message <%s> to #%s (%s)', entry.messageId, connection.id, connection.messages + 1);
253
208
  if (this._rateLimit.limit) {
254
209
  this._rateLimit.counter++;
255
210
  if (!this._rateLimit.checkpoint) {
256
211
  this._rateLimit.checkpoint = Date.now();
257
212
  }
258
213
  }
259
-
260
214
  connection.send(entry.mail, (err, info) => {
261
215
  // only process callback if current handler is not changed
262
216
  if (entry === connection.queueEntry) {
263
217
  try {
264
218
  entry.callback(err, info);
265
- } catch (E) {
266
- this.logger.error(
267
- {
268
- err: E,
269
- tnx: 'callback',
270
- cid: connection.id
271
- },
272
- 'Callback error for #%s: %s',
273
- connection.id,
274
- E.message
275
- );
219
+ }
220
+ catch (E) {
221
+ this.logger.error({
222
+ err: E,
223
+ tnx: 'callback',
224
+ cid: connection.id
225
+ }, 'Callback error for #%s: %s', connection.id, E.message);
276
226
  }
277
227
  connection.queueEntry = false;
278
228
  }
279
229
  });
280
230
  }
281
-
282
231
  /**
283
232
  * Creates a new pool resource
233
+ * @internal
284
234
  */
285
235
  _createConnection() {
286
236
  const connection = new PoolResource(this);
287
-
288
237
  connection.id = ++this._connectionCounter;
289
-
290
- this.logger.info(
291
- {
292
- tnx: 'pool',
293
- cid: connection.id,
294
- action: 'conection'
295
- },
296
- 'Created new pool resource #%s',
297
- connection.id
298
- );
299
-
238
+ this.logger.info({
239
+ tnx: 'pool',
240
+ cid: connection.id,
241
+ action: 'conection'
242
+ }, 'Created new pool resource #%s', connection.id);
300
243
  // resource comes available
301
244
  connection.on('available', () => {
302
- this.logger.debug(
303
- {
304
- tnx: 'connection',
305
- cid: connection.id,
306
- action: 'available'
307
- },
308
- 'Connection #%s became available',
309
- connection.id
310
- );
311
-
245
+ this.logger.debug({
246
+ tnx: 'connection',
247
+ cid: connection.id,
248
+ action: 'available'
249
+ }, 'Connection #%s became available', connection.id);
312
250
  if (this._closed) {
313
251
  // if already closed run close() that will remove this connections from connections list
314
252
  this.close();
315
- } else {
253
+ }
254
+ else {
316
255
  // check if there's anything else to send
317
256
  this._processMessages();
318
257
  }
319
258
  });
320
-
321
259
  // resource is terminated with an error
322
- connection.once('error', err => {
260
+ connection.once('error', (err) => {
323
261
  if (err.code !== errors.EMAXLIMIT) {
324
- this.logger.warn(
325
- {
326
- err,
327
- tnx: 'pool',
328
- cid: connection.id
329
- },
330
- 'Pool Error for #%s: %s',
331
- connection.id,
332
- err.message
333
- );
334
- } else {
335
- this.logger.debug(
336
- {
337
- tnx: 'pool',
338
- cid: connection.id,
339
- action: 'maxlimit'
340
- },
341
- 'Max messages limit exchausted for #%s',
342
- connection.id
343
- );
262
+ this.logger.warn({
263
+ err,
264
+ tnx: 'pool',
265
+ cid: connection.id
266
+ }, 'Pool Error for #%s: %s', connection.id, err.message);
267
+ }
268
+ else {
269
+ this.logger.debug({
270
+ tnx: 'pool',
271
+ cid: connection.id,
272
+ action: 'maxlimit'
273
+ }, 'Max messages limit exchausted for #%s', connection.id);
344
274
  }
345
-
346
275
  if (connection.queueEntry) {
347
276
  try {
348
277
  connection.queueEntry.callback(err);
349
- } catch (E) {
350
- this.logger.error(
351
- {
352
- err: E,
353
- tnx: 'callback',
354
- cid: connection.id
355
- },
356
- 'Callback error for #%s: %s',
357
- connection.id,
358
- E.message
359
- );
278
+ }
279
+ catch (E) {
280
+ this.logger.error({
281
+ err: E,
282
+ tnx: 'callback',
283
+ cid: connection.id
284
+ }, 'Callback error for #%s: %s', connection.id, E.message);
360
285
  }
361
286
  connection.queueEntry = false;
362
287
  }
363
-
364
288
  // remove the erroneus connection from connections list
365
289
  this._removeConnection(connection);
366
-
367
290
  this._continueProcessing();
368
291
  });
369
-
370
292
  connection.once('close', () => {
371
- this.logger.info(
372
- {
373
- tnx: 'connection',
374
- cid: connection.id,
375
- action: 'closed'
376
- },
377
- 'Connection #%s was closed',
378
- connection.id
379
- );
380
-
293
+ this.logger.info({
294
+ tnx: 'connection',
295
+ cid: connection.id,
296
+ action: 'closed'
297
+ }, 'Connection #%s was closed', connection.id);
381
298
  this._removeConnection(connection);
382
-
383
299
  if (connection.queueEntry) {
384
300
  // If the connection closed when sending, add the message to the queue again
385
301
  // if max number of requeues is not reached yet
386
302
  // Note that we must wait a bit.. because the callback of the 'error' handler might be called
387
303
  // in the next event loop
388
304
  setTimeout(() => {
305
+ let delay = 0;
389
306
  if (connection.queueEntry) {
390
307
  if (this._shouldRequeuOnConnectionClose(connection.queueEntry)) {
391
- this._requeueEntryOnConnectionClose(connection);
392
- } else {
308
+ delay = this._requeueEntryOnConnectionClose(connection);
309
+ }
310
+ else {
393
311
  this._failDeliveryOnConnectionClose(connection);
394
312
  }
395
313
  }
396
- this._continueProcessing();
314
+ if (delay) {
315
+ // back off, a server that keeps dropping connections is not hammered
316
+ setTimeout(() => this._continueProcessing(), delay);
317
+ }
318
+ else {
319
+ this._continueProcessing();
320
+ }
397
321
  }, 50);
398
- } else {
322
+ }
323
+ else {
399
324
  if (!this._closed && this.idling && !this._connections.length) {
400
325
  this.emit('clear');
401
326
  }
402
-
403
327
  this._continueProcessing();
404
328
  }
405
329
  });
406
-
407
330
  this._connections.push(connection);
408
-
409
331
  return connection;
410
332
  }
411
-
333
+ /** @internal */
412
334
  _shouldRequeuOnConnectionClose(queueEntry) {
413
- if (this.options.maxRequeues === undefined || this.options.maxRequeues < 0) {
335
+ if (this.options.maxRequeues < 0) {
414
336
  return true;
415
337
  }
416
-
417
338
  return queueEntry.requeueAttempts < this.options.maxRequeues;
418
339
  }
419
-
340
+ /** @internal */
420
341
  _failDeliveryOnConnectionClose(connection) {
421
342
  if (connection.queueEntry && connection.queueEntry.callback) {
422
343
  try {
423
- connection.queueEntry.callback(new Error('Reached maximum number of retries after connection was closed'));
424
- } catch (E) {
425
- this.logger.error(
426
- {
427
- err: E,
428
- tnx: 'callback',
429
- messageId: connection.queueEntry.messageId,
430
- cid: connection.id
431
- },
432
- 'Callback error for #%s: %s',
433
- connection.id,
434
- E.message
435
- );
344
+ const err = new Error('Reached maximum number of retries after connection was closed');
345
+ err.code = errors.ECONNECTION;
346
+ connection.queueEntry.callback(err);
347
+ }
348
+ catch (E) {
349
+ this.logger.error({
350
+ err: E,
351
+ tnx: 'callback',
352
+ messageId: connection.queueEntry.messageId,
353
+ cid: connection.id
354
+ }, 'Callback error for #%s: %s', connection.id, E.message);
436
355
  }
437
356
  connection.queueEntry = false;
438
357
  }
439
358
  }
440
-
359
+ /** @internal */
441
360
  _requeueEntryOnConnectionClose(connection) {
361
+ const delay = Math.min(REQUEUE_BASE_DELAY * 2 ** connection.queueEntry.requeueAttempts, REQUEUE_MAX_DELAY);
442
362
  connection.queueEntry.requeueAttempts += 1;
443
- this.logger.debug(
444
- {
445
- tnx: 'pool',
446
- cid: connection.id,
447
- messageId: connection.queueEntry.messageId,
448
- action: 'requeue'
449
- },
450
- 'Re-queued message <%s> for #%s. Attempt: #%s',
451
- connection.queueEntry.messageId,
452
- connection.id,
453
- connection.queueEntry.requeueAttempts
454
- );
363
+ this.logger.debug({
364
+ tnx: 'pool',
365
+ cid: connection.id,
366
+ messageId: connection.queueEntry.messageId,
367
+ action: 'requeue'
368
+ }, 'Re-queued message <%s> for #%s. Attempt: #%s', connection.queueEntry.messageId, connection.id, connection.queueEntry.requeueAttempts);
455
369
  this._queue.unshift(connection.queueEntry);
456
370
  connection.queueEntry = false;
371
+ return delay;
457
372
  }
458
-
459
373
  /**
460
374
  * Continue to process message if the pool hasn't closed
375
+ * @internal
461
376
  */
462
377
  _continueProcessing() {
463
378
  if (this._closed) {
464
379
  this.close();
465
- } else {
380
+ }
381
+ else {
466
382
  setTimeout(() => this._processMessages(), 100);
467
383
  }
468
384
  }
469
-
470
385
  /**
471
386
  * Remove resource from pool
472
387
  *
473
- * @param {Object} connection The PoolResource to remove
388
+ * @param connection The PoolResource to remove
389
+ * @internal
474
390
  */
475
391
  _removeConnection(connection) {
476
392
  const index = this._connections.indexOf(connection);
477
-
478
393
  if (index !== -1) {
479
394
  this._connections.splice(index, 1);
480
395
  }
481
396
  }
482
-
483
397
  /**
484
398
  * Checks if connections have hit current rate limit and if so, queues the availability callback
485
399
  *
486
- * @param {Function} callback Callback function to run once rate limiter has been cleared
400
+ * @param callback Callback function to run once rate limiter has been cleared
401
+ * @internal
487
402
  */
488
403
  _checkRateLimit(callback) {
489
404
  if (!this._rateLimit.limit) {
490
405
  return callback();
491
406
  }
492
-
493
407
  const now = Date.now();
494
-
495
408
  if (this._rateLimit.counter < this._rateLimit.limit) {
496
409
  return callback();
497
410
  }
498
-
499
411
  this._rateLimit.waiting.push(callback);
500
-
501
412
  if (this._rateLimit.checkpoint <= now - this._rateLimit.delta) {
502
413
  return this._clearRateLimit();
503
414
  }
504
-
505
415
  if (!this._rateLimit.timeout) {
506
416
  this._rateLimit.timeout = setTimeout(() => this._clearRateLimit(), this._rateLimit.delta - (now - this._rateLimit.checkpoint));
507
417
  this._rateLimit.checkpoint = now;
508
418
  }
509
419
  }
510
-
511
420
  /**
512
421
  * Clears current rate limit limitation and runs paused callback
422
+ * @internal
513
423
  */
514
424
  _clearRateLimit() {
515
425
  clearTimeout(this._rateLimit.timeout);
516
426
  this._rateLimit.timeout = null;
517
427
  this._rateLimit.counter = 0;
518
428
  this._rateLimit.checkpoint = false;
519
-
520
429
  // resume all paused connections
521
430
  while (this._rateLimit.waiting.length) {
522
431
  const cb = this._rateLimit.waiting.shift();
523
432
  setImmediate(cb);
524
433
  }
525
434
  }
526
-
527
435
  /**
528
436
  * Returns true if there are free slots in the queue
529
437
  */
530
438
  isIdle() {
531
439
  return this.idling;
532
440
  }
533
-
534
- /**
535
- * Verifies SMTP configuration
536
- *
537
- * @param {Function} callback Callback function
538
- */
539
441
  verify(callback) {
540
442
  let promise;
541
-
542
443
  if (!callback) {
543
444
  promise = new Promise((resolve, reject) => {
544
445
  callback = shared.callbackPromise(resolve, reject);
545
446
  });
546
447
  }
547
-
448
+ // the error paths hand over the error alone
449
+ const done = callback;
548
450
  const auth = new PoolResource(this).auth;
549
-
550
451
  this.getSocket(this.options, (err, socketOptions) => {
551
452
  if (err) {
552
- return callback(err);
453
+ return done(err);
553
454
  }
554
-
555
455
  let options = this.options;
556
456
  if (socketOptions && socketOptions.connection) {
557
- this.logger.info(
558
- {
559
- tnx: 'proxy',
560
- remoteAddress: socketOptions.connection.remoteAddress,
561
- remotePort: socketOptions.connection.remotePort,
562
- destHost: options.host || '',
563
- destPort: options.port || '',
564
- action: 'connected'
565
- },
566
- 'Using proxied socket from %s:%s to %s:%s',
567
- socketOptions.connection.remoteAddress,
568
- socketOptions.connection.remotePort,
569
- options.host || '',
570
- options.port || ''
571
- );
457
+ this.logger.info({
458
+ tnx: 'proxy',
459
+ remoteAddress: socketOptions.connection.remoteAddress,
460
+ remotePort: socketOptions.connection.remotePort,
461
+ destHost: options.host || '',
462
+ destPort: options.port || '',
463
+ action: 'connected'
464
+ }, 'Using proxied socket from %s:%s to %s:%s', socketOptions.connection.remoteAddress, socketOptions.connection.remotePort, options.host || '', options.port || '');
572
465
  options = Object.assign(shared.assign(false, options), socketOptions);
573
466
  }
574
-
575
467
  const connection = new SMTPConnection(options);
576
468
  let returned = false;
577
-
578
469
  connection.once('error', err => {
579
470
  if (returned) {
580
471
  return;
581
472
  }
582
473
  returned = true;
583
474
  connection.close();
584
- return callback(err);
475
+ return done(err);
585
476
  });
586
-
587
477
  connection.once('end', () => {
588
478
  if (returned) {
589
479
  return;
590
480
  }
591
481
  returned = true;
592
- return callback(new Error('Connection closed'));
482
+ return done(new Error('Connection closed'));
593
483
  });
594
-
595
484
  const finalize = () => {
596
485
  if (returned) {
597
486
  return;
598
487
  }
599
488
  returned = true;
600
489
  connection.quit();
601
- return callback(null, true);
490
+ return done(null, true);
602
491
  };
603
-
604
- connection.connect(() => {
492
+ connection.connect(err => {
605
493
  if (returned) {
606
494
  return;
607
495
  }
608
-
496
+ if (err) {
497
+ returned = true;
498
+ connection.close();
499
+ return done(err);
500
+ }
609
501
  if (auth && (connection.allowsAuth || options.forceAuth)) {
610
502
  connection.login(auth, err => {
611
503
  if (returned) {
612
504
  return;
613
505
  }
614
-
615
506
  if (err) {
616
507
  returned = true;
617
508
  connection.close();
618
- return callback(err);
509
+ return done(err);
619
510
  }
620
-
621
511
  finalize();
622
512
  });
623
- } else if (!auth && connection.allowsAuth && options.forceAuth) {
513
+ }
514
+ else if (!auth && connection.allowsAuth && options.forceAuth) {
624
515
  const err = new Error('Authentication info was not provided');
625
516
  err.code = errors.ENOAUTH;
626
-
627
517
  returned = true;
628
518
  connection.close();
629
- return callback(err);
630
- } else {
519
+ return done(err);
520
+ }
521
+ else {
631
522
  finalize();
632
523
  }
633
524
  });
634
525
  });
635
-
636
526
  return promise;
637
527
  }
638
528
  }
639
-
640
- // expose to the world
641
- module.exports = SMTPPool;
529
+ export default SMTPPool;