@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.
- 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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const MimeNode = require('../mime-node');
|
|
6
6
|
const mimeFuncs = require('../mime-funcs');
|
|
7
|
-
const parseDataURI = require('../shared')
|
|
7
|
+
const { parseDataURI, copyOwnKeys } = require('../shared');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates the object for composing a MimeNode instance out from the mail options
|
|
@@ -32,7 +32,11 @@ class MailComposer {
|
|
|
32
32
|
|
|
33
33
|
// Compose MIME tree
|
|
34
34
|
if (this.mail.raw) {
|
|
35
|
-
this.message = new MimeNode('message/rfc822', {
|
|
35
|
+
this.message = new MimeNode('message/rfc822', {
|
|
36
|
+
newline: this.mail.newline,
|
|
37
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
38
|
+
disableFileAccess: this.mail.disableFileAccess
|
|
39
|
+
}).setRaw(this.mail.raw);
|
|
36
40
|
} else if (this._useMixed) {
|
|
37
41
|
this.message = this._createMixed();
|
|
38
42
|
} else if (this._useAlternative) {
|
|
@@ -59,7 +63,7 @@ class MailComposer {
|
|
|
59
63
|
|
|
60
64
|
// Add headers to the root node, always overrides custom headers
|
|
61
65
|
['from', 'sender', 'to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'message-id', 'date'].forEach(header => {
|
|
62
|
-
|
|
66
|
+
const key = header.replace(/-(\w)/g, (o, c) => c.toUpperCase());
|
|
63
67
|
if (this.mail[key]) {
|
|
64
68
|
this.message.setHeader(header, this.mail[key]);
|
|
65
69
|
}
|
|
@@ -83,23 +87,36 @@ class MailComposer {
|
|
|
83
87
|
* @returns {Object} An object of arrays (`related` and `attached`)
|
|
84
88
|
*/
|
|
85
89
|
getAttachments(findRelated) {
|
|
86
|
-
let
|
|
87
|
-
|
|
88
|
-
let data;
|
|
89
|
-
let isMessageNode = /^message\//i.test(attachment.contentType);
|
|
90
|
-
|
|
90
|
+
let eventObject;
|
|
91
|
+
const attachments = [].concat(this.mail.attachments || []).map((attachment, i) => {
|
|
91
92
|
if (/^data:/i.test(attachment.path || attachment.href)) {
|
|
92
93
|
attachment = this._processDataUrl(attachment);
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const contentType =
|
|
97
|
+
attachment.contentType || mimeFuncs.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin');
|
|
98
|
+
|
|
99
|
+
const isImage = /^image\//i.test(contentType);
|
|
100
|
+
const isMessageNode = /^message\//i.test(contentType);
|
|
101
|
+
|
|
102
|
+
const contentDisposition =
|
|
103
|
+
attachment.contentDisposition || (isMessageNode || (isImage && attachment.cid) ? 'inline' : 'attachment');
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
let contentTransferEncoding;
|
|
106
|
+
if ('contentTransferEncoding' in attachment) {
|
|
107
|
+
// also contains `false`, to set
|
|
108
|
+
contentTransferEncoding = attachment.contentTransferEncoding;
|
|
109
|
+
} else if (isMessageNode) {
|
|
110
|
+
// the content might include non-ASCII bytes but at this point we do not know it yet
|
|
111
|
+
contentTransferEncoding = '8bit';
|
|
112
|
+
} else {
|
|
113
|
+
contentTransferEncoding = 'base64'; // the default
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const data = {
|
|
100
117
|
contentType,
|
|
101
118
|
contentDisposition,
|
|
102
|
-
contentTransferEncoding
|
|
119
|
+
contentTransferEncoding
|
|
103
120
|
};
|
|
104
121
|
|
|
105
122
|
if (attachment.filename) {
|
|
@@ -129,7 +146,8 @@ class MailComposer {
|
|
|
129
146
|
} else if (attachment.href) {
|
|
130
147
|
data.content = {
|
|
131
148
|
href: attachment.href,
|
|
132
|
-
httpHeaders: attachment.httpHeaders
|
|
149
|
+
httpHeaders: attachment.httpHeaders,
|
|
150
|
+
tls: attachment.tls
|
|
133
151
|
};
|
|
134
152
|
} else {
|
|
135
153
|
data.content = attachment.content || '';
|
|
@@ -147,21 +165,7 @@ class MailComposer {
|
|
|
147
165
|
});
|
|
148
166
|
|
|
149
167
|
if (this.mail.icalEvent) {
|
|
150
|
-
|
|
151
|
-
typeof this.mail.icalEvent === 'object' &&
|
|
152
|
-
(this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
|
|
153
|
-
) {
|
|
154
|
-
icalEvent = this.mail.icalEvent;
|
|
155
|
-
} else {
|
|
156
|
-
icalEvent = {
|
|
157
|
-
content: this.mail.icalEvent
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
eventObject = {};
|
|
162
|
-
Object.keys(icalEvent).forEach(key => {
|
|
163
|
-
eventObject[key] = icalEvent[key];
|
|
164
|
-
});
|
|
168
|
+
eventObject = Object.assign({}, this._getIcalEvent());
|
|
165
169
|
|
|
166
170
|
eventObject.contentType = 'application/ics';
|
|
167
171
|
if (!eventObject.headers) {
|
|
@@ -177,12 +181,75 @@ class MailComposer {
|
|
|
177
181
|
attached: attachments.concat(eventObject || []),
|
|
178
182
|
related: []
|
|
179
183
|
};
|
|
180
|
-
} else {
|
|
181
|
-
return {
|
|
182
|
-
attached: attachments.filter(attachment => !attachment.cid).concat(eventObject || []),
|
|
183
|
-
related: attachments.filter(attachment => !!attachment.cid)
|
|
184
|
-
};
|
|
185
184
|
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
attached: attachments.filter(attachment => !attachment.cid).concat(eventObject || []),
|
|
188
|
+
related: attachments.filter(attachment => !!attachment.cid)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Returns the icalEvent value with `path`/`href`/data uri input normalized into
|
|
194
|
+
* a `content` entry, the same way as for regular attachments. The same event is
|
|
195
|
+
* included twice (as a text/calendar alternative and as an application/ics
|
|
196
|
+
* attachment), so the shared content object is marked to be resolved just once
|
|
197
|
+
* and the buffered result is reused by the second node.
|
|
198
|
+
*
|
|
199
|
+
* @returns {Object} Normalized icalEvent data
|
|
200
|
+
*/
|
|
201
|
+
_getIcalEvent() {
|
|
202
|
+
if (!this._icalEvent) {
|
|
203
|
+
let icalEvent;
|
|
204
|
+
if (
|
|
205
|
+
typeof this.mail.icalEvent === 'object' &&
|
|
206
|
+
(this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
|
|
207
|
+
) {
|
|
208
|
+
// an own "__proto__" key would make the copy inherit path/href from caller
|
|
209
|
+
// data, and the mapping below then replaces the content the caller did set
|
|
210
|
+
icalEvent = copyOwnKeys({}, this.mail.icalEvent);
|
|
211
|
+
} else {
|
|
212
|
+
icalEvent = {
|
|
213
|
+
content: this.mail.icalEvent
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (/^data:/i.test(icalEvent.path || icalEvent.href)) {
|
|
218
|
+
icalEvent = this._processDataUrl(icalEvent);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (/^https?:\/\//i.test(icalEvent.path)) {
|
|
222
|
+
icalEvent.href = icalEvent.path;
|
|
223
|
+
icalEvent.path = undefined;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (!icalEvent.raw) {
|
|
227
|
+
// map file path and URL values into `content`, otherwise the content
|
|
228
|
+
// nodes would render an empty body
|
|
229
|
+
if (icalEvent.path) {
|
|
230
|
+
icalEvent.content = {
|
|
231
|
+
path: icalEvent.path
|
|
232
|
+
};
|
|
233
|
+
icalEvent.path = undefined;
|
|
234
|
+
} else if (icalEvent.href) {
|
|
235
|
+
icalEvent.content = {
|
|
236
|
+
href: icalEvent.href,
|
|
237
|
+
httpHeaders: icalEvent.httpHeaders
|
|
238
|
+
};
|
|
239
|
+
icalEvent.href = undefined;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (icalEvent.content && typeof icalEvent.content === 'object') {
|
|
244
|
+
// we are going to have the same attachment twice, so mark this to be
|
|
245
|
+
// resolved just once
|
|
246
|
+
icalEvent.content._resolve = true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
this._icalEvent = icalEvent;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return this._icalEvent;
|
|
186
253
|
}
|
|
187
254
|
|
|
188
255
|
/**
|
|
@@ -191,16 +258,14 @@ class MailComposer {
|
|
|
191
258
|
* @returns {Array} An array of alternative elements. Includes the `text` and `html` values as well
|
|
192
259
|
*/
|
|
193
260
|
getAlternatives() {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
html,
|
|
197
|
-
watchHtml,
|
|
198
|
-
amp,
|
|
199
|
-
icalEvent,
|
|
200
|
-
eventObject;
|
|
261
|
+
const alternatives = [];
|
|
262
|
+
let text, html, watchHtml, amp, eventObject;
|
|
201
263
|
|
|
202
264
|
if (this.mail.text) {
|
|
203
|
-
if (
|
|
265
|
+
if (
|
|
266
|
+
typeof this.mail.text === 'object' &&
|
|
267
|
+
(this.mail.text.content || this.mail.text.path || this.mail.text.href || this.mail.text.raw)
|
|
268
|
+
) {
|
|
204
269
|
text = this.mail.text;
|
|
205
270
|
} else {
|
|
206
271
|
text = {
|
|
@@ -225,7 +290,10 @@ class MailComposer {
|
|
|
225
290
|
}
|
|
226
291
|
|
|
227
292
|
if (this.mail.amp) {
|
|
228
|
-
if (
|
|
293
|
+
if (
|
|
294
|
+
typeof this.mail.amp === 'object' &&
|
|
295
|
+
(this.mail.amp.content || this.mail.amp.path || this.mail.amp.href || this.mail.amp.raw)
|
|
296
|
+
) {
|
|
229
297
|
amp = this.mail.amp;
|
|
230
298
|
} else {
|
|
231
299
|
amp = {
|
|
@@ -237,37 +305,21 @@ class MailComposer {
|
|
|
237
305
|
|
|
238
306
|
// NB! when including attachments with a calendar alternative you might end up in a blank screen on some clients
|
|
239
307
|
if (this.mail.icalEvent) {
|
|
240
|
-
|
|
241
|
-
typeof this.mail.icalEvent === 'object' &&
|
|
242
|
-
(this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
|
|
243
|
-
) {
|
|
244
|
-
icalEvent = this.mail.icalEvent;
|
|
245
|
-
} else {
|
|
246
|
-
icalEvent = {
|
|
247
|
-
content: this.mail.icalEvent
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
eventObject = {};
|
|
252
|
-
Object.keys(icalEvent).forEach(key => {
|
|
253
|
-
eventObject[key] = icalEvent[key];
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
if (eventObject.content && typeof eventObject.content === 'object') {
|
|
257
|
-
// we are going to have the same attachment twice, so mark this to be
|
|
258
|
-
// resolved just once
|
|
259
|
-
eventObject.content._resolve = true;
|
|
260
|
-
}
|
|
308
|
+
eventObject = Object.assign({}, this._getIcalEvent());
|
|
261
309
|
|
|
262
310
|
eventObject.filename = false;
|
|
263
|
-
eventObject.contentType =
|
|
311
|
+
eventObject.contentType =
|
|
312
|
+
'text/calendar; charset=utf-8; method=' + (eventObject.method || 'PUBLISH').toString().trim().toUpperCase();
|
|
264
313
|
if (!eventObject.headers) {
|
|
265
314
|
eventObject.headers = {};
|
|
266
315
|
}
|
|
267
316
|
}
|
|
268
317
|
|
|
269
318
|
if (this.mail.html) {
|
|
270
|
-
if (
|
|
319
|
+
if (
|
|
320
|
+
typeof this.mail.html === 'object' &&
|
|
321
|
+
(this.mail.html.content || this.mail.html.path || this.mail.html.href || this.mail.html.raw)
|
|
322
|
+
) {
|
|
271
323
|
html = this.mail.html;
|
|
272
324
|
} else {
|
|
273
325
|
html = {
|
|
@@ -285,14 +337,14 @@ class MailComposer {
|
|
|
285
337
|
.concat(eventObject || [])
|
|
286
338
|
.concat(this.mail.alternatives || [])
|
|
287
339
|
.forEach(alternative => {
|
|
288
|
-
let data;
|
|
289
|
-
|
|
290
340
|
if (/^data:/i.test(alternative.path || alternative.href)) {
|
|
291
341
|
alternative = this._processDataUrl(alternative);
|
|
292
342
|
}
|
|
293
343
|
|
|
294
|
-
data = {
|
|
295
|
-
contentType:
|
|
344
|
+
const data = {
|
|
345
|
+
contentType:
|
|
346
|
+
alternative.contentType ||
|
|
347
|
+
mimeFuncs.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
|
|
296
348
|
contentTransferEncoding: alternative.contentTransferEncoding
|
|
297
349
|
};
|
|
298
350
|
|
|
@@ -341,26 +393,22 @@ class MailComposer {
|
|
|
341
393
|
* @returns {Object} MimeNode node element
|
|
342
394
|
*/
|
|
343
395
|
_createMixed(parentNode) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
361
|
-
newline: this.mail.newline
|
|
362
|
-
});
|
|
363
|
-
}
|
|
396
|
+
const node = parentNode
|
|
397
|
+
? parentNode.createChild('multipart/mixed', {
|
|
398
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
399
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
400
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
401
|
+
newline: this.mail.newline
|
|
402
|
+
})
|
|
403
|
+
: new MimeNode('multipart/mixed', {
|
|
404
|
+
baseBoundary: this.mail.baseBoundary,
|
|
405
|
+
textEncoding: this.mail.textEncoding,
|
|
406
|
+
boundaryPrefix: this.mail.boundaryPrefix,
|
|
407
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
408
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
409
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
410
|
+
newline: this.mail.newline
|
|
411
|
+
});
|
|
364
412
|
|
|
365
413
|
if (this._useAlternative) {
|
|
366
414
|
this._createAlternative(node);
|
|
@@ -389,26 +437,22 @@ class MailComposer {
|
|
|
389
437
|
* @returns {Object} MimeNode node element
|
|
390
438
|
*/
|
|
391
439
|
_createAlternative(parentNode) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
409
|
-
newline: this.mail.newline
|
|
410
|
-
});
|
|
411
|
-
}
|
|
440
|
+
const node = parentNode
|
|
441
|
+
? parentNode.createChild('multipart/alternative', {
|
|
442
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
443
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
444
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
445
|
+
newline: this.mail.newline
|
|
446
|
+
})
|
|
447
|
+
: new MimeNode('multipart/alternative', {
|
|
448
|
+
baseBoundary: this.mail.baseBoundary,
|
|
449
|
+
textEncoding: this.mail.textEncoding,
|
|
450
|
+
boundaryPrefix: this.mail.boundaryPrefix,
|
|
451
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
452
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
453
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
454
|
+
newline: this.mail.newline
|
|
455
|
+
});
|
|
412
456
|
|
|
413
457
|
this._alternatives.forEach(alternative => {
|
|
414
458
|
if (this._useRelated && this._htmlNode === alternative) {
|
|
@@ -428,26 +472,22 @@ class MailComposer {
|
|
|
428
472
|
* @returns {Object} MimeNode node element
|
|
429
473
|
*/
|
|
430
474
|
_createRelated(parentNode) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
448
|
-
newline: this.mail.newline
|
|
449
|
-
});
|
|
450
|
-
}
|
|
475
|
+
const node = parentNode
|
|
476
|
+
? parentNode.createChild('multipart/related; type="text/html"', {
|
|
477
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
478
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
479
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
480
|
+
newline: this.mail.newline
|
|
481
|
+
})
|
|
482
|
+
: new MimeNode('multipart/related; type="text/html"', {
|
|
483
|
+
baseBoundary: this.mail.baseBoundary,
|
|
484
|
+
textEncoding: this.mail.textEncoding,
|
|
485
|
+
boundaryPrefix: this.mail.boundaryPrefix,
|
|
486
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
487
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
488
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
489
|
+
newline: this.mail.newline
|
|
490
|
+
});
|
|
451
491
|
|
|
452
492
|
this._createContentNode(node, this._htmlNode);
|
|
453
493
|
|
|
@@ -467,33 +507,30 @@ class MailComposer {
|
|
|
467
507
|
element = element || {};
|
|
468
508
|
element.content = element.content || '';
|
|
469
509
|
|
|
470
|
-
|
|
471
|
-
let encoding = (element.encoding || 'utf8')
|
|
510
|
+
const encoding = (element.encoding || 'utf8')
|
|
472
511
|
.toString()
|
|
473
512
|
.toLowerCase()
|
|
474
513
|
.replace(/[-_\s]/g, '');
|
|
475
514
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
});
|
|
496
|
-
}
|
|
515
|
+
const node = parentNode
|
|
516
|
+
? parentNode.createChild(element.contentType, {
|
|
517
|
+
filename: element.filename,
|
|
518
|
+
textEncoding: this.mail.textEncoding,
|
|
519
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
520
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
521
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
522
|
+
newline: this.mail.newline
|
|
523
|
+
})
|
|
524
|
+
: new MimeNode(element.contentType, {
|
|
525
|
+
filename: element.filename,
|
|
526
|
+
baseBoundary: this.mail.baseBoundary,
|
|
527
|
+
textEncoding: this.mail.textEncoding,
|
|
528
|
+
boundaryPrefix: this.mail.boundaryPrefix,
|
|
529
|
+
disableUrlAccess: this.mail.disableUrlAccess,
|
|
530
|
+
disableFileAccess: this.mail.disableFileAccess,
|
|
531
|
+
normalizeHeaderKey: this.mail.normalizeHeaderKey,
|
|
532
|
+
newline: this.mail.newline
|
|
533
|
+
});
|
|
497
534
|
|
|
498
535
|
// add custom headers
|
|
499
536
|
if (element.headers) {
|
|
@@ -538,9 +575,46 @@ class MailComposer {
|
|
|
538
575
|
* @return {Object} Parsed element
|
|
539
576
|
*/
|
|
540
577
|
_processDataUrl(element) {
|
|
578
|
+
const dataUrl = element.path || element.href;
|
|
579
|
+
|
|
580
|
+
// Early validation to prevent ReDoS
|
|
581
|
+
if (!dataUrl || typeof dataUrl !== 'string') {
|
|
582
|
+
return element;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (!dataUrl.startsWith('data:')) {
|
|
586
|
+
return element;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (dataUrl.length > 52428800) {
|
|
590
|
+
// 52428800 chars = 50MB limit for data URL string (~37.5MB decoded image)
|
|
591
|
+
// Extract content type before rejecting to preserve MIME type
|
|
592
|
+
let detectedType = 'application/octet-stream';
|
|
593
|
+
const commaPos = dataUrl.indexOf(',');
|
|
594
|
+
|
|
595
|
+
if (commaPos > 0 && commaPos < 200) {
|
|
596
|
+
// Parse header safely with size limit
|
|
597
|
+
const header = dataUrl.substring(5, commaPos); // skip 'data:'
|
|
598
|
+
const parts = header.split(';');
|
|
599
|
+
if (parts[0] && parts[0].includes('/')) {
|
|
600
|
+
detectedType = parts[0].trim();
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Return empty content for excessively long data URLs
|
|
605
|
+
return Object.assign(copyOwnKeys({}, element), {
|
|
606
|
+
path: false,
|
|
607
|
+
href: false,
|
|
608
|
+
content: Buffer.alloc(0),
|
|
609
|
+
contentType: element.contentType || detectedType
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
|
|
541
613
|
let parsedDataUri;
|
|
542
|
-
|
|
543
|
-
parsedDataUri = parseDataURI(
|
|
614
|
+
try {
|
|
615
|
+
parsedDataUri = parseDataURI(dataUrl);
|
|
616
|
+
} catch (_err) {
|
|
617
|
+
return element;
|
|
544
618
|
}
|
|
545
619
|
|
|
546
620
|
if (!parsedDataUri) {
|