@nocobase/plugin-workflow-mailer 2.2.16 → 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.
- package/dist/externalVersion.js +6 -6
- package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
- package/dist/node_modules/joi/lib/index.js +1 -1
- package/dist/node_modules/joi/lib/messages.js +35 -6
- package/dist/node_modules/joi/lib/types/keys.js +18 -1
- package/dist/node_modules/joi/lib/types/link.js +18 -2
- package/dist/node_modules/joi/lib/types/string.js +2 -2
- package/dist/node_modules/joi/package.json +1 -1
- package/dist/node_modules/nodemailer/.ncurc.js +2 -0
- package/dist/node_modules/nodemailer/.prettierignore +8 -0
- package/dist/node_modules/nodemailer/.prettierrc +12 -0
- package/dist/node_modules/nodemailer/.prettierrc.js +2 -0
- package/dist/node_modules/nodemailer/.release-please-config.json +9 -0
- package/dist/node_modules/nodemailer/eslint.config.js +88 -0
- package/dist/node_modules/nodemailer/lib/addressparser/index.js +314 -71
- package/dist/node_modules/nodemailer/lib/base64/index.js +9 -13
- package/dist/node_modules/nodemailer/lib/dkim/index.js +17 -18
- package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +12 -13
- package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +3 -3
- package/dist/node_modules/nodemailer/lib/dkim/sign.js +22 -18
- package/dist/node_modules/nodemailer/lib/errors.js +59 -0
- package/dist/node_modules/nodemailer/lib/fetch/cookies.js +14 -19
- package/dist/node_modules/nodemailer/lib/fetch/index.js +164 -27
- package/dist/node_modules/nodemailer/lib/json-transport/index.js +4 -4
- package/dist/node_modules/nodemailer/lib/mail-composer/index.js +229 -155
- package/dist/node_modules/nodemailer/lib/mailer/index.js +106 -54
- package/dist/node_modules/nodemailer/lib/mailer/mail-message.js +106 -68
- package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +105 -59
- package/dist/node_modules/nodemailer/lib/mime-funcs/mime-types.js +21 -14
- package/dist/node_modules/nodemailer/lib/mime-node/index.js +389 -137
- package/dist/node_modules/nodemailer/lib/mime-node/last-newline.js +1 -1
- package/dist/node_modules/nodemailer/lib/mime-node/le-unix.js +4 -7
- package/dist/node_modules/nodemailer/lib/mime-node/le-windows.js +1 -4
- package/dist/node_modules/nodemailer/lib/nodemailer.js +1 -1
- package/dist/node_modules/nodemailer/lib/punycode/index.js +1 -1
- package/dist/node_modules/nodemailer/lib/qp/index.js +33 -22
- package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +54 -44
- package/dist/node_modules/nodemailer/lib/ses-transport/index.js +110 -193
- package/dist/node_modules/nodemailer/lib/shared/index.js +299 -240
- package/dist/node_modules/nodemailer/lib/shared/objects.js +42 -0
- package/dist/node_modules/nodemailer/lib/shared/url.js +151 -0
- package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +3 -6
- package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +50 -19
- package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +415 -223
- package/dist/node_modules/nodemailer/lib/smtp-pool/index.js +27 -34
- package/dist/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +19 -16
- package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +66 -53
- package/dist/node_modules/nodemailer/lib/stream-transport/index.js +16 -7
- package/dist/node_modules/nodemailer/lib/well-known/index.js +7 -7
- package/dist/node_modules/nodemailer/lib/well-known/services.json +328 -38
- package/dist/node_modules/nodemailer/lib/xoauth2/index.js +105 -33
- package/dist/node_modules/nodemailer/package.json +1 -1
- 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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
155
|
-
let
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
163
|
-
|
|
69
|
+
const envelope = mail.message.getEnvelope();
|
|
70
|
+
const messageId = mail.message.messageId();
|
|
164
71
|
|
|
165
|
-
|
|
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
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
235
|
-
|
|
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
|
-
|
|
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
|
-
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
sendPromise = ses.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
}
|