@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
@@ -1,9 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const Stream = require('stream').Stream;
3
+ const { Stream } = require('stream');
4
4
  const nmfetch = require('../fetch');
5
5
  const crypto = require('crypto');
6
6
  const shared = require('../shared');
7
+ const errors = require('../errors');
7
8
 
8
9
  /**
9
10
  * XOAUTH2 access_token generator for Gmail.
@@ -32,6 +33,7 @@ const shared = require('../shared');
32
33
  * @param {Number} options.expires Optional Access Token expire time in ms
33
34
  * @param {Number} options.timeout Optional TTL for Access Token in seconds
34
35
  * @param {Function} options.provisionCallback Function to run when a new access token is required
36
+ * @param {Object} options.tls Optional TLS options forwarded to the HTTPS token request. Defaults to strict cert validation; supply { rejectUnauthorized: false } only for self-hosted OAuth providers on private CAs.
35
37
  */
36
38
  class XOAuth2 extends Stream {
37
39
  constructor(options, logger) {
@@ -41,11 +43,13 @@ class XOAuth2 extends Stream {
41
43
 
42
44
  if (options && options.serviceClient) {
43
45
  if (!options.privateKey || !options.user) {
44
- setImmediate(() => this.emit('error', new Error('Options "privateKey" and "user" are required for service account!')));
46
+ const err = new Error('Options "privateKey" and "user" are required for service account!');
47
+ err.code = errors.EOAUTH2;
48
+ setImmediate(() => this.emit('error', err));
45
49
  return;
46
50
  }
47
51
 
48
- let serviceRequestTimeout = Math.min(Math.max(Number(this.options.serviceRequestTimeout) || 0, 0), 3600);
52
+ const serviceRequestTimeout = Math.min(Math.max(Number(this.options.serviceRequestTimeout) || 0, 0), 3600);
49
53
  this.options.serviceRequestTimeout = serviceRequestTimeout || 5 * 60;
50
54
  }
51
55
 
@@ -69,9 +73,12 @@ class XOAuth2 extends Stream {
69
73
  if (this.options.expires && Number(this.options.expires)) {
70
74
  this.expires = this.options.expires;
71
75
  } else {
72
- let timeout = Math.max(Number(this.options.timeout) || 0, 0);
76
+ const timeout = Math.max(Number(this.options.timeout) || 0, 0);
73
77
  this.expires = (timeout && Date.now() + timeout * 1000) || 0;
74
78
  }
79
+
80
+ this.renewing = false; // Track if renewal is in progress
81
+ this.renewalQueue = []; // Queue for pending requests during renewal
75
82
  }
76
83
 
77
84
  /**
@@ -82,14 +89,63 @@ class XOAuth2 extends Stream {
82
89
  */
83
90
  getToken(renew, callback) {
84
91
  if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) {
92
+ this.logger.debug(
93
+ {
94
+ tnx: 'OAUTH2',
95
+ user: this.options.user,
96
+ action: 'reuse'
97
+ },
98
+ 'Reusing existing access token for %s',
99
+ this.options.user
100
+ );
85
101
  return callback(null, this.accessToken);
86
102
  }
87
103
 
88
- let generateCallback = (...args) => {
89
- if (args[0]) {
104
+ // check if it is possible to renew, if not, return the current token or error
105
+ if (!this.provisionCallback && !this.options.refreshToken && !this.options.serviceClient) {
106
+ if (this.accessToken) {
107
+ this.logger.debug(
108
+ {
109
+ tnx: 'OAUTH2',
110
+ user: this.options.user,
111
+ action: 'reuse'
112
+ },
113
+ 'Reusing existing access token (no refresh capability) for %s',
114
+ this.options.user
115
+ );
116
+ return callback(null, this.accessToken);
117
+ }
118
+ this.logger.error(
119
+ {
120
+ tnx: 'OAUTH2',
121
+ user: this.options.user,
122
+ action: 'renew'
123
+ },
124
+ 'Cannot renew access token for %s: No refresh mechanism available',
125
+ this.options.user
126
+ );
127
+ const err = new Error("Can't create new access token for user");
128
+ err.code = errors.EOAUTH2;
129
+ return callback(err);
130
+ }
131
+
132
+ // If renewal already in progress, queue this request instead of starting another
133
+ if (this.renewing) {
134
+ return this.renewalQueue.push({ renew, callback });
135
+ }
136
+
137
+ this.renewing = true;
138
+
139
+ // Handles token renewal completion - processes queued requests and cleans up
140
+ const generateCallback = (err, accessToken) => {
141
+ this.renewalQueue.forEach(item => item.callback(err, accessToken));
142
+ this.renewalQueue = [];
143
+ this.renewing = false;
144
+
145
+ if (err) {
90
146
  this.logger.error(
91
147
  {
92
- err: args[0],
148
+ err,
93
149
  tnx: 'OAUTH2',
94
150
  user: this.options.user,
95
151
  action: 'renew'
@@ -108,7 +164,8 @@ class XOAuth2 extends Stream {
108
164
  this.options.user
109
165
  );
110
166
  }
111
- callback(...args);
167
+ // Complete original request
168
+ callback(err, accessToken);
112
169
  };
113
170
 
114
171
  if (this.provisionCallback) {
@@ -154,8 +211,8 @@ class XOAuth2 extends Stream {
154
211
  let loggedUrlOptions;
155
212
  if (this.options.serviceClient) {
156
213
  // service account - https://developers.google.com/identity/protocols/OAuth2ServiceAccount
157
- let iat = Math.floor(Date.now() / 1000); // unix time
158
- let tokenData = {
214
+ const iat = Math.floor(Date.now() / 1000); // unix time
215
+ const tokenData = {
159
216
  iss: this.options.serviceClient,
160
217
  scope: this.options.scope || 'https://mail.google.com/',
161
218
  sub: this.options.user,
@@ -166,8 +223,10 @@ class XOAuth2 extends Stream {
166
223
  let token;
167
224
  try {
168
225
  token = this.jwtSignRS256(tokenData);
169
- } catch (err) {
170
- return callback(new Error('Can\x27t generate token. Check your auth options'));
226
+ } catch (_err) {
227
+ const err = new Error("Can't generate token. Check your auth options");
228
+ err.code = errors.EOAUTH2;
229
+ return callback(err);
171
230
  }
172
231
 
173
232
  urlOptions = {
@@ -181,7 +240,9 @@ class XOAuth2 extends Stream {
181
240
  };
182
241
  } else {
183
242
  if (!this.options.refreshToken) {
184
- return callback(new Error('Can\x27t create new access token for user'));
243
+ const err = new Error("Can't create new access token for user");
244
+ err.code = errors.EOAUTH2;
245
+ return callback(err);
185
246
  }
186
247
 
187
248
  // web app - https://developers.google.com/identity/protocols/OAuth2WebServer
@@ -200,10 +261,8 @@ class XOAuth2 extends Stream {
200
261
  };
201
262
  }
202
263
 
203
- Object.keys(this.options.customParams).forEach(key => {
204
- urlOptions[key] = this.options.customParams[key];
205
- loggedUrlOptions[key] = this.options.customParams[key];
206
- });
264
+ Object.assign(urlOptions, this.options.customParams);
265
+ Object.assign(loggedUrlOptions, this.options.customParams);
207
266
 
208
267
  this.logger.debug(
209
268
  {
@@ -238,17 +297,15 @@ class XOAuth2 extends Stream {
238
297
  'Response: %s',
239
298
  (body || '').toString()
240
299
  );
241
- return callback(new Error('Invalid authentication response'));
300
+ const err = new Error('Invalid authentication response');
301
+ err.code = errors.EOAUTH2;
302
+ return callback(err);
242
303
  }
243
304
 
244
- let logData = {};
245
- Object.keys(data).forEach(key => {
246
- if (key !== 'access_token') {
247
- logData[key] = data[key];
248
- } else {
249
- logData[key] = (data[key] || '').toString().substr(0, 6) + '...';
250
- }
251
- });
305
+ const logData = Object.assign({}, data);
306
+ if (logData.access_token) {
307
+ logData.access_token = (logData.access_token || '').toString().substr(0, 6) + '...';
308
+ }
252
309
 
253
310
  this.logger.debug(
254
311
  {
@@ -269,7 +326,9 @@ class XOAuth2 extends Stream {
269
326
  if (data.error_uri) {
270
327
  errorMessage += ' (' + data.error_uri + ')';
271
328
  }
272
- return callback(new Error(errorMessage));
329
+ const err = new Error(errorMessage);
330
+ err.code = errors.EOAUTH2;
331
+ return callback(err);
273
332
  }
274
333
 
275
334
  if (data.access_token) {
@@ -277,7 +336,9 @@ class XOAuth2 extends Stream {
277
336
  return callback(null, this.accessToken);
278
337
  }
279
338
 
280
- return callback(new Error('No access token'));
339
+ const err = new Error('No access token');
340
+ err.code = errors.EOAUTH2;
341
+ return callback(err);
281
342
  });
282
343
  }
283
344
 
@@ -288,7 +349,7 @@ class XOAuth2 extends Stream {
288
349
  * @return {String} Base64 encoded token for IMAP or SMTP login
289
350
  */
290
351
  buildXOAuth2Token(accessToken) {
291
- let authData = ['user=' + (this.options.user || ''), 'auth=Bearer ' + (accessToken || this.accessToken), '', ''];
352
+ const authData = ['user=' + (this.options.user || ''), 'auth=Bearer ' + (accessToken || this.accessToken), '', ''];
292
353
  return Buffer.from(authData.join('\x01'), 'utf-8').toString('base64');
293
354
  }
294
355
 
@@ -307,15 +368,26 @@ class XOAuth2 extends Stream {
307
368
  postRequest(url, payload, params, callback) {
308
369
  let returned = false;
309
370
 
310
- let chunks = [];
371
+ const chunks = [];
311
372
  let chunklen = 0;
312
373
 
313
- let req = nmfetch(url, {
374
+ const fetchOptions = {
314
375
  method: 'post',
315
376
  headers: params.customHeaders,
316
377
  body: payload,
317
378
  allowErrorResponse: true
318
- });
379
+ };
380
+
381
+ // OAuth2 token endpoints are credential-bearing. lib/fetch already
382
+ // validates certs by default; pin rejectUnauthorized:true here so the
383
+ // token fetch stays strict, while still layering params.tls (the
384
+ // user's options.tls) on top so callers with a self-hosted provider on
385
+ // a private CA can override.
386
+ if (/^https:/i.test(url)) {
387
+ fetchOptions.tls = Object.assign({ rejectUnauthorized: true }, params.tls || {});
388
+ }
389
+
390
+ const req = nmfetch(url, fetchOptions);
319
391
 
320
392
  req.on('readable', () => {
321
393
  let chunk;
@@ -368,7 +440,7 @@ class XOAuth2 extends Stream {
368
440
  */
369
441
  jwtSignRS256(payload) {
370
442
  payload = ['{"alg":"RS256","typ":"JWT"}', JSON.stringify(payload)].map(val => this.toBase64URL(val)).join('.');
371
- let signature = crypto.createSign('RSA-SHA256').update(payload).sign(this.options.privateKey);
443
+ const signature = crypto.createSign('RSA-SHA256').update(payload).sign(this.options.privateKey);
372
444
  return payload + '.' + this.toBase64URL(signature);
373
445
  }
374
446
  }
@@ -1 +1 @@
1
- {"name":"nodemailer","version":"6.9.13","description":"Easy as cake e-mail sending from your Node.js applications","main":"lib/nodemailer.js","scripts":{"test":"node --test --test-concurrency=1 test/**/*.test.js test/**/*-test.js","test:coverage":"c8 node --test --test-concurrency=1 test/**/*.test.js test/**/*-test.js","lint":"eslint .","update":"rm -rf node_modules/ package-lock.json && ncu -u && npm install"},"repository":{"type":"git","url":"https://github.com/nodemailer/nodemailer.git"},"keywords":["Nodemailer"],"author":"Andris Reinman","license":"MIT-0","bugs":{"url":"https://github.com/nodemailer/nodemailer/issues"},"homepage":"https://nodemailer.com/","devDependencies":{"@aws-sdk/client-ses":"3.529.1","bunyan":"1.8.15","c8":"9.1.0","eslint":"8.57.0","eslint-config-nodemailer":"1.2.0","eslint-config-prettier":"9.1.0","libbase64":"1.3.0","libmime":"5.3.4","libqp":"2.1.0","nodemailer-ntlm-auth":"1.0.4","proxy":"1.0.2","proxy-test-server":"1.0.0","smtp-server":"3.13.3"},"engines":{"node":">=6.0.0"},"_lastModified":"2026-09-24T00:59:07.639Z"}
1
+ {"name":"nodemailer","version":"9.1.1","description":"Easy as cake e-mail sending from your Node.js applications","main":"lib/nodemailer.js","scripts":{"test":"node --test --test-concurrency=1 $(find test \\( -name '*-test.js' -o -name '*.test.js' \\))","test:coverage":"c8 node --test --test-concurrency=1 $(find test \\( -name '*-test.js' -o -name '*.test.js' \\))","format":"prettier --write \"**/*.{js,json,md}\"","format:check":"prettier --check \"**/*.{js,json,md}\"","lint":"eslint .","lint:fix":"eslint . --fix","update":"rm -rf node_modules/ package-lock.json && ncu -u && npm install","test:syntax":"docker run --rm -v \"$PWD:/app:ro\" -w /app node:6-alpine node test/syntax-compat.js"},"repository":{"type":"git","url":"https://github.com/nodemailer/nodemailer.git"},"keywords":["Nodemailer"],"author":"Andris Reinman","license":"MIT-0","bugs":{"url":"https://github.com/nodemailer/nodemailer/issues"},"homepage":"https://nodemailer.com/","devDependencies":{"@aws-sdk/client-sesv2":"3.1121.0","bunyan":"1.8.15","c8":"12.0.0","eslint":"10.9.1","eslint-config-prettier":"10.1.8","globals":"17.11.0","libbase64":"1.3.0","libmime":"5.4.2","libqp":"2.1.1","prettier":"3.9.6","proxy":"1.0.2","proxy-test-server":"1.0.0","smtp-server":"3.19.4"},"engines":{"node":">=6.0.0"},"_lastModified":"2026-09-25T14:54:18.536Z"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Send email in workflow.",
7
7
  "description.ru-RU": "Отправляет электронное письмо в рамках рабочего процесса.",
8
8
  "description.zh-CN": "可用于在工作流中发送电子邮件。",
9
- "version": "2.2.17",
9
+ "version": "2.2.18",
10
10
  "license": "Apache-2.0",
11
11
  "main": "./dist/server/index.js",
12
12
  "homepage": "https://docs.nocobase.com/handbook/workflow-smtp-mailer",
@@ -14,8 +14,8 @@
14
14
  "homepage.ru-RU": "https://docs-ru.nocobase.com/handbook/workflow-smtp-mailer",
15
15
  "devDependencies": {
16
16
  "antd": "5.x",
17
- "joi": "^17.13.3",
18
- "nodemailer": "6.9.13",
17
+ "joi": "^17.13.6",
18
+ "nodemailer": "^9.1.1",
19
19
  "react": "18.x"
20
20
  },
21
21
  "peerDependencies": {
@@ -27,7 +27,7 @@
27
27
  "@nocobase/server": "2.x",
28
28
  "@nocobase/test": "2.x"
29
29
  },
30
- "gitHead": "08565a7d1c326c4c2d190150f303596dda9c6450",
30
+ "gitHead": "0c464cd27b2c1ccdf10b00d339bf6599b18bee22",
31
31
  "keywords": [
32
32
  "NocoBase",
33
33
  "Workflow",