@nocobase/plugin-workflow-mailer 2.3.0-beta.12 → 2.3.0-beta.14

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