@nocobase/plugin-notifications 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 (181) hide show
  1. package/dist/externalVersion.js +3 -3
  2. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +59 -0
  3. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.js +790 -0
  4. package/dist/node_modules/nodemailer/dist/cjs/base64/index.d.ts +36 -0
  5. package/dist/node_modules/nodemailer/dist/cjs/base64/index.js +119 -0
  6. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +52 -0
  7. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.js +228 -0
  8. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +48 -0
  9. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +180 -0
  10. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +36 -0
  11. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.js +148 -0
  12. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +52 -0
  13. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.js +165 -0
  14. package/dist/node_modules/nodemailer/dist/cjs/errors.d.ts +96 -0
  15. package/dist/node_modules/nodemailer/dist/cjs/errors.js +70 -0
  16. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +107 -0
  17. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.js +282 -0
  18. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +65 -0
  19. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.js +384 -0
  20. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +64 -0
  21. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.js +99 -0
  22. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +174 -0
  23. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.js +613 -0
  24. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +237 -0
  25. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.js +415 -0
  26. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +97 -0
  27. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +342 -0
  28. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +161 -0
  29. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +787 -0
  30. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.d.ts +2 -0
  31. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +2103 -0
  32. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +333 -0
  33. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.js +1493 -0
  34. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.d.ts +5 -0
  35. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.js +32 -0
  36. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.d.ts +9 -0
  37. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.js +40 -0
  38. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.d.ts +10 -0
  39. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.js +47 -0
  40. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +124 -0
  41. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
  42. package/dist/node_modules/nodemailer/dist/cjs/package-info.d.ts +3 -0
  43. package/dist/node_modules/nodemailer/dist/cjs/package-info.js +7 -0
  44. package/dist/node_modules/nodemailer/dist/cjs/package.json +3 -0
  45. package/dist/node_modules/nodemailer/dist/cjs/punycode/index.d.ts +73 -0
  46. package/dist/node_modules/nodemailer/dist/cjs/punycode/index.js +411 -0
  47. package/dist/node_modules/nodemailer/dist/cjs/qp/index.d.ts +32 -0
  48. package/dist/node_modules/nodemailer/dist/cjs/qp/index.js +207 -0
  49. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +69 -0
  50. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +210 -0
  51. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +112 -0
  52. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.js +252 -0
  53. package/dist/node_modules/nodemailer/dist/cjs/shared/index.d.ts +260 -0
  54. package/dist/node_modules/nodemailer/dist/cjs/shared/index.js +680 -0
  55. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.d.ts +23 -0
  56. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.js +43 -0
  57. package/dist/node_modules/nodemailer/dist/cjs/shared/url.d.ts +21 -0
  58. package/dist/node_modules/nodemailer/dist/cjs/shared/url.js +255 -0
  59. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +15 -0
  60. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +108 -0
  61. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +47 -0
  62. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +189 -0
  63. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +416 -0
  64. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +1837 -0
  65. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +133 -0
  66. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +569 -0
  67. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.d.ts +62 -0
  68. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +257 -0
  69. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +156 -0
  70. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +371 -0
  71. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +65 -0
  72. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.js +146 -0
  73. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.d.ts +35 -0
  74. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.js +41 -0
  75. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.d.ts +2 -0
  76. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.js +674 -0
  77. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +201 -0
  78. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.js +426 -0
  79. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +59 -0
  80. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.js +786 -0
  81. package/dist/node_modules/nodemailer/dist/esm/base64/index.d.ts +36 -0
  82. package/dist/node_modules/nodemailer/{lib → dist/esm}/base64/index.js +39 -68
  83. package/dist/node_modules/nodemailer/dist/esm/dkim/index.d.ts +52 -0
  84. package/dist/node_modules/nodemailer/{lib → dist/esm}/dkim/index.js +62 -92
  85. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +48 -0
  86. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.js +176 -0
  87. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +36 -0
  88. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +141 -0
  89. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +52 -0
  90. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.js +125 -0
  91. package/dist/node_modules/nodemailer/dist/esm/errors.d.ts +96 -0
  92. package/dist/node_modules/nodemailer/dist/esm/errors.js +67 -0
  93. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +107 -0
  94. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.js +242 -0
  95. package/dist/node_modules/nodemailer/dist/esm/fetch/index.d.ts +65 -0
  96. package/dist/node_modules/nodemailer/dist/esm/fetch/index.js +344 -0
  97. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +64 -0
  98. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.js +62 -0
  99. package/dist/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +174 -0
  100. package/dist/node_modules/nodemailer/{lib → dist/esm}/mail-composer/index.js +288 -280
  101. package/dist/node_modules/nodemailer/dist/esm/mailer/index.d.ts +237 -0
  102. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/index.js +142 -194
  103. package/dist/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +97 -0
  104. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/mail-message.js +111 -125
  105. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +161 -0
  106. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.js +738 -0
  107. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.d.ts +2 -0
  108. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-funcs/mime-types.js +43 -49
  109. package/dist/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +333 -0
  110. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/index.js +584 -436
  111. package/dist/node_modules/nodemailer/dist/esm/mime-node/last-newline.d.ts +5 -0
  112. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/last-newline.js +4 -10
  113. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-unix.d.ts +9 -0
  114. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-unix.js +7 -15
  115. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-windows.d.ts +10 -0
  116. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-windows.js +6 -16
  117. package/dist/node_modules/nodemailer/dist/esm/nodemailer.d.ts +124 -0
  118. package/dist/node_modules/nodemailer/dist/esm/nodemailer.js +166 -0
  119. package/dist/node_modules/nodemailer/dist/esm/package-info.d.ts +3 -0
  120. package/dist/node_modules/nodemailer/dist/esm/package-info.js +4 -0
  121. package/dist/node_modules/nodemailer/dist/esm/package.json +3 -0
  122. package/dist/node_modules/nodemailer/dist/esm/punycode/index.d.ts +73 -0
  123. package/dist/node_modules/nodemailer/dist/esm/punycode/index.js +405 -0
  124. package/dist/node_modules/nodemailer/dist/esm/qp/index.d.ts +32 -0
  125. package/dist/node_modules/nodemailer/{lib → dist/esm}/qp/index.js +59 -77
  126. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +69 -0
  127. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +170 -0
  128. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +112 -0
  129. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.js +212 -0
  130. package/dist/node_modules/nodemailer/dist/esm/shared/index.d.ts +260 -0
  131. package/dist/node_modules/nodemailer/dist/esm/shared/index.js +631 -0
  132. package/dist/node_modules/nodemailer/dist/esm/shared/objects.d.ts +23 -0
  133. package/dist/node_modules/nodemailer/dist/esm/shared/objects.js +38 -0
  134. package/dist/node_modules/nodemailer/dist/esm/shared/url.d.ts +21 -0
  135. package/dist/node_modules/nodemailer/dist/esm/shared/url.js +214 -0
  136. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +15 -0
  137. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +103 -0
  138. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +47 -0
  139. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +149 -0
  140. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +416 -0
  141. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.js +1797 -0
  142. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +133 -0
  143. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/index.js +195 -314
  144. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.d.ts +62 -0
  145. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/pool-resource.js +70 -107
  146. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +156 -0
  147. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.js +331 -0
  148. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +65 -0
  149. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.js +106 -0
  150. package/dist/node_modules/nodemailer/dist/esm/well-known/index.d.ts +35 -0
  151. package/dist/node_modules/nodemailer/{lib → dist/esm}/well-known/index.js +12 -23
  152. package/dist/node_modules/nodemailer/dist/esm/well-known/services.d.ts +2 -0
  153. package/dist/node_modules/nodemailer/dist/esm/well-known/services.js +671 -0
  154. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +201 -0
  155. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.js +386 -0
  156. package/dist/node_modules/nodemailer/dist/well-known/services.json +640 -0
  157. package/dist/node_modules/nodemailer/package.json +1 -1
  158. package/dist/server/models/NotificationService.d.ts +1 -2
  159. package/package.json +3 -3
  160. package/dist/node_modules/nodemailer/.gitattributes +0 -6
  161. package/dist/node_modules/nodemailer/.ncurc.js +0 -7
  162. package/dist/node_modules/nodemailer/.prettierrc.js +0 -8
  163. package/dist/node_modules/nodemailer/lib/addressparser/index.js +0 -313
  164. package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  165. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  166. package/dist/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  167. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  168. package/dist/node_modules/nodemailer/lib/fetch/index.js +0 -274
  169. package/dist/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  170. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  171. package/dist/node_modules/nodemailer/lib/nodemailer.js +0 -1
  172. package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  173. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +0 -349
  174. package/dist/node_modules/nodemailer/lib/shared/index.js +0 -638
  175. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  176. package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  177. package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1812
  178. package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +0 -416
  179. package/dist/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  180. package/dist/node_modules/nodemailer/lib/well-known/services.json +0 -338
  181. package/dist/node_modules/nodemailer/lib/xoauth2/index.js +0 -376
@@ -1,22 +1,26 @@
1
1
  /* eslint no-undefined: 0 */
2
-
3
- 'use strict';
4
-
5
- const MimeNode = require('../mime-node');
6
- const mimeFuncs = require('../mime-funcs');
7
-
2
+ import MimeNode from '../mime-node/index.js';
3
+ import * as mimeFuncs from '../mime-funcs/index.js';
4
+ import { parseDataURI, copyOwnKeys } from '../shared/index.js';
8
5
  /**
9
6
  * Creates the object for composing a MimeNode instance out from the mail options
10
7
  *
11
8
  * @constructor
12
- * @param {Object} mail Mail options
9
+ * @param mail Mail options
13
10
  */
11
+ /**
12
+ * Tells whether a content value is a content descriptor object (something to load or to
13
+ * use as is) rather than the content itself
14
+ */
15
+ function isContentObject(value) {
16
+ const content = value;
17
+ return typeof value === 'object' && !!(content.content || content.path || content.href || content.raw);
18
+ }
14
19
  class MailComposer {
15
20
  constructor(mail) {
16
21
  this.mail = mail || {};
17
22
  this.message = false;
18
23
  }
19
-
20
24
  /**
21
25
  * Builds MimeNode instance
22
26
  */
@@ -24,144 +28,134 @@ class MailComposer {
24
28
  this._alternatives = this.getAlternatives();
25
29
  this._htmlNode = this._alternatives.filter(alternative => /^text\/html\b/i.test(alternative.contentType)).pop();
26
30
  this._attachments = this.getAttachments(!!this._htmlNode);
27
-
28
31
  this._useRelated = !!(this._htmlNode && this._attachments.related.length);
29
32
  this._useAlternative = this._alternatives.length > 1;
30
33
  this._useMixed = this._attachments.attached.length > 1 || (this._alternatives.length && this._attachments.attached.length === 1);
31
-
32
34
  // Compose MIME tree
33
35
  if (this.mail.raw) {
34
- this.message = new MimeNode('message/rfc822', { newline: this.mail.newline }).setRaw(this.mail.raw);
35
- } else if (this._useMixed) {
36
+ this.message = new MimeNode('message/rfc822', {
37
+ newline: this.mail.newline,
38
+ disableUrlAccess: this.mail.disableUrlAccess,
39
+ disableFileAccess: this.mail.disableFileAccess
40
+ }).setRaw(this.mail.raw);
41
+ }
42
+ else if (this._useMixed) {
36
43
  this.message = this._createMixed();
37
- } else if (this._useAlternative) {
44
+ }
45
+ else if (this._useAlternative) {
38
46
  this.message = this._createAlternative();
39
- } else if (this._useRelated) {
47
+ }
48
+ else if (this._useRelated) {
40
49
  this.message = this._createRelated();
41
- } else {
42
- this.message = this._createContentNode(
43
- false,
44
- []
45
- .concat(this._alternatives || [])
46
- .concat(this._attachments.attached || [])
47
- .shift() || {
48
- contentType: 'text/plain',
49
- content: ''
50
- }
51
- );
52
50
  }
53
-
51
+ else {
52
+ this.message = this._createContentNode(false, []
53
+ .concat(this._alternatives || [])
54
+ .concat(this._attachments.attached || [])
55
+ .shift() || {
56
+ contentType: 'text/plain',
57
+ content: ''
58
+ });
59
+ }
54
60
  // Add custom headers
55
61
  if (this.mail.headers) {
56
62
  this.message.addHeader(this.mail.headers);
57
63
  }
58
-
59
64
  // Add headers to the root node, always overrides custom headers
60
65
  ['from', 'sender', 'to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'message-id', 'date'].forEach(header => {
61
- let key = header.replace(/-(\w)/g, (o, c) => c.toUpperCase());
66
+ const key = header.replace(/-(\w)/g, (o, c) => c.toUpperCase());
62
67
  if (this.mail[key]) {
63
68
  this.message.setHeader(header, this.mail[key]);
64
69
  }
65
70
  });
66
-
67
71
  // Sets custom envelope
68
72
  if (this.mail.envelope) {
69
73
  this.message.setEnvelope(this.mail.envelope);
70
74
  }
71
-
72
75
  // ensure Message-Id value
73
76
  this.message.messageId();
74
-
75
77
  return this.message;
76
78
  }
77
-
78
79
  /**
79
80
  * List all attachments. Resulting attachment objects can be used as input for MimeNode nodes
80
81
  *
81
- * @param {Boolean} findRelated If true separate related attachments from attached ones
82
- * @returns {Object} An object of arrays (`related` and `attached`)
82
+ * @param findRelated If true separate related attachments from attached ones
83
+ * @returns An object of arrays (`related` and `attached`)
83
84
  */
84
85
  getAttachments(findRelated) {
85
- let icalEvent, eventObject;
86
- let attachments = [].concat(this.mail.attachments || []).map((attachment, i) => {
87
- let data;
88
- let isMessageNode = /^message\//i.test(attachment.contentType);
89
-
90
- if (/^data:/i.test(attachment.path || attachment.href)) {
86
+ let eventObject;
87
+ const attachments = [].concat(this.mail.attachments || []).map((attachment, i) => {
88
+ if (/^data:/i.test((attachment.path || attachment.href))) {
91
89
  attachment = this._processDataUrl(attachment);
92
90
  }
93
-
94
- let contentType = attachment.contentType || mimeFuncs.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin');
95
- let isImage = /^image\//i.test(contentType);
96
- let contentDisposition = attachment.contentDisposition || (isMessageNode || (isImage && attachment.cid) ? 'inline' : 'attachment');
97
-
98
- data = {
91
+ const contentType = attachment.contentType || mimeFuncs.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin');
92
+ const isImage = /^image\//i.test(contentType);
93
+ const isMessageNode = /^message\//i.test(contentType);
94
+ const contentDisposition = attachment.contentDisposition || (isMessageNode || (isImage && attachment.cid) ? 'inline' : 'attachment');
95
+ let contentTransferEncoding;
96
+ if ('contentTransferEncoding' in attachment) {
97
+ // also contains `false`, to set
98
+ contentTransferEncoding = attachment.contentTransferEncoding;
99
+ }
100
+ else if (isMessageNode) {
101
+ // the content might include non-ASCII bytes but at this point we do not know it yet
102
+ contentTransferEncoding = '8bit';
103
+ }
104
+ else {
105
+ contentTransferEncoding = 'base64'; // the default
106
+ }
107
+ const data = {
99
108
  contentType,
100
109
  contentDisposition,
101
- contentTransferEncoding: 'contentTransferEncoding' in attachment ? attachment.contentTransferEncoding : 'base64'
110
+ contentTransferEncoding
102
111
  };
103
-
104
112
  if (attachment.filename) {
105
113
  data.filename = attachment.filename;
106
- } else if (!isMessageNode && attachment.filename !== false) {
107
- data.filename = (attachment.path || attachment.href || '').split('/').pop().split('?').shift() || 'attachment-' + (i + 1);
114
+ }
115
+ else if (!isMessageNode && attachment.filename !== false) {
116
+ // a backslash separates as well, so a Windows path does not put the sender's directories in the headers
117
+ data.filename =
118
+ (attachment.path || attachment.href || '').split(/[/\\]/).pop().split('?').shift() ||
119
+ 'attachment-' + (i + 1);
108
120
  if (data.filename.indexOf('.') < 0) {
109
121
  data.filename += '.' + mimeFuncs.detectExtension(data.contentType);
110
122
  }
111
123
  }
112
-
113
124
  if (/^https?:\/\//i.test(attachment.path)) {
114
125
  attachment.href = attachment.path;
115
126
  attachment.path = undefined;
116
127
  }
117
-
118
128
  if (attachment.cid) {
119
129
  data.cid = attachment.cid;
120
130
  }
121
-
122
131
  if (attachment.raw) {
123
132
  data.raw = attachment.raw;
124
- } else if (attachment.path) {
133
+ }
134
+ else if (attachment.path) {
125
135
  data.content = {
126
136
  path: attachment.path
127
137
  };
128
- } else if (attachment.href) {
138
+ }
139
+ else if (attachment.href) {
129
140
  data.content = {
130
141
  href: attachment.href,
131
- httpHeaders: attachment.httpHeaders
142
+ httpHeaders: attachment.httpHeaders,
143
+ tls: attachment.tls
132
144
  };
133
- } else {
145
+ }
146
+ else {
134
147
  data.content = attachment.content || '';
135
148
  }
136
-
137
149
  if (attachment.encoding) {
138
150
  data.encoding = attachment.encoding;
139
151
  }
140
-
141
152
  if (attachment.headers) {
142
153
  data.headers = attachment.headers;
143
154
  }
144
-
145
155
  return data;
146
156
  });
147
-
148
157
  if (this.mail.icalEvent) {
149
- if (
150
- typeof this.mail.icalEvent === 'object' &&
151
- (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
152
- ) {
153
- icalEvent = this.mail.icalEvent;
154
- } else {
155
- icalEvent = {
156
- content: this.mail.icalEvent
157
- };
158
- }
159
-
160
- eventObject = {};
161
- Object.keys(icalEvent).forEach(key => {
162
- eventObject[key] = icalEvent[key];
163
- });
164
-
158
+ eventObject = Object.assign({}, this._getIcalEvent());
165
159
  eventObject.contentType = 'application/ics';
166
160
  if (!eventObject.headers) {
167
161
  eventObject.headers = {};
@@ -170,112 +164,136 @@ class MailComposer {
170
164
  eventObject.headers['Content-Disposition'] = 'attachment';
171
165
  eventObject.headers['Content-Transfer-Encoding'] = 'base64';
172
166
  }
173
-
174
167
  if (!findRelated) {
175
168
  return {
176
169
  attached: attachments.concat(eventObject || []),
177
170
  related: []
178
171
  };
179
- } else {
180
- return {
181
- attached: attachments.filter(attachment => !attachment.cid).concat(eventObject || []),
182
- related: attachments.filter(attachment => !!attachment.cid)
183
- };
184
172
  }
173
+ return {
174
+ attached: attachments.filter(attachment => !attachment.cid).concat(eventObject || []),
175
+ related: attachments.filter(attachment => !!attachment.cid)
176
+ };
177
+ }
178
+ /**
179
+ * Returns the icalEvent value with `path`/`href`/data uri input normalized into
180
+ * a `content` entry, the same way as for regular attachments. The same event is
181
+ * included twice (as a text/calendar alternative and as an application/ics
182
+ * attachment), so the shared content object is marked to be resolved just once
183
+ * and the buffered result is reused by the second node.
184
+ *
185
+ * @returns Normalized icalEvent data
186
+ * @internal
187
+ */
188
+ _getIcalEvent() {
189
+ if (!this._icalEvent) {
190
+ let icalEvent;
191
+ if (isContentObject(this.mail.icalEvent)) {
192
+ // an own "__proto__" key would make the copy inherit path/href from caller
193
+ // data, and the mapping below then replaces the content the caller did set
194
+ icalEvent = copyOwnKeys({}, this.mail.icalEvent);
195
+ }
196
+ else {
197
+ icalEvent = {
198
+ content: this.mail.icalEvent
199
+ };
200
+ }
201
+ if (/^data:/i.test((icalEvent.path || icalEvent.href))) {
202
+ icalEvent = this._processDataUrl(icalEvent);
203
+ }
204
+ if (/^https?:\/\//i.test(icalEvent.path)) {
205
+ icalEvent.href = icalEvent.path;
206
+ icalEvent.path = undefined;
207
+ }
208
+ if (!icalEvent.raw) {
209
+ // map file path and URL values into `content`, otherwise the content
210
+ // nodes would render an empty body
211
+ if (icalEvent.path) {
212
+ icalEvent.content = {
213
+ path: icalEvent.path
214
+ };
215
+ icalEvent.path = undefined;
216
+ }
217
+ else if (icalEvent.href) {
218
+ icalEvent.content = {
219
+ href: icalEvent.href,
220
+ httpHeaders: icalEvent.httpHeaders,
221
+ tls: icalEvent.tls
222
+ };
223
+ icalEvent.href = undefined;
224
+ }
225
+ }
226
+ if (icalEvent.content && typeof icalEvent.content === 'object') {
227
+ // we are going to have the same attachment twice, so mark this to be
228
+ // resolved just once
229
+ icalEvent.content._resolve = true;
230
+ }
231
+ this._icalEvent = icalEvent;
232
+ }
233
+ return this._icalEvent;
185
234
  }
186
-
187
235
  /**
188
236
  * List alternatives. Resulting objects can be used as input for MimeNode nodes
189
237
  *
190
- * @returns {Array} An array of alternative elements. Includes the `text` and `html` values as well
238
+ * @returns An array of alternative elements. Includes the `text` and `html` values as well
191
239
  */
192
240
  getAlternatives() {
193
- let alternatives = [],
194
- text,
195
- html,
196
- watchHtml,
197
- amp,
198
- icalEvent,
199
- eventObject;
200
-
241
+ const alternatives = [];
242
+ let text, html, watchHtml, amp, eventObject;
201
243
  if (this.mail.text) {
202
- if (typeof this.mail.text === 'object' && (this.mail.text.content || this.mail.text.path || this.mail.text.href || this.mail.text.raw)) {
244
+ if (isContentObject(this.mail.text)) {
203
245
  text = this.mail.text;
204
- } else {
246
+ }
247
+ else {
205
248
  text = {
206
249
  content: this.mail.text
207
250
  };
208
251
  }
209
252
  text.contentType = 'text/plain; charset=utf-8';
210
253
  }
211
-
212
254
  if (this.mail.watchHtml) {
213
- if (
214
- typeof this.mail.watchHtml === 'object' &&
215
- (this.mail.watchHtml.content || this.mail.watchHtml.path || this.mail.watchHtml.href || this.mail.watchHtml.raw)
216
- ) {
255
+ if (isContentObject(this.mail.watchHtml)) {
217
256
  watchHtml = this.mail.watchHtml;
218
- } else {
257
+ }
258
+ else {
219
259
  watchHtml = {
220
260
  content: this.mail.watchHtml
221
261
  };
222
262
  }
223
263
  watchHtml.contentType = 'text/watch-html; charset=utf-8';
224
264
  }
225
-
226
265
  if (this.mail.amp) {
227
- if (typeof this.mail.amp === 'object' && (this.mail.amp.content || this.mail.amp.path || this.mail.amp.href || this.mail.amp.raw)) {
266
+ if (isContentObject(this.mail.amp)) {
228
267
  amp = this.mail.amp;
229
- } else {
268
+ }
269
+ else {
230
270
  amp = {
231
271
  content: this.mail.amp
232
272
  };
233
273
  }
234
274
  amp.contentType = 'text/x-amp-html; charset=utf-8';
235
275
  }
236
-
237
276
  // NB! when including attachments with a calendar alternative you might end up in a blank screen on some clients
238
277
  if (this.mail.icalEvent) {
239
- if (
240
- typeof this.mail.icalEvent === 'object' &&
241
- (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
242
- ) {
243
- icalEvent = this.mail.icalEvent;
244
- } else {
245
- icalEvent = {
246
- content: this.mail.icalEvent
247
- };
248
- }
249
-
250
- eventObject = {};
251
- Object.keys(icalEvent).forEach(key => {
252
- eventObject[key] = icalEvent[key];
253
- });
254
-
255
- if (eventObject.content && typeof eventObject.content === 'object') {
256
- // we are going to have the same attachment twice, so mark this to be
257
- // resolved just once
258
- eventObject.content._resolve = true;
259
- }
260
-
278
+ eventObject = Object.assign({}, this._getIcalEvent());
261
279
  eventObject.filename = false;
262
- eventObject.contentType = 'text/calendar; charset=utf-8; method=' + (eventObject.method || 'PUBLISH').toString().trim().toUpperCase();
280
+ eventObject.contentType =
281
+ 'text/calendar; charset=utf-8; method=' + (eventObject.method || 'PUBLISH').toString().trim().toUpperCase();
263
282
  if (!eventObject.headers) {
264
283
  eventObject.headers = {};
265
284
  }
266
285
  }
267
-
268
286
  if (this.mail.html) {
269
- if (typeof this.mail.html === 'object' && (this.mail.html.content || this.mail.html.path || this.mail.html.href || this.mail.html.raw)) {
287
+ if (isContentObject(this.mail.html)) {
270
288
  html = this.mail.html;
271
- } else {
289
+ }
290
+ else {
272
291
  html = {
273
292
  content: this.mail.html
274
293
  };
275
294
  }
276
295
  html.contentType = 'text/html; charset=utf-8';
277
296
  }
278
-
279
297
  []
280
298
  .concat(text || [])
281
299
  .concat(watchHtml || [])
@@ -284,282 +302,272 @@ class MailComposer {
284
302
  .concat(eventObject || [])
285
303
  .concat(this.mail.alternatives || [])
286
304
  .forEach(alternative => {
287
- let data;
288
-
289
- if (/^data:/i.test(alternative.path || alternative.href)) {
290
- alternative = this._processDataUrl(alternative);
291
- }
292
-
293
- data = {
294
- contentType: alternative.contentType || mimeFuncs.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
295
- contentTransferEncoding: alternative.contentTransferEncoding
305
+ if (/^data:/i.test((alternative.path || alternative.href))) {
306
+ alternative = this._processDataUrl(alternative);
307
+ }
308
+ const data = {
309
+ contentType: alternative.contentType ||
310
+ mimeFuncs.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
311
+ contentTransferEncoding: alternative.contentTransferEncoding
312
+ };
313
+ if (alternative.filename) {
314
+ data.filename = alternative.filename;
315
+ }
316
+ if (/^https?:\/\//i.test(alternative.path)) {
317
+ alternative.href = alternative.path;
318
+ alternative.path = undefined;
319
+ }
320
+ if (alternative.raw) {
321
+ data.raw = alternative.raw;
322
+ }
323
+ else if (alternative.path) {
324
+ data.content = {
325
+ path: alternative.path
296
326
  };
297
-
298
- if (alternative.filename) {
299
- data.filename = alternative.filename;
300
- }
301
-
302
- if (/^https?:\/\//i.test(alternative.path)) {
303
- alternative.href = alternative.path;
304
- alternative.path = undefined;
305
- }
306
-
307
- if (alternative.raw) {
308
- data.raw = alternative.raw;
309
- } else if (alternative.path) {
310
- data.content = {
311
- path: alternative.path
312
- };
313
- } else if (alternative.href) {
314
- data.content = {
315
- href: alternative.href
316
- };
317
- } else {
318
- data.content = alternative.content || '';
319
- }
320
-
321
- if (alternative.encoding) {
322
- data.encoding = alternative.encoding;
323
- }
324
-
325
- if (alternative.headers) {
326
- data.headers = alternative.headers;
327
- }
328
-
329
- alternatives.push(data);
330
- });
331
-
327
+ }
328
+ else if (alternative.href) {
329
+ data.content = {
330
+ href: alternative.href,
331
+ httpHeaders: alternative.httpHeaders,
332
+ tls: alternative.tls
333
+ };
334
+ }
335
+ else {
336
+ data.content = alternative.content || '';
337
+ }
338
+ if (alternative.encoding) {
339
+ data.encoding = alternative.encoding;
340
+ }
341
+ if (alternative.headers) {
342
+ data.headers = alternative.headers;
343
+ }
344
+ alternatives.push(data);
345
+ });
332
346
  return alternatives;
333
347
  }
334
-
335
348
  /**
336
349
  * Builds multipart/mixed node. It should always contain different type of elements on the same level
337
350
  * eg. text + attachments
338
351
  *
339
- * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
340
- * @returns {Object} MimeNode node element
352
+ * @param parentNode Parent for this note. If it does not exist, a root node is created
353
+ * @returns MimeNode node element
354
+ * @internal
341
355
  */
342
356
  _createMixed(parentNode) {
343
- let node;
344
-
345
- if (!parentNode) {
346
- node = new MimeNode('multipart/mixed', {
347
- baseBoundary: this.mail.baseBoundary,
348
- textEncoding: this.mail.textEncoding,
349
- boundaryPrefix: this.mail.boundaryPrefix,
357
+ const node = parentNode
358
+ ? parentNode.createChild('multipart/mixed', {
350
359
  disableUrlAccess: this.mail.disableUrlAccess,
351
360
  disableFileAccess: this.mail.disableFileAccess,
352
361
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
353
362
  newline: this.mail.newline
354
- });
355
- } else {
356
- node = parentNode.createChild('multipart/mixed', {
363
+ })
364
+ : new MimeNode('multipart/mixed', {
365
+ baseBoundary: this.mail.baseBoundary,
366
+ textEncoding: this.mail.textEncoding,
367
+ boundaryPrefix: this.mail.boundaryPrefix,
357
368
  disableUrlAccess: this.mail.disableUrlAccess,
358
369
  disableFileAccess: this.mail.disableFileAccess,
359
370
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
360
371
  newline: this.mail.newline
361
372
  });
362
- }
363
-
364
373
  if (this._useAlternative) {
365
374
  this._createAlternative(node);
366
- } else if (this._useRelated) {
375
+ }
376
+ else if (this._useRelated) {
367
377
  this._createRelated(node);
368
378
  }
369
-
370
379
  []
371
380
  .concat((!this._useAlternative && this._alternatives) || [])
372
381
  .concat(this._attachments.attached || [])
373
382
  .forEach(element => {
374
- // if the element is a html node from related subpart then ignore it
375
- if (!this._useRelated || element !== this._htmlNode) {
376
- this._createContentNode(node, element);
377
- }
378
- });
379
-
383
+ // if the element is a html node from related subpart then ignore it
384
+ if (!this._useRelated || element !== this._htmlNode) {
385
+ this._createContentNode(node, element);
386
+ }
387
+ });
380
388
  return node;
381
389
  }
382
-
383
390
  /**
384
391
  * Builds multipart/alternative node. It should always contain same type of elements on the same level
385
392
  * eg. text + html view of the same data
386
393
  *
387
- * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
388
- * @returns {Object} MimeNode node element
394
+ * @param parentNode Parent for this note. If it does not exist, a root node is created
395
+ * @returns MimeNode node element
396
+ * @internal
389
397
  */
390
398
  _createAlternative(parentNode) {
391
- let node;
392
-
393
- if (!parentNode) {
394
- node = new MimeNode('multipart/alternative', {
395
- baseBoundary: this.mail.baseBoundary,
396
- textEncoding: this.mail.textEncoding,
397
- boundaryPrefix: this.mail.boundaryPrefix,
399
+ const node = parentNode
400
+ ? parentNode.createChild('multipart/alternative', {
398
401
  disableUrlAccess: this.mail.disableUrlAccess,
399
402
  disableFileAccess: this.mail.disableFileAccess,
400
403
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
401
404
  newline: this.mail.newline
402
- });
403
- } else {
404
- node = parentNode.createChild('multipart/alternative', {
405
+ })
406
+ : new MimeNode('multipart/alternative', {
407
+ baseBoundary: this.mail.baseBoundary,
408
+ textEncoding: this.mail.textEncoding,
409
+ boundaryPrefix: this.mail.boundaryPrefix,
405
410
  disableUrlAccess: this.mail.disableUrlAccess,
406
411
  disableFileAccess: this.mail.disableFileAccess,
407
412
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
408
413
  newline: this.mail.newline
409
414
  });
410
- }
411
-
412
415
  this._alternatives.forEach(alternative => {
413
416
  if (this._useRelated && this._htmlNode === alternative) {
414
417
  this._createRelated(node);
415
- } else {
418
+ }
419
+ else {
416
420
  this._createContentNode(node, alternative);
417
421
  }
418
422
  });
419
-
420
423
  return node;
421
424
  }
422
-
423
425
  /**
424
426
  * Builds multipart/related node. It should always contain html node with related attachments
425
427
  *
426
- * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
427
- * @returns {Object} MimeNode node element
428
+ * @param parentNode Parent for this note. If it does not exist, a root node is created
429
+ * @returns MimeNode node element
430
+ * @internal
428
431
  */
429
432
  _createRelated(parentNode) {
430
- let node;
431
-
432
- if (!parentNode) {
433
- node = new MimeNode('multipart/related; type="text/html"', {
434
- baseBoundary: this.mail.baseBoundary,
435
- textEncoding: this.mail.textEncoding,
436
- boundaryPrefix: this.mail.boundaryPrefix,
433
+ const node = parentNode
434
+ ? parentNode.createChild('multipart/related; type="text/html"', {
437
435
  disableUrlAccess: this.mail.disableUrlAccess,
438
436
  disableFileAccess: this.mail.disableFileAccess,
439
437
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
440
438
  newline: this.mail.newline
441
- });
442
- } else {
443
- node = parentNode.createChild('multipart/related; type="text/html"', {
439
+ })
440
+ : new MimeNode('multipart/related; type="text/html"', {
441
+ baseBoundary: this.mail.baseBoundary,
442
+ textEncoding: this.mail.textEncoding,
443
+ boundaryPrefix: this.mail.boundaryPrefix,
444
444
  disableUrlAccess: this.mail.disableUrlAccess,
445
445
  disableFileAccess: this.mail.disableFileAccess,
446
446
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
447
447
  newline: this.mail.newline
448
448
  });
449
- }
450
-
451
449
  this._createContentNode(node, this._htmlNode);
452
-
453
450
  this._attachments.related.forEach(alternative => this._createContentNode(node, alternative));
454
-
455
451
  return node;
456
452
  }
457
-
458
453
  /**
459
454
  * Creates a regular node with contents
460
455
  *
461
- * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
462
- * @param {Object} element Node data
463
- * @returns {Object} MimeNode node element
456
+ * @param parentNode Parent for this note. If it does not exist, a root node is created
457
+ * @param element Node data
458
+ * @returns MimeNode node element
459
+ * @internal
464
460
  */
465
461
  _createContentNode(parentNode, element) {
466
462
  element = element || {};
467
463
  element.content = element.content || '';
468
-
469
- let node;
470
- let encoding = (element.encoding || 'utf8')
464
+ const encoding = (element.encoding || 'utf8')
471
465
  .toString()
472
466
  .toLowerCase()
473
467
  .replace(/[-_\s]/g, '');
474
-
475
- if (!parentNode) {
476
- node = new MimeNode(element.contentType, {
468
+ const node = parentNode
469
+ ? parentNode.createChild(element.contentType, {
477
470
  filename: element.filename,
478
- baseBoundary: this.mail.baseBoundary,
479
471
  textEncoding: this.mail.textEncoding,
480
- boundaryPrefix: this.mail.boundaryPrefix,
481
472
  disableUrlAccess: this.mail.disableUrlAccess,
482
473
  disableFileAccess: this.mail.disableFileAccess,
483
474
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
484
475
  newline: this.mail.newline
485
- });
486
- } else {
487
- node = parentNode.createChild(element.contentType, {
476
+ })
477
+ : new MimeNode(element.contentType, {
488
478
  filename: element.filename,
479
+ baseBoundary: this.mail.baseBoundary,
489
480
  textEncoding: this.mail.textEncoding,
481
+ boundaryPrefix: this.mail.boundaryPrefix,
490
482
  disableUrlAccess: this.mail.disableUrlAccess,
491
483
  disableFileAccess: this.mail.disableFileAccess,
492
484
  normalizeHeaderKey: this.mail.normalizeHeaderKey,
493
485
  newline: this.mail.newline
494
486
  });
495
- }
496
-
497
487
  // add custom headers
498
488
  if (element.headers) {
499
489
  node.addHeader(element.headers);
500
490
  }
501
-
502
491
  if (element.cid) {
503
492
  node.setHeader('Content-Id', '<' + element.cid.replace(/[<>]/g, '') + '>');
504
493
  }
505
-
506
494
  if (element.contentTransferEncoding) {
507
495
  node.setHeader('Content-Transfer-Encoding', element.contentTransferEncoding);
508
- } else if (this.mail.encoding && /^text\//i.test(element.contentType)) {
496
+ }
497
+ else if (this.mail.encoding && /^text\//i.test(element.contentType)) {
509
498
  node.setHeader('Content-Transfer-Encoding', this.mail.encoding);
510
499
  }
511
-
512
500
  if (!/^text\//i.test(element.contentType) || element.contentDisposition) {
513
- node.setHeader(
514
- 'Content-Disposition',
515
- element.contentDisposition || (element.cid && /^image\//i.test(element.contentType) ? 'inline' : 'attachment')
516
- );
501
+ node.setHeader('Content-Disposition', element.contentDisposition || (element.cid && /^image\//i.test(element.contentType) ? 'inline' : 'attachment'));
517
502
  }
518
-
519
503
  if (typeof element.content === 'string' && !['utf8', 'usascii', 'ascii'].includes(encoding)) {
520
504
  element.content = Buffer.from(element.content, encoding);
521
505
  }
522
-
523
506
  // prefer pregenerated raw content
524
507
  if (element.raw) {
525
508
  node.setRaw(element.raw);
526
- } else {
509
+ }
510
+ else {
527
511
  node.setContent(element.content);
528
512
  }
529
-
530
513
  return node;
531
514
  }
532
-
533
515
  /**
534
516
  * Parses data uri and converts it to a Buffer
535
517
  *
536
- * @param {Object} element Content element
537
- * @return {Object} Parsed element
518
+ * @param element Content element
519
+ * @return Parsed element
520
+ * @internal
538
521
  */
539
522
  _processDataUrl(element) {
540
- let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
541
- if (!parts) {
523
+ const dataUrl = element.path || element.href;
524
+ // Early validation to prevent ReDoS
525
+ if (!dataUrl || typeof dataUrl !== 'string') {
526
+ return element;
527
+ }
528
+ if (!dataUrl.startsWith('data:')) {
529
+ return element;
530
+ }
531
+ if (dataUrl.length > 52428800) {
532
+ // 52428800 chars = 50MB limit for data URL string (~37.5MB decoded image)
533
+ // Extract content type before rejecting to preserve MIME type
534
+ let detectedType = 'application/octet-stream';
535
+ const commaPos = dataUrl.indexOf(',');
536
+ if (commaPos > 0 && commaPos < 200) {
537
+ // Parse header safely with size limit
538
+ const header = dataUrl.substring(5, commaPos); // skip 'data:'
539
+ const parts = header.split(';');
540
+ if (parts[0] && parts[0].includes('/')) {
541
+ detectedType = parts[0].trim();
542
+ }
543
+ }
544
+ // Return empty content for excessively long data URLs
545
+ return Object.assign(copyOwnKeys({}, element), {
546
+ path: false,
547
+ href: false,
548
+ content: Buffer.alloc(0),
549
+ contentType: element.contentType || detectedType
550
+ });
551
+ }
552
+ let parsedDataUri;
553
+ try {
554
+ parsedDataUri = parseDataURI(dataUrl);
555
+ }
556
+ catch (_err) {
542
557
  return element;
543
558
  }
544
-
545
- element.content = /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2]));
546
-
559
+ if (!parsedDataUri) {
560
+ return element;
561
+ }
562
+ element.content = parsedDataUri.data;
563
+ element.contentType = element.contentType || parsedDataUri.contentType;
547
564
  if ('path' in element) {
548
565
  element.path = false;
549
566
  }
550
-
551
567
  if ('href' in element) {
552
568
  element.href = false;
553
569
  }
554
-
555
- parts[1].split(';').forEach(item => {
556
- if (/^\w+\/[^/]+$/i.test(item)) {
557
- element.contentType = element.contentType || item.toLowerCase();
558
- }
559
- });
560
-
561
570
  return element;
562
571
  }
563
572
  }
564
-
565
- module.exports = MailComposer;
573
+ export default MailComposer;