@nocobase/plugin-workflow-mailer 2.2.17 → 2.2.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/externalVersion.js +6 -6
  2. package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
  3. package/dist/node_modules/joi/lib/index.js +1 -1
  4. package/dist/node_modules/joi/lib/messages.js +35 -6
  5. package/dist/node_modules/joi/lib/types/keys.js +18 -1
  6. package/dist/node_modules/joi/lib/types/link.js +18 -2
  7. package/dist/node_modules/joi/lib/types/string.js +2 -2
  8. package/dist/node_modules/joi/package.json +1 -1
  9. package/dist/node_modules/nodemailer/.ncurc.js +2 -0
  10. package/dist/node_modules/nodemailer/.prettierignore +8 -0
  11. package/dist/node_modules/nodemailer/.prettierrc +12 -0
  12. package/dist/node_modules/nodemailer/.prettierrc.js +2 -0
  13. package/dist/node_modules/nodemailer/.release-please-config.json +9 -0
  14. package/dist/node_modules/nodemailer/eslint.config.js +88 -0
  15. package/dist/node_modules/nodemailer/lib/addressparser/index.js +314 -71
  16. package/dist/node_modules/nodemailer/lib/base64/index.js +9 -13
  17. package/dist/node_modules/nodemailer/lib/dkim/index.js +17 -18
  18. package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +12 -13
  19. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +3 -3
  20. package/dist/node_modules/nodemailer/lib/dkim/sign.js +22 -18
  21. package/dist/node_modules/nodemailer/lib/errors.js +59 -0
  22. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +14 -19
  23. package/dist/node_modules/nodemailer/lib/fetch/index.js +164 -27
  24. package/dist/node_modules/nodemailer/lib/json-transport/index.js +4 -4
  25. package/dist/node_modules/nodemailer/lib/mail-composer/index.js +229 -155
  26. package/dist/node_modules/nodemailer/lib/mailer/index.js +106 -54
  27. package/dist/node_modules/nodemailer/lib/mailer/mail-message.js +106 -68
  28. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +105 -59
  29. package/dist/node_modules/nodemailer/lib/mime-funcs/mime-types.js +21 -14
  30. package/dist/node_modules/nodemailer/lib/mime-node/index.js +389 -137
  31. package/dist/node_modules/nodemailer/lib/mime-node/last-newline.js +1 -1
  32. package/dist/node_modules/nodemailer/lib/mime-node/le-unix.js +4 -7
  33. package/dist/node_modules/nodemailer/lib/mime-node/le-windows.js +1 -4
  34. package/dist/node_modules/nodemailer/lib/nodemailer.js +1 -1
  35. package/dist/node_modules/nodemailer/lib/punycode/index.js +1 -1
  36. package/dist/node_modules/nodemailer/lib/qp/index.js +33 -22
  37. package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +54 -44
  38. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +110 -193
  39. package/dist/node_modules/nodemailer/lib/shared/index.js +299 -240
  40. package/dist/node_modules/nodemailer/lib/shared/objects.js +42 -0
  41. package/dist/node_modules/nodemailer/lib/shared/url.js +151 -0
  42. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +3 -6
  43. package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +50 -19
  44. package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +415 -223
  45. package/dist/node_modules/nodemailer/lib/smtp-pool/index.js +27 -34
  46. package/dist/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +19 -16
  47. package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +66 -53
  48. package/dist/node_modules/nodemailer/lib/stream-transport/index.js +16 -7
  49. package/dist/node_modules/nodemailer/lib/well-known/index.js +7 -7
  50. package/dist/node_modules/nodemailer/lib/well-known/services.json +328 -38
  51. package/dist/node_modules/nodemailer/lib/xoauth2/index.js +105 -33
  52. package/dist/node_modules/nodemailer/package.json +1 -1
  53. package/package.json +4 -4
@@ -3,16 +3,25 @@
3
3
  const EventEmitter = require('events');
4
4
  const packageData = require('../../package.json');
5
5
  const shared = require('../shared');
6
+ const errors = require('../errors');
6
7
  const LeWindows = require('../mime-node/le-windows');
8
+ const MimeNode = require('../mime-node');
9
+
10
+ /**
11
+ * Tags AWS SDK rejections that carry no `code` property (SDK v3 errors only
12
+ * have a `name`) with the generic SES transport error code, keeping the
13
+ * original error object intact
14
+ */
15
+ function tagSesError(err) {
16
+ if (err && typeof err === 'object' && !err.code) {
17
+ err.code = errors.ESES;
18
+ }
19
+ return err;
20
+ }
7
21
 
8
22
  /**
9
23
  * Generates a Transport object for AWS SES
10
24
  *
11
- * Possible options can be the following:
12
- *
13
- * * **sendingRate** optional Number specifying how many messages per second should be delivered to SES
14
- * * **maxConnections** optional Number specifying max number of parallel connections to SES
15
- *
16
25
  * @constructor
17
26
  * @param {Object} optional config parameter
18
27
  */
@@ -21,7 +30,7 @@ class SESTransport extends EventEmitter {
21
30
  super();
22
31
  options = options || {};
23
32
 
24
- this.options = options || {};
33
+ this.options = options;
25
34
  this.ses = this.options.SES;
26
35
 
27
36
  this.name = 'SESTransport';
@@ -30,119 +39,18 @@ class SESTransport extends EventEmitter {
30
39
  this.logger = shared.getLogger(this.options, {
31
40
  component: this.options.component || 'ses-transport'
32
41
  });
33
-
34
- // parallel sending connections
35
- this.maxConnections = Number(this.options.maxConnections) || Infinity;
36
- this.connections = 0;
37
-
38
- // max messages per second
39
- this.sendingRate = Number(this.options.sendingRate) || Infinity;
40
- this.sendingRateTTL = null;
41
- this.rateInterval = 1000; // milliseconds
42
- this.rateMessages = [];
43
-
44
- this.pending = [];
45
-
46
- this.idling = true;
47
-
48
- setImmediate(() => {
49
- if (this.idling) {
50
- this.emit('idle');
51
- }
52
- });
53
42
  }
54
43
 
55
- /**
56
- * Schedules a sending of a message
57
- *
58
- * @param {Object} emailMessage MailComposer object
59
- * @param {Function} callback Callback function to run when the sending is completed
60
- */
61
- send(mail, callback) {
62
- if (this.connections >= this.maxConnections) {
63
- this.idling = false;
64
- return this.pending.push({
65
- mail,
66
- callback
67
- });
44
+ getRegion(cb) {
45
+ if (this.ses.sesClient.config && typeof this.ses.sesClient.config.region === 'function') {
46
+ // Resolve the region provider. Use the two-argument form of then() so that a
47
+ // synchronous throw from cb is not recaught here and used to invoke cb a second time.
48
+ return this.ses.sesClient.config.region().then(
49
+ region => cb(null, region),
50
+ err => cb(err)
51
+ );
68
52
  }
69
-
70
- if (!this._checkSendingRate()) {
71
- this.idling = false;
72
- return this.pending.push({
73
- mail,
74
- callback
75
- });
76
- }
77
-
78
- this._send(mail, (...args) => {
79
- setImmediate(() => callback(...args));
80
- this._sent();
81
- });
82
- }
83
-
84
- _checkRatedQueue() {
85
- if (this.connections >= this.maxConnections || !this._checkSendingRate()) {
86
- return;
87
- }
88
-
89
- if (!this.pending.length) {
90
- if (!this.idling) {
91
- this.idling = true;
92
- this.emit('idle');
93
- }
94
- return;
95
- }
96
-
97
- let next = this.pending.shift();
98
- this._send(next.mail, (...args) => {
99
- setImmediate(() => next.callback(...args));
100
- this._sent();
101
- });
102
- }
103
-
104
- _checkSendingRate() {
105
- clearTimeout(this.sendingRateTTL);
106
-
107
- let now = Date.now();
108
- let oldest = false;
109
- // delete older messages
110
- for (let i = this.rateMessages.length - 1; i >= 0; i--) {
111
- if (this.rateMessages[i].ts >= now - this.rateInterval && (!oldest || this.rateMessages[i].ts < oldest)) {
112
- oldest = this.rateMessages[i].ts;
113
- }
114
-
115
- if (this.rateMessages[i].ts < now - this.rateInterval && !this.rateMessages[i].pending) {
116
- this.rateMessages.splice(i, 1);
117
- }
118
- }
119
-
120
- if (this.rateMessages.length < this.sendingRate) {
121
- return true;
122
- }
123
-
124
- let delay = Math.max(oldest + 1001, now + 20);
125
- this.sendingRateTTL = setTimeout(() => this._checkRatedQueue(), now - delay);
126
-
127
- try {
128
- this.sendingRateTTL.unref();
129
- } catch (E) {
130
- // Ignore. Happens on envs with non-node timer implementation
131
- }
132
-
133
- return false;
134
- }
135
-
136
- _sent() {
137
- this.connections--;
138
- this._checkRatedQueue();
139
- }
140
-
141
- /**
142
- * Returns true if there are free slots in the queue
143
- */
144
- isIdle() {
145
- return this.idling;
53
+ return cb(null, false);
146
54
  }
147
55
 
148
56
  /**
@@ -151,18 +59,17 @@ class SESTransport extends EventEmitter {
151
59
  * @param {Object} emailMessage MailComposer object
152
60
  * @param {Function} callback Callback function to run when the sending is completed
153
61
  */
154
- _send(mail, callback) {
155
- let statObject = {
156
- ts: Date.now(),
157
- pending: true
158
- };
159
- this.connections++;
160
- this.rateMessages.push(statObject);
62
+ send(mail, callback) {
63
+ let fromHeader = mail.message._headers.find(header => /^from$/i.test(header.key));
64
+ if (fromHeader) {
65
+ const mimeNode = new MimeNode('text/plain');
66
+ fromHeader = mimeNode._convertAddresses(mimeNode._parseAddresses(fromHeader.value));
67
+ }
161
68
 
162
- let envelope = mail.data.envelope || mail.message.getEnvelope();
163
- let messageId = mail.message.messageId();
69
+ const envelope = mail.message.getEnvelope();
70
+ const messageId = mail.message.messageId();
164
71
 
165
- let recipients = [].concat(envelope.to || []);
72
+ const recipients = [].concat(envelope.to || []);
166
73
  if (recipients.length > 3) {
167
74
  recipients.push('...and ' + recipients.splice(2).length + ' more');
168
75
  }
@@ -176,7 +83,7 @@ class SESTransport extends EventEmitter {
176
83
  recipients.join(', ')
177
84
  );
178
85
 
179
- let getRawMessage = next => {
86
+ const getRawMessage = next => {
180
87
  // do not use Message-ID and Date in DKIM signature
181
88
  if (!mail.data._dkim) {
182
89
  mail.data._dkim = {};
@@ -187,9 +94,9 @@ class SESTransport extends EventEmitter {
187
94
  mail.data._dkim.skipFields = 'date:message-id';
188
95
  }
189
96
 
190
- let sourceStream = mail.message.createReadStream();
191
- let stream = sourceStream.pipe(new LeWindows());
192
- let chunks = [];
97
+ const sourceStream = mail.message.createReadStream();
98
+ const stream = sourceStream.pipe(new LeWindows());
99
+ const chunks = [];
193
100
  let chunklen = 0;
194
101
 
195
102
  stream.on('readable', () => {
@@ -202,9 +109,7 @@ class SESTransport extends EventEmitter {
202
109
 
203
110
  sourceStream.once('error', err => stream.emit('error', err));
204
111
 
205
- stream.once('error', err => {
206
- next(err);
207
- });
112
+ stream.once('error', err => next(err));
208
113
 
209
114
  stream.once('end', () => next(null, Buffer.concat(chunks, chunklen)));
210
115
  };
@@ -222,49 +127,51 @@ class SESTransport extends EventEmitter {
222
127
  messageId,
223
128
  err.message
224
129
  );
225
- statObject.pending = false;
226
130
  return callback(err);
227
131
  }
228
132
 
229
- let sesMessage = {
230
- RawMessage: {
231
- // required
232
- Data: raw // required
133
+ // mail.data.ses is caller supplied message data, so copy its own keys only
134
+ const sesMessage = shared.copyOwnKeys(
135
+ {
136
+ Content: {
137
+ Raw: {
138
+ // required
139
+ Data: raw // required
140
+ }
141
+ },
142
+ FromEmailAddress: fromHeader || envelope.from,
143
+ Destination: {
144
+ ToAddresses: envelope.to
145
+ }
233
146
  },
234
- Source: envelope.from,
235
- Destinations: envelope.to
236
- };
237
-
238
- Object.keys(mail.data.ses || {}).forEach(key => {
239
- sesMessage[key] = mail.data.ses[key];
240
- });
147
+ mail.data.ses
148
+ );
241
149
 
242
- let ses = (this.ses.aws ? this.ses.ses : this.ses) || {};
243
- let aws = this.ses.aws || {};
244
-
245
- let getRegion = cb => {
246
- if (ses.config && typeof ses.config.region === 'function') {
247
- // promise
248
- return ses.config
249
- .region()
250
- .then(region => cb(null, region))
251
- .catch(err => cb(err));
252
- }
253
- return cb(null, (ses.config && ses.config.region) || 'us-east-1');
254
- };
255
-
256
- getRegion((err, region) => {
150
+ this.getRegion((err, region) => {
257
151
  if (err || !region) {
258
152
  region = 'us-east-1';
259
153
  }
260
154
 
261
155
  let sendPromise;
262
- if (typeof ses.send === 'function' && aws.SendRawEmailCommand) {
263
- // v3 API
264
- sendPromise = ses.send(new aws.SendRawEmailCommand(sesMessage));
265
- } else {
266
- // v2 API
267
- sendPromise = ses.sendRawEmail(sesMessage).promise();
156
+ try {
157
+ // command construction or dispatch can throw synchronously on a
158
+ // misconfigured SDK; surface it as a single error callback instead
159
+ // of letting it escape into getRegion's promise chain
160
+ const command = new this.ses.SendEmailCommand(sesMessage);
161
+ sendPromise = this.ses.sesClient.send(command);
162
+ } catch (err) {
163
+ tagSesError(err);
164
+ this.logger.error(
165
+ {
166
+ err,
167
+ tnx: 'send'
168
+ },
169
+ 'Send error for %s: %s',
170
+ messageId,
171
+ err.message
172
+ );
173
+ setImmediate(() => callback(err));
174
+ return;
268
175
  }
269
176
 
270
177
  sendPromise
@@ -273,8 +180,7 @@ class SESTransport extends EventEmitter {
273
180
  region = 'email';
274
181
  }
275
182
 
276
- statObject.pending = false;
277
- callback(null, {
183
+ const info = {
278
184
  envelope: {
279
185
  from: envelope.from,
280
186
  to: envelope.to
@@ -282,9 +188,14 @@ class SESTransport extends EventEmitter {
282
188
  messageId: '<' + data.MessageId + (!/@/.test(data.MessageId) ? '@' + region + '.amazonses.com' : '') + '>',
283
189
  response: data.MessageId,
284
190
  raw
285
- });
191
+ };
192
+
193
+ // invoke the callback outside the promise chain so a throw from it
194
+ // is not recaught by .catch() and used to call it a second time
195
+ setImmediate(() => callback(null, info));
286
196
  })
287
197
  .catch(err => {
198
+ tagSesError(err);
288
199
  this.logger.error(
289
200
  {
290
201
  err,
@@ -294,8 +205,7 @@ class SESTransport extends EventEmitter {
294
205
  messageId,
295
206
  err.message
296
207
  );
297
- statObject.pending = false;
298
- callback(err);
208
+ setImmediate(() => callback(err));
299
209
  });
300
210
  });
301
211
  })
@@ -309,38 +219,45 @@ class SESTransport extends EventEmitter {
309
219
  */
310
220
  verify(callback) {
311
221
  let promise;
312
- let ses = (this.ses.aws ? this.ses.ses : this.ses) || {};
313
- let aws = this.ses.aws || {};
314
-
315
- const sesMessage = {
316
- RawMessage: {
317
- // required
318
- Data: 'From: invalid@invalid\r\nTo: invalid@invalid\r\n Subject: Invalid\r\n\r\nInvalid'
319
- },
320
- Source: 'invalid@invalid',
321
- Destinations: ['invalid@invalid']
322
- };
323
-
324
222
  if (!callback) {
325
223
  promise = new Promise((resolve, reject) => {
326
224
  callback = shared.callbackPromise(resolve, reject);
327
225
  });
328
226
  }
227
+
329
228
  const cb = err => {
330
- if (err && (err.code || err.Code) !== 'InvalidParameterValue') {
331
- return callback(err);
229
+ if (err && !['InvalidParameterValue', 'MessageRejected'].includes(err.code || err.Code || err.name)) {
230
+ return callback(tagSesError(err));
332
231
  }
333
232
  return callback(null, true);
334
233
  };
335
234
 
336
- if (typeof ses.send === 'function' && aws.SendRawEmailCommand) {
337
- // v3 API
338
- sesMessage.RawMessage.Data = Buffer.from(sesMessage.RawMessage.Data);
339
- ses.send(new aws.SendRawEmailCommand(sesMessage), cb);
340
- } else {
341
- // v2 API
342
- ses.sendRawEmail(sesMessage, cb);
343
- }
235
+ const sesMessage = {
236
+ Content: {
237
+ Raw: {
238
+ Data: Buffer.from('From: <invalid@invalid>\r\nTo: <invalid@invalid>\r\n Subject: Invalid\r\n\r\nInvalid')
239
+ }
240
+ },
241
+ FromEmailAddress: 'invalid@invalid',
242
+ Destination: {
243
+ ToAddresses: ['invalid@invalid']
244
+ }
245
+ };
246
+
247
+ // the region value is not used for anything when verifying, but the lookup
248
+ // exercises the client configuration the same way as send() does
249
+ this.getRegion(() => {
250
+ let sendPromise;
251
+ try {
252
+ const command = new this.ses.SendEmailCommand(sesMessage);
253
+ sendPromise = this.ses.sesClient.send(command);
254
+ } catch (err) {
255
+ setImmediate(() => cb(err));
256
+ return;
257
+ }
258
+
259
+ sendPromise.then(() => setImmediate(() => cb(null))).catch(err => setImmediate(() => cb(err)));
260
+ });
344
261
 
345
262
  return promise;
346
263
  }