@mavogel/awscdk-rootmail 0.1.8 → 0.1.10

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 (167) hide show
  1. package/.jsii +10 -10
  2. package/lib/rootmail.js +1 -1
  3. package/lib/ses-receive.js +1 -1
  4. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +5 -5
  5. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-es/schemas/schemas_0.js +4 -4
  6. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/DescribeDeliveryDestinationsCommand.d.ts +1 -0
  7. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/GetDeliveryDestinationCommand.d.ts +1 -0
  8. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutAccountPolicyCommand.d.ts +4 -1
  9. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/commands/PutDeliveryDestinationCommand.d.ts +2 -0
  10. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/models/models_0.d.ts +80 -36
  11. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/ts3.4/models/models_0.d.ts +2 -0
  12. package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +1 -1
  13. package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
  14. package/node_modules/@aws-sdk/client-route-53/package.json +1 -1
  15. package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +2 -1
  16. package/node_modules/@aws-sdk/client-s3/dist-es/models/enums.js +1 -0
  17. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetBucketInventoryConfigurationCommand.d.ts +1 -1
  18. package/node_modules/@aws-sdk/client-s3/dist-types/commands/ListBucketInventoryConfigurationsCommand.d.ts +1 -1
  19. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutBucketInventoryConfigurationCommand.d.ts +1 -1
  20. package/node_modules/@aws-sdk/client-s3/dist-types/models/enums.d.ts +1 -0
  21. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/enums.d.ts +1 -0
  22. package/node_modules/@aws-sdk/client-s3/package.json +2 -2
  23. package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
  24. package/node_modules/@aws-sdk/client-ses/package.json +1 -1
  25. package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +9 -3
  26. package/node_modules/@aws-sdk/client-ssm/dist-es/models/enums.js +4 -0
  27. package/node_modules/@aws-sdk/client-ssm/dist-es/schemas/schemas_0.js +3 -2
  28. package/node_modules/@aws-sdk/client-ssm/dist-types/commands/DeleteResourcePolicyCommand.d.ts +6 -0
  29. package/node_modules/@aws-sdk/client-ssm/dist-types/commands/PutResourcePolicyCommand.d.ts +12 -0
  30. package/node_modules/@aws-sdk/client-ssm/dist-types/models/enums.d.ts +12 -0
  31. package/node_modules/@aws-sdk/client-ssm/dist-types/models/models_0.d.ts +20 -1
  32. package/node_modules/@aws-sdk/client-ssm/dist-types/models/models_1.d.ts +2 -2
  33. package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/enums.d.ts +5 -0
  34. package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/models_0.d.ts +2 -0
  35. package/node_modules/@aws-sdk/client-ssm/package.json +1 -1
  36. package/node_modules/@zone-eu/mailsplit/lib/flowed-decoder.js +1 -5
  37. package/node_modules/@zone-eu/mailsplit/lib/headers.js +35 -25
  38. package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +126 -79
  39. package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +27 -5
  40. package/node_modules/@zone-eu/mailsplit/lib/node-rewriter.js +3 -2
  41. package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +0 -3
  42. package/node_modules/@zone-eu/mailsplit/package.json +5 -5
  43. package/node_modules/libbase64/.github/workflows/release.yaml +12 -10
  44. package/node_modules/libbase64/.ncurc.js +7 -1
  45. package/node_modules/libbase64/CHANGELOG.md +7 -0
  46. package/node_modules/libbase64/lib/libbase64.js +27 -0
  47. package/node_modules/libbase64/package.json +4 -4
  48. package/node_modules/libmime/CHANGELOG.md +14 -0
  49. package/node_modules/libmime/lib/libmime.js +41 -21
  50. package/node_modules/libmime/package.json +3 -3
  51. package/node_modules/libqp/.github/workflows/release.yaml +12 -10
  52. package/node_modules/libqp/CHANGELOG.md +7 -0
  53. package/node_modules/libqp/lib/libqp.js +6 -4
  54. package/node_modules/libqp/package.json +2 -2
  55. package/node_modules/libqp/test/libqp-test.js +71 -14
  56. package/node_modules/mailparser/.release-please-manifest.json +1 -1
  57. package/node_modules/mailparser/CHANGELOG.md +42 -0
  58. package/node_modules/mailparser/README.md +5 -0
  59. package/node_modules/mailparser/lib/mail-parser.js +107 -32
  60. package/node_modules/mailparser/lib/simple-parser.js +12 -0
  61. package/node_modules/mailparser/lib/stream-hash.js +1 -1
  62. package/node_modules/mailparser/package.json +6 -6
  63. package/node_modules/nodemailer/CHANGELOG.md +38 -0
  64. package/node_modules/nodemailer/README.md +1 -1
  65. package/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +16 -2
  66. package/node_modules/nodemailer/dist/cjs/addressparser/index.js +147 -28
  67. package/node_modules/nodemailer/dist/cjs/base64/index.js +2 -1
  68. package/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +13 -1
  69. package/node_modules/nodemailer/dist/cjs/dkim/index.js +25 -8
  70. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +10 -1
  71. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +28 -4
  72. package/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +10 -1
  73. package/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +3 -0
  74. package/node_modules/nodemailer/dist/cjs/dkim/sign.js +18 -1
  75. package/node_modules/nodemailer/dist/cjs/errors.d.ts +3 -2
  76. package/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +12 -1
  77. package/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +15 -1
  78. package/node_modules/nodemailer/dist/cjs/fetch/index.js +39 -64
  79. package/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +14 -4
  80. package/node_modules/nodemailer/dist/cjs/json-transport/index.js +2 -0
  81. package/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +8 -3
  82. package/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +43 -25
  83. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +11 -4
  84. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +7 -3
  85. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +198 -84
  86. package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +5 -2
  87. package/node_modules/nodemailer/dist/cjs/mime-node/index.js +2 -1
  88. package/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +38 -16
  89. package/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
  90. package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
  91. package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
  92. package/node_modules/nodemailer/dist/cjs/punycode/index.js +1 -0
  93. package/node_modules/nodemailer/dist/cjs/qp/index.d.ts +2 -0
  94. package/node_modules/nodemailer/dist/cjs/qp/index.js +10 -1
  95. package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +2 -0
  96. package/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +39 -2
  97. package/node_modules/nodemailer/dist/cjs/shared/index.d.ts +43 -7
  98. package/node_modules/nodemailer/dist/cjs/shared/index.js +5 -2
  99. package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +2 -1
  100. package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +32 -24
  101. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +13 -5
  102. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +23 -11
  103. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +59 -24
  104. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +156 -75
  105. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +12 -4
  106. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +39 -11
  107. package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +27 -31
  108. package/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +19 -6
  109. package/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +25 -33
  110. package/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +2 -0
  111. package/node_modules/nodemailer/dist/cjs/well-known/services.js +6 -0
  112. package/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +13 -3
  113. package/node_modules/nodemailer/dist/cjs/xoauth2/index.js +25 -13
  114. package/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +16 -2
  115. package/node_modules/nodemailer/dist/esm/addressparser/index.js +147 -27
  116. package/node_modules/nodemailer/dist/esm/base64/index.js +2 -1
  117. package/node_modules/nodemailer/dist/esm/dkim/index.d.ts +13 -1
  118. package/node_modules/nodemailer/dist/esm/dkim/index.js +25 -8
  119. package/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +10 -1
  120. package/node_modules/nodemailer/dist/esm/dkim/message-parser.js +30 -5
  121. package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +10 -1
  122. package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +2 -1
  123. package/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +3 -0
  124. package/node_modules/nodemailer/dist/esm/dkim/sign.js +18 -1
  125. package/node_modules/nodemailer/dist/esm/errors.d.ts +3 -2
  126. package/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +12 -1
  127. package/node_modules/nodemailer/dist/esm/fetch/cookies.js +2 -1
  128. package/node_modules/nodemailer/dist/esm/fetch/index.d.ts +15 -1
  129. package/node_modules/nodemailer/dist/esm/fetch/index.js +39 -64
  130. package/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +14 -4
  131. package/node_modules/nodemailer/dist/esm/json-transport/index.js +2 -0
  132. package/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +8 -3
  133. package/node_modules/nodemailer/dist/esm/mailer/index.d.ts +43 -25
  134. package/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +11 -4
  135. package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +7 -3
  136. package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +198 -84
  137. package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +5 -2
  138. package/node_modules/nodemailer/dist/esm/mime-node/index.js +2 -1
  139. package/node_modules/nodemailer/dist/esm/nodemailer.d.ts +38 -16
  140. package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
  141. package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
  142. package/node_modules/nodemailer/dist/esm/punycode/index.js +1 -0
  143. package/node_modules/nodemailer/dist/esm/qp/index.d.ts +2 -0
  144. package/node_modules/nodemailer/dist/esm/qp/index.js +10 -1
  145. package/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +2 -0
  146. package/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +39 -2
  147. package/node_modules/nodemailer/dist/esm/shared/index.d.ts +43 -7
  148. package/node_modules/nodemailer/dist/esm/shared/index.js +5 -2
  149. package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +2 -1
  150. package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +32 -24
  151. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +13 -5
  152. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +23 -11
  153. package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +59 -24
  154. package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +156 -75
  155. package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +12 -4
  156. package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +39 -11
  157. package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +27 -31
  158. package/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +19 -6
  159. package/node_modules/nodemailer/dist/esm/smtp-transport/index.js +25 -33
  160. package/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +2 -0
  161. package/node_modules/nodemailer/dist/esm/well-known/services.js +6 -0
  162. package/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +13 -3
  163. package/node_modules/nodemailer/dist/esm/xoauth2/index.js +25 -13
  164. package/node_modules/nodemailer/dist/well-known/services.json +7 -0
  165. package/node_modules/nodemailer/package.json +16 -12
  166. package/package.json +16 -16
  167. package/renovate.json5 +1 -0
@@ -34,6 +34,16 @@ const MAX_LINKIFY_SEGMENT_LENGTH = 4096;
34
34
  const MAX_LINKIFY_HOST_LABELS = 6;
35
35
  const MAX_LINKIFY_WORK = 768 * 1024 * 1024; // shared by all text parts of a message
36
36
 
37
+ // Default upper bound for the total length of the URLs updateImageLinks() writes
38
+ // into the HTML (options.maxInlinedImagesSize). simpleParser inlines every cid:
39
+ // reference as a full data: URL, so a small message repeating a reference to
40
+ // one image thousands of times would otherwise grow the HTML past the maximum
41
+ // string length. References beyond the budget are left as cid: links.
42
+ const MAX_INLINED_IMAGES_SIZE = 20 * 1024 * 1024;
43
+
44
+ // List-* header names that must not become keys of the plain list object
45
+ const UNSAFE_LIST_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
46
+
37
47
  linkify
38
48
  .tlds(tlds) // Reload with full tlds list
39
49
  .tlds('onion', true) // Add unofficial `.onion` domain
@@ -72,6 +82,31 @@ linkify.add('@', {
72
82
  }
73
83
  });
74
84
 
85
+ // Linear equivalent of /<[^<>]+@[^<>]+>/.test(str). The regex backtracks
86
+ // quadratically on a long run of @ characters after a lone <, and the input is a
87
+ // decoded encoded-word bounded only by the header size limit.
88
+ function hasBracketedAddress(str) {
89
+ let start = -1;
90
+ // first @ after the current < that has at least one character before it
91
+ let at = -1;
92
+ for (let i = 0, len = str.length; i < len; i++) {
93
+ let chr = str.charAt(i);
94
+ if (chr === '<') {
95
+ start = i;
96
+ at = -1;
97
+ } else if (chr === '>') {
98
+ if (start >= 0 && at >= 0 && at < i - 1) {
99
+ return true;
100
+ }
101
+ start = -1;
102
+ at = -1;
103
+ } else if (chr === '@' && start >= 0 && at < 0 && i > start + 1) {
104
+ at = i;
105
+ }
106
+ }
107
+ return false;
108
+ }
109
+
75
110
  class IconvDecoder extends Transform {
76
111
  constructor(Iconv, charset) {
77
112
  super();
@@ -185,8 +220,6 @@ class MailParser extends Transform {
185
220
 
186
221
  this.attachmentList = [];
187
222
 
188
- this.boundaries = [];
189
-
190
223
  this.textTypes = ['text/plain', 'text/html'].concat(!this.options.keepDeliveryStatus ? 'message/delivery-status' : []);
191
224
 
192
225
  this.decoder = this.getDecoder();
@@ -236,7 +269,7 @@ class MailParser extends Transform {
236
269
  decodeStream(charset) {
237
270
  // resolve charset aliases (eg. iso-8859-8-i -> ISO-8859-8) via libmime's canonical table
238
271
  charset = libmime.normalizeCharset((charset || 'ascii').toString());
239
- if (/^jis|^iso-?2022-?jp|^EUCJP/i.test(charset)) {
272
+ if (/^jis|^iso-?2022-?jp/i.test(charset)) {
240
273
  // special case not supported by iconv-lite
241
274
  return new JPDecoder(charset);
242
275
  }
@@ -302,7 +335,12 @@ class MailParser extends Transform {
302
335
  if (this.finished) {
303
336
  return this.cleanup(done);
304
337
  }
305
- this.waitingEnd = () => {
338
+ this.waitingEnd = err => {
339
+ // runs once, either on a splitter error after end of input or when the splitter ends
340
+ this.waitingEnd = false;
341
+ if (err) {
342
+ return done(err);
343
+ }
306
344
  this.cleanup(done);
307
345
  };
308
346
  }
@@ -479,6 +517,10 @@ class MailParser extends Transform {
479
517
  }
480
518
 
481
519
  parseListHeader(key, value) {
520
+ if (UNSAFE_LIST_KEYS.has(key)) {
521
+ // would replace the prototype of (or shadow) the normalized list object
522
+ return false;
523
+ }
482
524
  let addresses = addressparser(value);
483
525
  let response = {};
484
526
  let data = addresses
@@ -563,7 +605,7 @@ class MailParser extends Transform {
563
605
  // must not be re-interpreted as an address -- RFC 2047 Section 5 prohibits
564
606
  // encoded-words in addr-spec, and re-parsing fabricates addresses not present
565
607
  // in the original header.
566
- if (/<[^<>]+@[^<>]+>/.test(decoded)) {
608
+ if (hasBracketedAddress(decoded)) {
567
609
  let parsed = addressparser(decoded);
568
610
  if (parsed.length) {
569
611
  parsed.forEach(entry => {
@@ -852,7 +894,8 @@ class MailParser extends Transform {
852
894
  processChunk(data, done) {
853
895
  let partId = null;
854
896
  if (data._parentBoundary) {
855
- partId = this._getPartId(data._parentBoundary);
897
+ // mailsplit numbers parts IMAP style from the actual tree, TEXT markers are not part of the id
898
+ partId = (data.partNr || []).filter(nr => typeof nr === 'number').join('.') || null;
856
899
  }
857
900
  switch (data.type) {
858
901
  case 'node': {
@@ -884,6 +927,11 @@ class MailParser extends Transform {
884
927
  contentType = this.libmime.detectMimeType(data.filename) || 'application/octet-stream';
885
928
  }
886
929
 
930
+ // backpressure state for the attachment stream, see pump() below
931
+ let released = false;
932
+ let waitingDrain = false;
933
+ let pump = null;
934
+
887
935
  let attachment = {
888
936
  type: 'attachment',
889
937
  content: null,
@@ -891,6 +939,11 @@ class MailParser extends Transform {
891
939
  partId,
892
940
  release: () => {
893
941
  attachment.release = null;
942
+ released = true;
943
+ if (waitingDrain) {
944
+ waitingDrain = false;
945
+ pump();
946
+ }
894
947
  if (this.waitUntilAttachmentEnd && typeof this.attachmentCallback === 'function') {
895
948
  setImmediate(this.attachmentCallback);
896
949
  }
@@ -900,16 +953,38 @@ class MailParser extends Transform {
900
953
  };
901
954
 
902
955
  let algo = this.options.checksumAlgo || 'md5';
903
- let hasher = new StreamHash(attachment, algo);
956
+ let hasher;
957
+ try {
958
+ hasher = new StreamHash(attachment, algo);
959
+ } catch (err) {
960
+ // an algorithm this Node does not offer (a typo, or MD5 on a host whose
961
+ // OpenSSL runs in FIPS mode) is a parser error, not a process-ending throw
962
+ err.message = `Checksum algorithm "${algo}" is not available: ${err.message}`;
963
+ return done(err);
964
+ }
904
965
  node.decoder.on('error', err => {
905
966
  hasher.emit('error', err);
906
967
  });
907
968
 
908
- node.decoder.on('readable', () => {
969
+ // Honour the consumer's backpressure while it reads the attachment. Once the
970
+ // attachment is released it is drained regardless, so that a caller that
971
+ // releases without reading the content does not stall the parser.
972
+ pump = () => {
909
973
  let chunk;
910
-
911
974
  while ((chunk = node.decoder.read()) !== null) {
912
- hasher.write(chunk);
975
+ if (hasher.write(chunk) === false && !released) {
976
+ waitingDrain = true;
977
+ return hasher.once('drain', () => {
978
+ waitingDrain = false;
979
+ pump();
980
+ });
981
+ }
982
+ }
983
+ };
984
+
985
+ node.decoder.on('readable', () => {
986
+ if (!waitingDrain) {
987
+ pump();
913
988
  }
914
989
  });
915
990
 
@@ -1041,22 +1116,6 @@ class MailParser extends Transform {
1041
1116
  setImmediate(done);
1042
1117
  }
1043
1118
 
1044
- _getPartId(parentBoundary) {
1045
- let boundaryIndex = this.boundaries.findIndex(item => item.name === parentBoundary);
1046
- if (boundaryIndex === -1) {
1047
- this.boundaries.push({ name: parentBoundary, count: 1 });
1048
- boundaryIndex = this.boundaries.length - 1;
1049
- } else {
1050
- this.boundaries[boundaryIndex].count++;
1051
- }
1052
- let partId = '1';
1053
- for (let i = 0; i <= boundaryIndex; i++) {
1054
- if (i === 0) partId = this.boundaries[i].count.toString();
1055
- else partId += '.' + this.boundaries[i].count.toString();
1056
- }
1057
- return partId;
1058
- }
1059
-
1060
1119
  getAddressesHTML(value) {
1061
1120
  let formatSingleLevel = addresses =>
1062
1121
  addresses
@@ -1139,12 +1198,28 @@ class MailParser extends Transform {
1139
1198
  let pos = 0;
1140
1199
  let processNext = () => {
1141
1200
  if (pos >= cidList.length) {
1142
- html = html.replace(/\bcid:([^'"\s]{1,256})/g, (match, cid) => {
1143
- if (cids.has(cid) && cids.get(cid).url) {
1144
- return cids.get(cid).url;
1145
- }
1146
- return match;
1147
- });
1201
+ let maxSize = this.options.maxInlinedImagesSize;
1202
+ if (typeof maxSize !== 'number' || !(maxSize >= 0)) {
1203
+ maxSize = MAX_INLINED_IMAGES_SIZE;
1204
+ }
1205
+ let inlinedSize = 0;
1206
+ try {
1207
+ html = html.replace(/\bcid:([^'"\s]{1,256})/g, (match, cid) => {
1208
+ let url = cids.has(cid) && cids.get(cid).url;
1209
+ if (!url) {
1210
+ return match;
1211
+ }
1212
+ url = String(url);
1213
+ if (inlinedSize + url.length > maxSize) {
1214
+ return match;
1215
+ }
1216
+ inlinedSize += url.length;
1217
+ return url;
1218
+ });
1219
+ } catch (err) {
1220
+ // runs from setImmediate, a throw here would be an uncaught exception
1221
+ return done(err);
1222
+ }
1148
1223
 
1149
1224
  return done(null, html);
1150
1225
  }
@@ -19,6 +19,18 @@ module.exports = (input, options, callback) => {
19
19
  });
20
20
  }
21
21
 
22
+ // MailParser may emit a non-fatal 'error' (eg. HTML too long to convert to text) and
23
+ // still reach 'end', so settle only once: the first error or the result wins
24
+ let settled = false;
25
+ let settle = callback;
26
+ callback = (...args) => {
27
+ if (settled) {
28
+ return;
29
+ }
30
+ settled = true;
31
+ settle(...args);
32
+ };
33
+
22
34
  options = options || {};
23
35
  let keepCidLinks = !!options.keepCidLinks;
24
36
 
@@ -8,7 +8,7 @@ class StreamHash extends Transform {
8
8
  super();
9
9
  this.attachment = attachment;
10
10
  this.algo = (algo || 'md5').toLowerCase();
11
- this.hash = crypto.createHash(algo);
11
+ this.hash = crypto.createHash(this.algo);
12
12
  this.byteCount = 0;
13
13
  }
14
14
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailparser",
3
- "version": "3.9.28",
3
+ "version": "3.9.34",
4
4
  "description": "Parse e-mails",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,10 +22,10 @@
22
22
  "he": "1.2.0",
23
23
  "html-to-text": "10.0.1",
24
24
  "iconv-lite": "0.7.3",
25
- "libmime": "5.4.4",
25
+ "libmime": "5.4.6",
26
26
  "linkify-it": "5.0.2",
27
- "@zone-eu/mailsplit": "5.4.17",
28
- "nodemailer": "10.0.10",
27
+ "@zone-eu/mailsplit": "5.4.19",
28
+ "nodemailer": "10.0.14",
29
29
  "punycode.js": "2.3.1",
30
30
  "tlds": "1.261.0"
31
31
  },
@@ -33,7 +33,7 @@
33
33
  "@eslint/eslintrc": "3.3.7",
34
34
  "@eslint/js": "10.0.1",
35
35
  "ajv": "8.20.0",
36
- "eslint": "10.10.0",
36
+ "eslint": "10.12.0",
37
37
  "eslint-config-nodemailer": "1.2.0",
38
38
  "eslint-config-prettier": "10.1.8",
39
39
  "grunt": "1.6.3",
@@ -41,7 +41,7 @@
41
41
  "grunt-contrib-nodeunit": "5.0.0",
42
42
  "grunt-eslint": "27.0.0",
43
43
  "iconv": "3.0.1",
44
- "prettier": "3.9.6",
44
+ "prettier": "3.9.9",
45
45
  "random-message": "1.1.0"
46
46
  },
47
47
  "repository": {
@@ -1,5 +1,43 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [10.0.14](https://github.com/nodemailer/nodemailer/compare/v10.0.13...v10.0.14) (2026-10-03)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **addressparser:** keep a quoted display name that holds no "@" out of the address ([3570d26](https://github.com/nodemailer/nodemailer/commit/3570d26c7b55f6e5df50d4076046600ad3fd040b))
9
+ * **addressparser:** keep the group recursion depth out of the options object ([a680254](https://github.com/nodemailer/nodemailer/commit/a68025405a1378c82e78f64ffad27b92c1035cbe))
10
+ * **addressparser:** stop a "[" from hiding the operators after it ([5619784](https://github.com/nodemailer/nodemailer/commit/561978491d5cc33d2052a6c89a499b838b960262))
11
+ * **dkim:** trim a header field name in linear time ([c6f7a55](https://github.com/nodemailer/nodemailer/commit/c6f7a55a2978bf031b8519ebf59baddf94c032c8))
12
+ * **mime-funcs:** read and write header parameters per rfc2045 and rfc2231 ([b8ccad7](https://github.com/nodemailer/nodemailer/commit/b8ccad723a7e49a674a4d70f32eb9fe77312008d))
13
+ * search only the new bytes for the end of the proxy CONNECT response ([81efd7b](https://github.com/nodemailer/nodemailer/commit/81efd7bfc559305f900d6a22b5c56aa94556002b))
14
+
15
+ ## [10.0.13](https://github.com/nodemailer/nodemailer/compare/v10.0.12...v10.0.13) (2026-09-30)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * read the advertised SASL methods without backtracking regexes ([b5a896f](https://github.com/nodemailer/nodemailer/commit/b5a896fcb02df1628329d7cd665ca08490b14b56))
21
+ * strip comments inside an angle-addr before it becomes the address ([a502247](https://github.com/nodemailer/nodemailer/commit/a502247555fd81773eac337486781f3b6008e16a))
22
+
23
+ ## [10.0.12](https://github.com/nodemailer/nodemailer/compare/v10.0.11...v10.0.12) (2026-09-28)
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * settle every send on a connection error, back off pool requeues, turn a bare CR into CRLF, bound fetch, honour requireTLS ([63ccd66](https://github.com/nodemailer/nodemailer/commit/63ccd66c894bbaac18c82084ee385bf6488226cf))
29
+
30
+ ## [10.0.11](https://github.com/nodemailer/nodemailer/compare/v10.0.10...v10.0.11) (2026-09-27)
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * **fetch:** report a form body that can not be encoded through the returned stream ([74d40bf](https://github.com/nodemailer/nodemailer/commit/74d40bf1e4553bc0568b471250a9251bcb569b00))
36
+ * keep the CommonJS entry point and the services subpath compatible with the pre-TypeScript build ([52901ef](https://github.com/nodemailer/nodemailer/commit/52901ef3725ad179aa56276495a60f53b2c83516))
37
+ * **qp:** keep wrap() terminating for short line lengths and a trailing incomplete escape ([8fa140b](https://github.com/nodemailer/nodemailer/commit/8fa140b11c62cb1202eac84d35bb3ba28bc3b1a1))
38
+ * **smtp-connection:** fail a password login cleanly when the server offers only XOAUTH2 ([90abf7d](https://github.com/nodemailer/nodemailer/commit/90abf7d11db5ebfeb4292b62c1fff969741c7d33))
39
+ * **types:** restore the layout of @types/nodemailer in the bundled declarations ([ac2e40f](https://github.com/nodemailer/nodemailer/commit/ac2e40ffc69427e0eb33ce3945fae76c4c828c8d))
40
+
3
41
  ## [10.0.10](https://github.com/nodemailer/nodemailer/compare/v10.0.9...v10.0.10) (2026-09-14)
4
42
 
5
43
 
@@ -72,7 +72,7 @@ let configOptions = {
72
72
 
73
73
  #### I have an issue with TypeScript types
74
74
 
75
- Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter<SMTPTransport.SentMessageInfo>` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply.
75
+ Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter<SMTPTransport.SentMessageInfo>` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. The modules under `nodemailer/lib/` are declared with a default export, so import a class as `import SMTPTransport from 'nodemailer/lib/smtp-transport'` (with `esModuleInterop` in a CommonJS project). The `import SMTPTransport = require(...)` and `import * as SMTPTransport from ...` forms still resolve the type aliases such as `SMTPTransport.Options`, but they refer to the module rather than to the class, so the class itself has to be imported with a default import. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply.
76
76
 
77
77
  #### I have a different problem
78
78
 
@@ -39,7 +39,21 @@ export type Address = MailboxAddress | GroupAddress;
39
39
  *
40
40
  * @param str Address field
41
41
  * @param options Optional options object
42
- * @param options._depth Internal recursion depth counter (do not set manually)
43
42
  * @return An array of address objects
44
43
  */
45
- export default function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
44
+ declare function addressparser(str: string | null | undefined, options: AddressParserOptions & {
45
+ flatten: true;
46
+ }): MailboxAddress[];
47
+ declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[];
48
+ /**
49
+ * Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working
50
+ */
51
+ type AddressEntry = Address;
52
+ declare namespace addressparser {
53
+ type Address = MailboxAddress;
54
+ type Group = GroupAddress;
55
+ type AddressOrGroup = AddressEntry;
56
+ }
57
+ /** The names @types/nodemailer used for the group entry and for the union of both entry types */
58
+ export type { GroupAddress as Group, Address as AddressOrGroup };
59
+ export default addressparser;
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = addressparser;
4
3
  /**
5
4
  * Restores the quoting of a local part that was read out of a quoted string.
6
5
  *
@@ -243,6 +242,81 @@ function _recoverAddrSpec(data) {
243
242
  .filter(part => part)
244
243
  .join(' ');
245
244
  }
245
+ /**
246
+ * Takes the RFC 5322 comments out of the contents of an angle-addr.
247
+ *
248
+ * The tokenizer tracks a single open operator, so once '<' is open a '(' is plain text and
249
+ * a comment inside the brackets reached the address verbatim: 'Name <user@example.com(x)evil.com>'
250
+ * put 'user@example.com(x)evil.com' into the envelope, a value that is no mailbox and that a
251
+ * receiver stripping the comment reads as 'user@example.comevil.com' (GHSA-g73g-hqqh-jr95).
252
+ * A comment is folding whitespace, so it is read as a space that splits two atoms and as
253
+ * nothing next to an '@', the same rule the token walk applies outside the brackets. Quoted
254
+ * strings and domain literals are copied through untouched, a '(' in there is not a comment.
255
+ *
256
+ * @param address Contents of the angle brackets
257
+ * @return The address with the comments removed, and the text of the comments
258
+ */
259
+ function _stripAddressComments(address) {
260
+ const comments = [];
261
+ let result = '';
262
+ let comment = '';
263
+ let depth = 0;
264
+ let closer = '';
265
+ // carried along rather than read back off the growing result, which would flatten it on
266
+ // every comment (see lastChars in _handleAddress)
267
+ let lastChar = '';
268
+ for (let i = 0, len = address.length; i < len; i++) {
269
+ const chr = address.charAt(i);
270
+ if (depth) {
271
+ if (chr === '\\' && i < len - 1) {
272
+ comment += address.charAt(++i);
273
+ }
274
+ else if (chr === '(') {
275
+ depth++;
276
+ comment += chr;
277
+ }
278
+ else if (chr === ')' && !--depth) {
279
+ comments.push(comment.trim());
280
+ comment = '';
281
+ if (lastChar !== '@' && address.charAt(i + 1) !== '@') {
282
+ result += ' ';
283
+ lastChar = ' ';
284
+ }
285
+ }
286
+ else {
287
+ comment += chr;
288
+ }
289
+ continue;
290
+ }
291
+ if (closer) {
292
+ if (chr === '\\' && closer === '"' && i < len - 1) {
293
+ result += chr + address.charAt(++i);
294
+ lastChar = address.charAt(i);
295
+ continue;
296
+ }
297
+ if (chr === closer) {
298
+ closer = '';
299
+ }
300
+ }
301
+ else if (chr === '"') {
302
+ closer = '"';
303
+ }
304
+ else if (chr === '[') {
305
+ closer = ']';
306
+ }
307
+ else if (chr === '(') {
308
+ depth = 1;
309
+ continue;
310
+ }
311
+ result += chr;
312
+ lastChar = chr;
313
+ }
314
+ if (depth) {
315
+ // an unterminated comment runs to the end of the address
316
+ comments.push(comment.trim());
317
+ }
318
+ return { address: result.trim(), comments: comments.filter(text => text) };
319
+ }
246
320
  /**
247
321
  * Converts tokens for a single address into an address object
248
322
  *
@@ -354,7 +428,7 @@ function _handleAddress(tokens, depth) {
354
428
  // Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
355
429
  let groupMembers = [];
356
430
  if (data.group.length) {
357
- const parsedGroup = addressparser(data.group.join(','), { _depth: depth + 1 });
431
+ const parsedGroup = _parseAddressList(data.group.join(','), depth + 1);
358
432
  parsedGroup.forEach(member => {
359
433
  if (member.group) {
360
434
  groupMembers = groupMembers.concat(member.group);
@@ -370,6 +444,24 @@ function _handleAddress(tokens, depth) {
370
444
  });
371
445
  }
372
446
  else {
447
+ // Comments come out of the angle-addr before anything asks whether one was found, so
448
+ // that brackets holding nothing but a comment read the same as empty ones
449
+ const addressComments = [];
450
+ const addressParts = [];
451
+ for (const part of data.address) {
452
+ if (part.indexOf('(') < 0) {
453
+ addressParts.push(part);
454
+ continue;
455
+ }
456
+ const stripped = _stripAddressComments(part);
457
+ for (const comment of stripped.comments) {
458
+ addressComments.push(comment);
459
+ }
460
+ if (stripped.address) {
461
+ addressParts.push(stripped.address);
462
+ }
463
+ }
464
+ data.address = addressParts;
373
465
  // If no address was found, try to detect one from regular text
374
466
  if (!data.address.length && data.text.length) {
375
467
  for (let i = data.text.length - 1; i >= 0; i--) {
@@ -423,7 +515,13 @@ function _handleAddress(tokens, depth) {
423
515
  // Join values with spaces
424
516
  data.text = data.text.join(' ');
425
517
  data.address = data.address.join(' ');
426
- if (addressFromQuotedText && data.text) {
518
+ if (addressFromQuotedText && data.text.indexOf('@') >= 0) {
519
+ // A quoted run with no '@' in it is a display name and nothing else, so it stays
520
+ // where it is. Moving it over anyway made a comment the mailbox was read from:
521
+ // '"Display Name" <(a comment)>' handed on 'Display Name' as the address with the
522
+ // comment as the name, and a quoted name holding a ',' or a ';' became an address
523
+ // that reads as two recipients once a consumer writes it back into a header.
524
+ //
427
525
  // The mailbox is still sitting in the text, so it moves over here and is quoted
428
526
  // before the recovery below rather than after it. Anything else the text holds
429
527
  // came along with it: a comment ends the domain but leaves the atoms behind it in
@@ -436,6 +534,10 @@ function _handleAddress(tokens, depth) {
436
534
  data.text = '';
437
535
  }
438
536
  _recoverAddrSpec(data);
537
+ // a comment names the mailbox only when nothing else does, as one outside the brackets
538
+ if (!data.text && addressComments.length) {
539
+ data.text = addressComments.join(' ');
540
+ }
439
541
  const address = {
440
542
  address: data.address || data.text || '',
441
543
  name: data.text || data.address || ''
@@ -466,6 +568,7 @@ class Tokenizer {
466
568
  this.node = null;
467
569
  this.escaped = false;
468
570
  this.inDomainLiteral = false;
571
+ this.afterAt = false;
469
572
  this.list = [];
470
573
  /**
471
574
  * Operator tokens and which tokens are expected to end the sequence
@@ -509,17 +612,23 @@ class Tokenizer {
509
612
  * Checks if a character is an operator or text and acts accordingly
510
613
  *
511
614
  * @param chr Character from the address field
615
+ * @param nextChr Character following chr, null at the end of the field
512
616
  */
513
617
  checkChar(chr, nextChr) {
514
- // Track RFC 5322 domain-literals ("[" *dtext "]"). Operator characters such
515
- // as the ":" of an IPv6 address-literal (user@[IPv6:2001:db8::1]) are dtext
516
- // and must not be treated as the group delimiter while inside the brackets.
517
- // Quoted strings and comments are handled separately via operatorExpecting,
518
- // so only enter this state when no operator is open. The list separators ","
519
- // and ";" are the exception: they always end the literal (and split the
520
- // address list) so that an unclosed "[" cannot swallow later recipients.
618
+ // Track RFC 5322 domain-literals ("[" *dtext "]"). The ":" of an IPv6
619
+ // address-literal (user@[IPv6:2001:db8::1]) is dtext and must not be treated as
620
+ // the group delimiter while inside the brackets. That is the only operator the
621
+ // literal hides: letting it hide the others as well meant a "[" could turn the
622
+ // comment, quoted string or angle-addr after it into text and pick a different
623
+ // mailbox, '[ ( ] <a@victim.com> ) <b@evil.com>' yielded a@victim.com where
624
+ // RFC 5322 reads b@evil.com. A "[" also only opens a literal right after the "@"
625
+ // of an addr-spec, so the group delimiter of a display name holding one stays
626
+ // intact. Quoted strings and comments are handled separately via
627
+ // operatorExpecting, so only enter this state when no operator is open. The list
628
+ // separators "," and ";" always end the literal (and split the address list) so
629
+ // that an unclosed "[" cannot swallow later recipients.
521
630
  if (!this.escaped && !this.operatorExpecting) {
522
- if (!this.inDomainLiteral && chr === '[') {
631
+ if (!this.inDomainLiteral && chr === '[' && this.afterAt) {
523
632
  this.inDomainLiteral = true;
524
633
  }
525
634
  else if (this.inDomainLiteral && (chr === ']' || chr === ',' || chr === ';')) {
@@ -539,17 +648,24 @@ class Tokenizer {
539
648
  }
540
649
  this.list.push(this.node);
541
650
  this.node = null;
651
+ if (chr !== ')') {
652
+ // a comment is folding whitespace, it does not part the "@" from the "["
653
+ this.afterAt = false;
654
+ }
542
655
  this.operatorExpecting = '';
543
656
  this.escaped = false;
544
657
  return;
545
658
  }
546
- else if (!this.operatorExpecting && !this.inDomainLiteral && chr in this.operators) {
659
+ else if (!this.operatorExpecting && !(this.inDomainLiteral && chr === ':') && chr in this.operators) {
547
660
  this.node = {
548
661
  type: 'operator',
549
662
  value: chr
550
663
  };
551
664
  this.list.push(this.node);
552
665
  this.node = null;
666
+ if (chr !== '(') {
667
+ this.afterAt = false;
668
+ }
553
669
  this.operatorExpecting = this.operators[chr];
554
670
  this.escaped = false;
555
671
  return;
@@ -573,6 +689,11 @@ class Tokenizer {
573
689
  if (chr.charCodeAt(0) >= 0x21 || [' ', '\t'].includes(chr)) {
574
690
  // skip command bytes
575
691
  this.node.value += chr;
692
+ // text inside a quoted string or a comment is not part of an addr-spec. Tracked
693
+ // as it goes rather than read back off the value (see lastChars in _handleAddress)
694
+ if (!this.operatorExpecting && chr !== ' ' && chr !== '\t') {
695
+ this.afterAt = chr === '@';
696
+ }
576
697
  }
577
698
  this.escaped = false;
578
699
  }
@@ -584,24 +705,18 @@ class Tokenizer {
584
705
  */
585
706
  const MAX_NESTED_GROUP_DEPTH = 50;
586
707
  /**
587
- * Parses structured e-mail addresses from an address field
588
- *
589
- * Example:
590
- *
591
- * 'Name <address@domain>'
708
+ * Parses an address list, recursing into the groups it holds.
592
709
  *
593
- * will be converted to
594
- *
595
- * [{name: 'Name', address: 'address@domain'}]
710
+ * The depth is threaded through the calls rather than carried in an options object, so a
711
+ * caller supplied one can not seed it and lift the recursion limit: `{ _depth: -1e9 }`
712
+ * bought a billion levels of nesting and turned the guard below into the stack overflow it
713
+ * is there to prevent.
596
714
  *
597
715
  * @param str Address field
598
- * @param options Optional options object
599
- * @param options._depth Internal recursion depth counter (do not set manually)
716
+ * @param depth Current recursion depth for nested group protection
600
717
  * @return An array of address objects
601
718
  */
602
- function addressparser(str, options) {
603
- options = options || {};
604
- const depth = options._depth || 0;
719
+ function _parseAddressList(str, depth) {
605
720
  // Prevent stack overflow from deeply nested groups (DoS protection)
606
721
  if (depth > MAX_NESTED_GROUP_DEPTH) {
607
722
  return [];
@@ -610,7 +725,7 @@ function addressparser(str, options) {
610
725
  const tokens = tokenizer.tokenize();
611
726
  const addresses = [];
612
727
  let address = [];
613
- let parsedAddresses = [];
728
+ const parsedAddresses = [];
614
729
  tokens.forEach(token => {
615
730
  if (token.type === 'operator' && (token.value === ',' || token.value === ';')) {
616
731
  if (address.length) {
@@ -651,8 +766,11 @@ function addressparser(str, options) {
651
766
  }
652
767
  }
653
768
  mergedAddresses.reverse();
654
- parsedAddresses = mergedAddresses;
655
- if (options.flatten) {
769
+ return mergedAddresses;
770
+ }
771
+ function addressparser(str, options) {
772
+ const parsedAddresses = _parseAddressList(str, 0);
773
+ if (options?.flatten) {
656
774
  const flatAddresses = [];
657
775
  const walkAddressList = (list) => {
658
776
  list.forEach(entry => {
@@ -667,5 +785,6 @@ function addressparser(str, options) {
667
785
  }
668
786
  return parsedAddresses;
669
787
  }
788
+ exports.default = addressparser;
670
789
  module.exports = exports.default;
671
790
  Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });