@mavogel/awscdk-rootmail 0.1.26 → 0.1.28

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 (175) hide show
  1. package/.jsii +8 -8
  2. package/lib/rootmail.js +1 -1
  3. package/lib/ses-receive.js +1 -1
  4. package/node_modules/@aws-sdk/checksums/package.json +4 -4
  5. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +1 -1
  6. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/CloudWatchLogsClient.d.ts +2 -1
  7. package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +5 -5
  8. package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
  9. package/node_modules/@aws-sdk/client-route-53/dist-types/Route53Client.d.ts +2 -1
  10. package/node_modules/@aws-sdk/client-route-53/package.json +6 -6
  11. package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +1 -1
  12. package/node_modules/@aws-sdk/client-s3/dist-types/S3Client.d.ts +2 -1
  13. package/node_modules/@aws-sdk/client-s3/package.json +9 -9
  14. package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
  15. package/node_modules/@aws-sdk/client-ses/dist-types/SESClient.d.ts +2 -1
  16. package/node_modules/@aws-sdk/client-ses/package.json +5 -5
  17. package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +1 -1
  18. package/node_modules/@aws-sdk/client-ssm/dist-types/SSMClient.d.ts +2 -1
  19. package/node_modules/@aws-sdk/client-ssm/package.json +5 -5
  20. package/node_modules/@aws-sdk/core/package.json +3 -3
  21. package/node_modules/@aws-sdk/credential-provider-env/package.json +4 -4
  22. package/node_modules/@aws-sdk/credential-provider-http/package.json +4 -4
  23. package/node_modules/@aws-sdk/credential-provider-ini/package.json +11 -11
  24. package/node_modules/@aws-sdk/credential-provider-login/package.json +5 -5
  25. package/node_modules/@aws-sdk/credential-provider-node/package.json +9 -9
  26. package/node_modules/@aws-sdk/credential-provider-process/package.json +4 -4
  27. package/node_modules/@aws-sdk/credential-provider-sso/package.json +6 -6
  28. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +5 -5
  29. package/node_modules/@aws-sdk/middleware-sdk-route53/package.json +2 -2
  30. package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +5 -5
  31. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  32. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  33. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  34. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  35. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  36. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/cognito-identity/CognitoIdentityClient.d.ts +2 -1
  37. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/signin/SigninClient.d.ts +2 -1
  38. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso/SSOClient.d.ts +2 -1
  39. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso-oidc/SSOOIDCClient.d.ts +2 -1
  40. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sts/STSClient.d.ts +2 -1
  41. package/node_modules/@aws-sdk/nested-clients/package.json +5 -5
  42. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +2 -2
  43. package/node_modules/@aws-sdk/token-providers/package.json +5 -5
  44. package/node_modules/@aws-sdk/types/dist-types/feature-ids.d.ts +3 -0
  45. package/node_modules/@aws-sdk/types/dist-types/ts3.4/feature-ids.d.ts +3 -0
  46. package/node_modules/@aws-sdk/types/package.json +1 -1
  47. package/node_modules/@smithy/core/dist-cjs/submodules/client/index.js +15 -2
  48. package/node_modules/@smithy/core/dist-cjs/submodules/event-streams/index.browser.js +10 -0
  49. package/node_modules/@smithy/core/dist-cjs/submodules/event-streams/index.js +10 -0
  50. package/node_modules/@smithy/core/dist-cjs/submodules/protocols/index.js +5 -5
  51. package/node_modules/@smithy/core/dist-es/submodules/client/smithy-client/command.js +16 -2
  52. package/node_modules/@smithy/core/dist-es/submodules/event-streams/eventstream-codec/HeaderMarshaller.js +10 -0
  53. package/node_modules/@smithy/core/dist-es/submodules/protocols/json/codec-v2/JsonShapeSerializer2.js +5 -5
  54. package/node_modules/@smithy/core/package.json +1 -1
  55. package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +39 -27
  56. package/node_modules/@zone-eu/mailsplit/lib/mime-node.d.ts +1 -1
  57. package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +38 -61
  58. package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +1 -1
  59. package/node_modules/@zone-eu/mailsplit/package.json +2 -2
  60. package/node_modules/libmime/CHANGELOG.md +36 -0
  61. package/node_modules/libmime/README.md +40 -3
  62. package/node_modules/libmime/dist/cjs/charset.d.ts +36 -0
  63. package/node_modules/libmime/dist/cjs/charset.js +165 -2
  64. package/node_modules/libmime/dist/cjs/charsets.js +8 -2
  65. package/node_modules/libmime/dist/cjs/libmime.d.ts +20 -3
  66. package/node_modules/libmime/dist/cjs/libmime.js +100 -6
  67. package/node_modules/libmime/dist/cjs/types.d.ts +28 -0
  68. package/node_modules/libmime/dist/esm/charset.d.ts +36 -0
  69. package/node_modules/libmime/dist/esm/charset.js +162 -2
  70. package/node_modules/libmime/dist/esm/charsets.js +8 -2
  71. package/node_modules/libmime/dist/esm/libmime.d.ts +20 -3
  72. package/node_modules/libmime/dist/esm/libmime.js +100 -6
  73. package/node_modules/libmime/dist/esm/types.d.ts +28 -0
  74. package/node_modules/libmime/package.json +3 -3
  75. package/node_modules/mailparser/CHANGELOG.md +51 -0
  76. package/node_modules/mailparser/README.md +32 -1
  77. package/node_modules/mailparser/dist/cjs/address-header.d.ts +19 -0
  78. package/node_modules/mailparser/dist/cjs/address-header.js +185 -0
  79. package/node_modules/mailparser/dist/cjs/index.d.ts +3 -1
  80. package/node_modules/mailparser/dist/cjs/index.js +4 -2
  81. package/node_modules/mailparser/dist/cjs/mail-parser.js +36 -183
  82. package/node_modules/mailparser/dist/cjs/stream-hash.d.ts +5 -4
  83. package/node_modules/mailparser/dist/cjs/stream-hash.js +8 -5
  84. package/node_modules/mailparser/dist/cjs/types.d.ts +33 -6
  85. package/node_modules/mailparser/dist/esm/address-header.d.ts +19 -0
  86. package/node_modules/mailparser/dist/esm/address-header.js +176 -0
  87. package/node_modules/mailparser/dist/esm/index.d.ts +3 -1
  88. package/node_modules/mailparser/dist/esm/index.js +3 -2
  89. package/node_modules/mailparser/dist/esm/mail-parser.js +36 -183
  90. package/node_modules/mailparser/dist/esm/stream-hash.d.ts +5 -4
  91. package/node_modules/mailparser/dist/esm/stream-hash.js +8 -5
  92. package/node_modules/mailparser/dist/esm/types.d.ts +33 -6
  93. package/node_modules/mailparser/package.json +6 -7
  94. package/node_modules/nodemailer/CHANGELOG.md +23 -0
  95. package/node_modules/nodemailer/dist/cjs/addressparser/index.js +2 -5
  96. package/node_modules/nodemailer/dist/cjs/dkim/index.js +1 -3
  97. package/node_modules/nodemailer/dist/cjs/errors.d.ts +19 -0
  98. package/node_modules/nodemailer/dist/cjs/errors.js +14 -1
  99. package/node_modules/nodemailer/dist/cjs/fetch/cookies.js +2 -4
  100. package/node_modules/nodemailer/dist/cjs/fetch/index.js +2 -8
  101. package/node_modules/nodemailer/dist/cjs/mail-composer/index.js +42 -9
  102. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +5 -6
  103. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +18 -1
  104. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +43 -1
  105. package/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +3 -12
  106. package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +34 -1
  107. package/node_modules/nodemailer/dist/cjs/mime-node/index.js +40 -15
  108. package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
  109. package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
  110. package/node_modules/nodemailer/dist/cjs/qp/index.js +3 -12
  111. package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +1 -3
  112. package/node_modules/nodemailer/dist/cjs/shared/index.js +2 -6
  113. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +1 -1
  114. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +6 -0
  115. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +15 -12
  116. package/node_modules/nodemailer/dist/cjs/smtp-connection/server-message-id.d.ts +14 -0
  117. package/node_modules/nodemailer/dist/cjs/smtp-connection/server-message-id.js +53 -0
  118. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +11 -0
  119. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +25 -1
  120. package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +2 -5
  121. package/node_modules/nodemailer/dist/esm/addressparser/index.js +2 -5
  122. package/node_modules/nodemailer/dist/esm/dkim/index.js +1 -3
  123. package/node_modules/nodemailer/dist/esm/errors.d.ts +19 -0
  124. package/node_modules/nodemailer/dist/esm/errors.js +12 -0
  125. package/node_modules/nodemailer/dist/esm/fetch/cookies.js +2 -4
  126. package/node_modules/nodemailer/dist/esm/fetch/index.js +2 -8
  127. package/node_modules/nodemailer/dist/esm/mail-composer/index.js +42 -9
  128. package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +5 -6
  129. package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +18 -1
  130. package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +43 -1
  131. package/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.js +3 -12
  132. package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +34 -1
  133. package/node_modules/nodemailer/dist/esm/mime-node/index.js +40 -15
  134. package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
  135. package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
  136. package/node_modules/nodemailer/dist/esm/qp/index.js +3 -12
  137. package/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +1 -3
  138. package/node_modules/nodemailer/dist/esm/shared/index.js +2 -6
  139. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +1 -1
  140. package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +6 -0
  141. package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +16 -13
  142. package/node_modules/nodemailer/dist/esm/smtp-connection/server-message-id.d.ts +14 -0
  143. package/node_modules/nodemailer/dist/esm/smtp-connection/server-message-id.js +50 -0
  144. package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +11 -0
  145. package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +25 -1
  146. package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +2 -5
  147. package/node_modules/nodemailer/package.json +11 -9
  148. package/package.json +9 -9
  149. package/node_modules/mailparser/node_modules/iconv-lite/LICENSE +0 -21
  150. package/node_modules/mailparser/node_modules/iconv-lite/README.md +0 -138
  151. package/node_modules/mailparser/node_modules/iconv-lite/encodings/dbcs-codec.js +0 -532
  152. package/node_modules/mailparser/node_modules/iconv-lite/encodings/dbcs-data.js +0 -185
  153. package/node_modules/mailparser/node_modules/iconv-lite/encodings/index.js +0 -23
  154. package/node_modules/mailparser/node_modules/iconv-lite/encodings/internal.js +0 -218
  155. package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-codec.js +0 -75
  156. package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-data-generated.js +0 -451
  157. package/node_modules/mailparser/node_modules/iconv-lite/encodings/sbcs-data.js +0 -180
  158. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/big5-added.json +0 -122
  159. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp936.json +0 -264
  160. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp949.json +0 -273
  161. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/cp950.json +0 -177
  162. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/eucjp.json +0 -182
  163. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +0 -1
  164. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/gbk-added.json +0 -56
  165. package/node_modules/mailparser/node_modules/iconv-lite/encodings/tables/shiftjis.json +0 -125
  166. package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf16.js +0 -187
  167. package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf32.js +0 -314
  168. package/node_modules/mailparser/node_modules/iconv-lite/encodings/utf7.js +0 -283
  169. package/node_modules/mailparser/node_modules/iconv-lite/lib/bom-handling.js +0 -48
  170. package/node_modules/mailparser/node_modules/iconv-lite/lib/helpers/merge-exports.js +0 -13
  171. package/node_modules/mailparser/node_modules/iconv-lite/lib/index.d.ts +0 -129
  172. package/node_modules/mailparser/node_modules/iconv-lite/lib/index.js +0 -182
  173. package/node_modules/mailparser/node_modules/iconv-lite/lib/streams.js +0 -105
  174. package/node_modules/mailparser/node_modules/iconv-lite/package.json +0 -70
  175. package/node_modules/mailparser/node_modules/iconv-lite/types/encodings.d.ts +0 -425
@@ -6,6 +6,26 @@ import * as libcharset from './charset.js';
6
6
  import * as mimetypes from './mimetypes.js';
7
7
  const STAGE_KEY = 0x1001;
8
8
  const STAGE_VALUE = 0x1002;
9
+ /**
10
+ * Offset of the ")" that closes the rfc822 comment opening at `start`, or -1 when the
11
+ * comment never closes. Comments nest, and a backslash escapes the character after it
12
+ */
13
+ const findCommentEnd = (str, start) => {
14
+ let depth = 0;
15
+ for (let i = start, len = str.length; i < len; i++) {
16
+ let chr = str.charAt(i);
17
+ if (chr === '\\') {
18
+ i++;
19
+ }
20
+ else if (chr === '(') {
21
+ depth++;
22
+ }
23
+ else if (chr === ')' && --depth === 0) {
24
+ return i;
25
+ }
26
+ }
27
+ return -1;
28
+ };
9
29
  // Sets an own property on a plain object. A regular assignment with a
10
30
  // '__proto__' key would silently modify the object's prototype instead of
11
31
  // creating an own property, so it needs special handling.
@@ -22,6 +42,9 @@ const setOwnProperty = (obj, key, value) => {
22
42
  obj[key] = value;
23
43
  }
24
44
  };
45
+ // Header names decodeHeaders() leaves out with the skipPrototypeKeys option. Keys are lowercased,
46
+ // so of these only '__proto__' and 'constructor' can ever match
47
+ const PROTOTYPE_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));
25
48
  // Whitespace that separates the tokens of a header value. Kept as a char comparison,
26
49
  // a regex test would be run for every single char of every parsed header
27
50
  const isWSP = (chr) => chr === ' ' || chr === '\t' || chr === '\r' || chr === '\n' || chr === '\f' || chr === '\v';
@@ -259,6 +282,18 @@ export class Libmime {
259
282
  normalizeCharset(charset) {
260
283
  return libcharset.normalizeCharset(charset);
261
284
  }
285
+ /**
286
+ * Creates a Transform stream that decodes a body in the given charset into UTF-8 Buffers,
287
+ * resolving the charset name and handling the Japanese charsets the same way header
288
+ * decoding does. An unknown or refused charset (UTF-7, base64, hex) is decoded as UTF-8,
289
+ * and the stream says so with `supported` set to false.
290
+ *
291
+ * @param {String} [charset='UTF-8'] Charset the input is encoded in
292
+ * @return {DecodeStream} Transform stream with `charset` and `supported` properties
293
+ */
294
+ createDecodeStream(charset) {
295
+ return libcharset.createDecodeStream(charset);
296
+ }
262
297
  /**
263
298
  * Decodes the inner payload of a single mime encoded-word into a unicode string.
264
299
  * Expects the three components of `=?charset?encoding?text?=` already separated.
@@ -417,9 +452,11 @@ export class Libmime {
417
452
  * header might have its own rules (eg. formatted email addresses and such)
418
453
  *
419
454
  * @param {String} headers Headers string
455
+ * @param {Object} [options] Options
456
+ * @param {Boolean} [options.skipPrototypeKeys] Leave out headers named like an Object.prototype member, eg. `__proto__` and `constructor`
420
457
  * @return {Object} An object of headers, where header keys are object keys and every value is an Array of the values for that key
421
458
  */
422
- decodeHeaders(headers) {
459
+ decodeHeaders(headers, options) {
423
460
  let lines = headers.split(/\r?\n|\r/), headersObj = {}, header, i, len;
424
461
  // Empty lines in front of the block are not part of any header, a caller might
425
462
  // include the line break that separates a mime part boundary from its headers
@@ -445,6 +482,9 @@ export class Libmime {
445
482
  lines = unfolded;
446
483
  for (i = 0, len = lines.length; i < len; i++) {
447
484
  header = this.decodeHeader(lines[i]);
485
+ if (options?.skipPrototypeKeys && PROTOTYPE_KEYS.has(header.key)) {
486
+ continue;
487
+ }
448
488
  // own properties only, an attacker controlled key such as '__proto__' or 'toString' would
449
489
  // otherwise resolve to an inherited Object.prototype member
450
490
  if (!Object.hasOwn(headersObj, header.key)) {
@@ -513,9 +553,12 @@ export class Libmime {
513
553
  * decoded, so a caller that runs decodeWords() over the params has to leave them out
514
554
  *
515
555
  * @param {String} str Header value
556
+ * @param {Object} [options] Options, see ParseHeaderValueOptions
516
557
  * @return {Object} Header value as a parsed structure
517
558
  */
518
- parseHeaderValue(str) {
559
+ parseHeaderValue(str, options) {
560
+ // Cleared again by an unclosed "(", see the loop
561
+ let stripComments = !!options?.stripComments;
519
562
  let response = {
520
563
  value: '',
521
564
  params: {}
@@ -535,10 +578,23 @@ export class Libmime {
535
578
  let valueEnd = 0;
536
579
  let stage = STAGE_VALUE;
537
580
  let quote = false;
581
+ // A quoted string has closed and the ";" that ends the parameter has not come yet
582
+ let quoteClosed = false;
538
583
  let escaped = false;
539
584
  let chr;
585
+ // Whether a "(" would continue the unquoted token of a parameter value, which it does
586
+ // right behind the "=" and behind a character of the token: `filename=Invoice(1).pdf`
587
+ // names the file and `boundary=(c)b` the boundary `(c)b`, as they do for Python and
588
+ // postal-mime. Anywhere else, in the type, in a parameter name, behind whitespace or
589
+ // behind a quoted string, a "(" opens a comment
590
+ let tokenOpen = false;
540
591
  // Stores the collected value, either as the default value, as the value for the
541
- // current key, or as a key that has no value at all. Runs once per parameter
592
+ // current key, or as a key that has no value at all. Runs once per parameter.
593
+ //
594
+ // A parameter given twice keeps its first value, as it does for Python and for
595
+ // postal-mime. Letting the last one win read `boundary=b; boundary=c` as a multipart
596
+ // of the parts under `--c`, which the other readers leave in the epilogue of the
597
+ // parts under `--b`
542
598
  let commit = () => {
543
599
  let collected = value.substring(0, valueEnd);
544
600
  value = '';
@@ -546,21 +602,42 @@ export class Libmime {
546
602
  if (stage === STAGE_KEY) {
547
603
  // key without a value, see emptykey:
548
604
  // Header-Key: somevalue; key=value; emptykey
549
- if (collected) {
550
- setOwnProperty(response.params, collected.toLowerCase(), '');
605
+ let name = collected.toLowerCase();
606
+ if (name && !Object.hasOwn(response.params, name)) {
607
+ setOwnProperty(response.params, name, '');
551
608
  }
552
609
  }
553
610
  else if (key === false) {
554
611
  // default value
555
612
  response.value = collected;
556
613
  }
557
- else {
614
+ else if (!Object.hasOwn(response.params, key)) {
558
615
  // subkey value
559
616
  setOwnProperty(response.params, key, collected);
560
617
  }
561
618
  };
562
619
  for (let i = 0, len = str.length; i < len; i++) {
563
620
  chr = str.charAt(i);
621
+ // With stripComments, an rfc822 comment stands anywhere outside a quoted string
622
+ // but right behind a token it would continue. Read as content, `boundary=b (comment)`
623
+ // named a boundary no delimiter line matches, so the parts that Python and
624
+ // postal-mime find stayed hidden from a splitter built on this
625
+ if (stripComments && chr === '(' && !quote && !escaped && !tokenOpen) {
626
+ let end = findCommentEnd(str, i);
627
+ if (end < 0 && str.indexOf(';', i) < 0) {
628
+ // A comment that never closes runs to the end of the value, as it does for
629
+ // Python. One that a parameter follows is content instead, with everything
630
+ // after it, so that the parameter survives, as postal-mime keeps it
631
+ end = len - 1;
632
+ }
633
+ if (end >= 0) {
634
+ i = end;
635
+ continue;
636
+ }
637
+ // Looking for a closing ")" again would scan a run of unclosed "(" to its end
638
+ // once for each of them
639
+ stripComments = false;
640
+ }
564
641
  switch (stage) {
565
642
  case STAGE_KEY:
566
643
  if (chr === '=') {
@@ -568,6 +645,7 @@ export class Libmime {
568
645
  value = '';
569
646
  valueEnd = 0;
570
647
  stage = STAGE_VALUE;
648
+ tokenOpen = true;
571
649
  }
572
650
  else if (chr === ';') {
573
651
  // key without a value, eg. the "inline" in "attachment; inline; filename=a.txt"
@@ -584,9 +662,19 @@ export class Libmime {
584
662
  }
585
663
  break;
586
664
  case STAGE_VALUE:
665
+ if (quoteClosed && chr !== ';') {
666
+ // Nothing behind a closed quoted string reaches the value: a parameter
667
+ // value is a token or a quoted string, not both (rfc2045 section 5.1),
668
+ // so what follows one is junk up to the ";" that ends the parameter, as
669
+ // Python and postal-mime read it. Read on, `boundary="b"c` named a
670
+ // boundary bc that no delimiter line of the message matches
671
+ escaped = false;
672
+ break;
673
+ }
587
674
  if (escaped) {
588
675
  value += chr;
589
676
  valueEnd = value.length;
677
+ tokenOpen = key !== false && !quote;
590
678
  }
591
679
  else if (chr === '\\') {
592
680
  escaped = true;
@@ -594,20 +682,26 @@ export class Libmime {
594
682
  }
595
683
  else if (chr === '"') {
596
684
  // every char between the quotes is significant, including whitespace
685
+ quoteClosed = quote;
597
686
  quote = !quote;
687
+ tokenOpen = false;
598
688
  }
599
689
  else if (!quote && chr === ';') {
600
690
  commit();
601
691
  stage = STAGE_KEY;
692
+ tokenOpen = false;
693
+ quoteClosed = false;
602
694
  }
603
695
  else if (!quote && isWSP(chr)) {
604
696
  if (value.length) {
605
697
  value += chr;
606
698
  }
699
+ tokenOpen = false;
607
700
  }
608
701
  else {
609
702
  value += chr;
610
703
  valueEnd = value.length;
704
+ tokenOpen = key !== false && !quote;
611
705
  }
612
706
  escaped = false;
613
707
  break;
@@ -15,6 +15,34 @@ export interface HeaderLine {
15
15
  * Parsed header block, every key holds the values of all the header lines with that key
16
16
  */
17
17
  export type HeaderObject = Record<string, string[]>;
18
+ /**
19
+ * Options of decodeHeaders()
20
+ */
21
+ export interface DecodeHeadersOptions {
22
+ /**
23
+ * Leave out the headers whose name is also the name of an Object.prototype member, such as
24
+ * `__proto__` and `constructor`. By default they are kept as own properties of the result,
25
+ * where a lookup with the `in` operator or a merge into another object can not tell them
26
+ * apart from the inherited members
27
+ */
28
+ skipPrototypeKeys?: boolean | undefined;
29
+ }
30
+ /**
31
+ * Options of parseHeaderValue()
32
+ */
33
+ export interface ParseHeaderValueOptions {
34
+ /**
35
+ * Drop the RFC 822 comments outside quoted strings. The MIME headers (Content-Type,
36
+ * Content-Disposition) allow them and they are not part of the value, so `boundary=b (comment)`
37
+ * names the boundary `b`. A parenthesis right behind the `=` of a parameter or behind a token
38
+ * of its value continues the token, as it does for Python and postal-mime: `filename=Invoice(1).pdf`
39
+ * keeps its name and `boundary=(c)b` names the boundary `(c)b`. A comment that never closes runs to the end
40
+ * of the value, unless a parameter follows it, in which case it is content and the parameter
41
+ * survives. By default comments are kept as they are, since a header such as
42
+ * Authentication-Results carries information in them
43
+ */
44
+ stripComments?: boolean | undefined;
45
+ }
18
46
  /**
19
47
  * Header value with key=value parameters as returned by parseHeaderValue()
20
48
  */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "libmime",
3
3
  "description": "Encode and decode quoted printable and base64 strings",
4
- "version": "5.5.2",
4
+ "version": "5.6.3",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/libmime.js",
7
7
  "types": "./dist/cjs/libmime.d.ts",
@@ -75,11 +75,11 @@
75
75
  "eslint": "10.13.0",
76
76
  "eslint-config-prettier": "10.1.8",
77
77
  "globals": "17.13.0",
78
- "nodemailer": "10.1.6",
78
+ "nodemailer": "10.2.0",
79
79
  "prettier": "3.9.10",
80
80
  "tsx": "4.23.15",
81
81
  "typescript": "6.0.3",
82
- "typescript-eslint": "8.71.2"
82
+ "typescript-eslint": "8.72.0"
83
83
  },
84
84
  "engines": {
85
85
  "node": ">=20.0.0"
@@ -1,5 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.12.4](https://github.com/nodemailer/mailparser/compare/v3.12.3...v3.12.4) (2026-10-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * update dependencies ([fe3b459](https://github.com/nodemailer/mailparser/commit/fe3b4596140eccfdd8e224ab4576094e0e49ef54))
9
+
10
+ ## [3.12.3](https://github.com/nodemailer/mailparser/compare/v3.12.2...v3.12.3) (2026-10-22)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **deps:** bump mailsplit to 5.4.28 and libmime to 5.6.3 ([996a18f](https://github.com/nodemailer/mailparser/commit/996a18f06a8a7e93c3042e293a35f3abb4d159bf))
16
+ * **deps:** bump mailsplit to 5.4.29, which reads an RFC 2231 filename the same way ([7ccd32b](https://github.com/nodemailer/mailparser/commit/7ccd32b72a1321543a02bddbfe0ef2c372ec0e0f))
17
+ * drop the comments of a Content-Type or Content-Disposition in the headers map ([eaf345b](https://github.com/nodemailer/mailparser/commit/eaf345b8bb9c94866da3bf1722aede6a88a7e11b))
18
+ * tell an RFC 2231 parameter apart by what libmime decoded, not by a second scan of the header ([eba8da2](https://github.com/nodemailer/mailparser/commit/eba8da294cd077d4816398a5499b14f1a79031d5))
19
+
20
+ ## [3.12.2](https://github.com/nodemailer/mailparser/compare/v3.12.1...v3.12.2) (2026-10-21)
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * the html and text forms parseAddressHeader() builds lazily can be assigned again ([bc6c421](https://github.com/nodemailer/mailparser/commit/bc6c4215c531a448c71540027c5ade74b4d60fab))
26
+
27
+ ## [3.12.1](https://github.com/nodemailer/mailparser/compare/v3.12.0...v3.12.1) (2026-10-21)
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * parseAddressHeader() builds the html and text forms only when they are read ([e08de61](https://github.com/nodemailer/mailparser/commit/e08de61740d04bdd534f8006d5b88eba6e4f89ed))
33
+
34
+ ## [3.12.0](https://github.com/nodemailer/mailparser/compare/v3.11.0...v3.12.0) (2026-10-21)
35
+
36
+
37
+ ### Features
38
+
39
+ * parseAddressHeader() accepts decodePunycode: false to keep IDN domains in ASCII form ([0652c3f](https://github.com/nodemailer/mailparser/commit/0652c3fca470d975aed0e6ec5b1a4ca8e53d95f1))
40
+
41
+ ## [3.11.0](https://github.com/nodemailer/mailparser/compare/v3.10.0...v3.11.0) (2026-10-21)
42
+
43
+
44
+ ### Features
45
+
46
+ * accept checksumAlgo: false to skip hashing attachments ([21f806c](https://github.com/nodemailer/mailparser/commit/21f806cd03b0b98644ad7a5b95678cc259f838db))
47
+ * export parseAddressHeader() for parsing an address header value ([8ac364e](https://github.com/nodemailer/mailparser/commit/8ac364e330fbc815b45986a0f64251b382b88421))
48
+
49
+
50
+ ### Bug Fixes
51
+
52
+ * decode text bodies with libmime's decode stream ([b9a5e41](https://github.com/nodemailer/mailparser/commit/b9a5e4125f1bf0a4aa88d275da5fbdb282cb779c))
53
+
3
54
  ## [3.10.0](https://github.com/nodemailer/mailparser/compare/v3.9.47...v3.10.0) (2026-10-19)
4
55
 
5
56
 
@@ -24,13 +24,44 @@ const mailparser = require('mailparser');
24
24
  or, from an ES module or TypeScript (type declarations are included):
25
25
 
26
26
  ```js
27
- import { simpleParser, MailParser } from 'mailparser';
27
+ import { simpleParser, MailParser, parseAddressHeader } from 'mailparser';
28
28
  ```
29
29
 
30
30
  ## Usage
31
31
 
32
32
  See [mailparser homepage](https://nodemailer.com/extras/mailparser/) for documentation and terms.
33
33
 
34
+ ### Parsing an address header
35
+
36
+ `parseAddressHeader(value, [options])` parses the value of an address header (`From`, `To`, `Cc`, `Reply-To` and the like) into the same `{ value, html, text }` object `MailParser` and `simpleParser` produce for one, for when the header comes from somewhere else than a message being parsed, for example an IMAP `HEADER.FIELDS` fetch.
37
+
38
+ ```js
39
+ const { parseAddressHeader } = require('mailparser');
40
+
41
+ parseAddressHeader('=?utf-8?Q?J=C3=B5geva?= <info@xn--mnchen-3ya.example>, Team: a@example.com;');
42
+ // {
43
+ // value: [
44
+ // { address: 'info@münchen.example', name: 'Jõgeva' },
45
+ // { name: 'Team', group: [{ address: 'a@example.com', name: '' }] }
46
+ // ],
47
+ // html: '<span class="mp_address_group">...',
48
+ // text: '"Jõgeva" <info@münchen.example>, "Team": a@example.com;'
49
+ // }
50
+ ```
51
+
52
+ - **value** - the header value without the `Name:` prefix, as a string. Folded lines are fine, raw 8-bit bytes have to be decoded into the string first. An array of values (a repeated header) is parsed one value at a time and the addresses are listed in order. An empty or missing value gives an empty list
53
+ - **options.flatten** - if `true`, every group is replaced with its members and the group names are dropped, so `value` lists mailboxes only
54
+
55
+ Each entry of `value` has a `name` (an empty string when there is none, encoded words decoded) and either an `address` (a punycode domain decoded to Unicode) or, for a group, a `group` list of the same entries. RFC 2047 does not allow encoded words in the address itself, so an address part hiding one is kept only when it decodes to a plain `local@domain`, otherwise `address` is an empty string; a display name that decodes to something looking like an address stays a name.
56
+
57
+ ### Character sets
58
+
59
+ Text bodies are decoded with libmime's `createDecodeStream()`, which resolves charset aliases, decodes the Japanese charsets iconv-lite does not support (ISO-2022-JP and friends) and keeps a multibyte character that is split across chunks intact. A body in a charset that is not known, or one that is refused, is decoded as UTF-8 with invalid bytes replaced by U+FFFD, the same fallback encoded words in headers get. The refused charsets are UTF-7 (and its aliases), which can carry markup past a filter that looks for `<` (`+ADw-script+AD4-` decodes to `<script>`), and the base64 and hex transfer encodings. A UTF-7 body therefore keeps its `+ADw-` sequences as literal text. The refusal applies with the `Iconv` option as well.
60
+
61
+ ### Attachment checksums
62
+
63
+ Every attachment gets a `checksum` (hex, md5 unless the `checksumAlgo` option names another algorithm `crypto.createHash()` accepts) and a `size`. Set `checksumAlgo: false` to skip hashing altogether, for example where MD5 is not available (FIPS mode) or the checksum is not used. `checksum` is then not set on the attachments, `size` still is.
64
+
34
65
  ### Limits
35
66
 
36
67
  - `simpleParser` replaces `cid:` image references in the HTML with `data:` URLs. The total length of the URLs written into the HTML is capped by the `maxInlinedImagesSize` option (default 20 MB, counted in characters of the inserted URLs). References past the cap stay as `cid:` links. The same cap applies to URLs returned from a custom `updateImageLinks()` callback.
@@ -0,0 +1,19 @@
1
+ import type { AddressObject, ParseAddressHeaderOptions } from './types.js';
2
+ /**
3
+ * Parses the value of an address header (`From`, `To`, `Cc`, `Reply-To` and the like) into the
4
+ * {@link AddressObject} `MailParser` and `simpleParser` produce for one: display names have their
5
+ * encoded words decoded, an internationalized (punycode) domain is decoded to Unicode (unless
6
+ * `decodePunycode` is false), and an
7
+ * address part that hides an encoded word is dropped unless it decodes to a plain `local@domain`
8
+ * (RFC 2047 keeps encoded words out of the address, so `=?utf-8?B?...?=@example.com` naming
9
+ * another address is not taken at its word).
10
+ *
11
+ * The value is the header value without the `Name:` prefix, as a string. Line folding may be left
12
+ * in. Raw 8-bit bytes have to be decoded into the string first, eg. `buffer.toString('utf-8')`.
13
+ * Several values (a header that occurs more than once) can be given as an array: each is parsed
14
+ * on its own and the addresses are listed in order.
15
+ *
16
+ * @param value The header value, or several of them
17
+ * @param options See {@link ParseAddressHeaderOptions}
18
+ */
19
+ export declare function parseAddressHeader(value: string | string[] | null | undefined, options?: ParseAddressHeaderOptions): AddressObject;
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.decodeAddresses = decodeAddresses;
7
+ exports.formatAddressesHTML = formatAddressesHTML;
8
+ exports.formatAddressesText = formatAddressesText;
9
+ exports.parseAddressHeader = parseAddressHeader;
10
+ const he_1 = __importDefault(require("he"));
11
+ const libmime_1 = __importDefault(require("libmime"));
12
+ const addressparser_1 = __importDefault(require("nodemailer/lib/addressparser"));
13
+ const punycode_js_1 = __importDefault(require("punycode.js"));
14
+ // An RFC 2047 encoded word
15
+ const ENCODED_WORD = /[=]\?[^?]+\?[BbQq]\?[^?]*\?[=]/;
16
+ /**
17
+ * Decodes the addresses addressparser produced, in place: encoded words in display names, an
18
+ * internationalized (punycode) domain, and the members of a group.
19
+ *
20
+ * @internal
21
+ */
22
+ function decodeAddresses(addresses, decoder = libmime_1.default, decodePunycode = true) {
23
+ for (let address of addresses) {
24
+ address.name = (address.name || '').toString().trim();
25
+ // An encoded word decodes into the display name and nothing else, whatever it
26
+ // decodes to. RFC 2047 section 5 keeps encoded words out of the addr-spec, so a
27
+ // name that decodes to "CEO" <ceo@bank.com> is still only a name: parsing it
28
+ // again would report an address the header never carried
29
+ if (address.name) {
30
+ try {
31
+ address.name = decoder.decodeWords(address.name);
32
+ }
33
+ catch {
34
+ //ignore, keep as is
35
+ }
36
+ }
37
+ // Security fix: detect RFC 2047 encoded-words in the address field.
38
+ // Per RFC 2047 Section 5, encoded-words MUST NOT appear in addr-spec.
39
+ // If found, decode and validate; reject if result is not a simple local@domain.
40
+ if (address.address && ENCODED_WORD.test(address.address)) {
41
+ try {
42
+ let decodedAddr = decoder.decodeWords(address.address);
43
+ if (/^[^\s@]+@[^\s@]+$/.test(decodedAddr) && !/[=]\?/.test(decodedAddr)) {
44
+ address.address = decodedAddr;
45
+ }
46
+ else {
47
+ address.address = '';
48
+ }
49
+ }
50
+ catch {
51
+ address.address = '';
52
+ }
53
+ }
54
+ if (decodePunycode && address.address && /@xn--/.test(address.address)) {
55
+ try {
56
+ address.address =
57
+ address.address.slice(0, address.address.lastIndexOf('@') + 1) +
58
+ punycode_js_1.default.toUnicode(address.address.slice(address.address.lastIndexOf('@') + 1));
59
+ }
60
+ catch {
61
+ // Not a valid punycode string; keep as is
62
+ }
63
+ }
64
+ if (address.group) {
65
+ decodeAddresses(address.group, decoder, decodePunycode);
66
+ }
67
+ }
68
+ }
69
+ /**
70
+ * Formats parsed addresses for an HTML context, every value HTML-escaped.
71
+ *
72
+ * @internal
73
+ */
74
+ function formatAddressesHTML(value) {
75
+ let formatSingleLevel = (addresses) => addresses
76
+ .map(address => {
77
+ let str = '<span class="mp_address_group">';
78
+ if (address.name) {
79
+ str += '<span class="mp_address_name">' + he_1.default.encode(address.name) + (address.group ? ': ' : '') + '</span>';
80
+ }
81
+ if (address.address) {
82
+ let link = '<a href="mailto:' + he_1.default.encode(address.address) + '" class="mp_address_email">' + he_1.default.encode(address.address) + '</a>';
83
+ if (address.name) {
84
+ str += ' &lt;' + link + '&gt;';
85
+ }
86
+ else {
87
+ str += link;
88
+ }
89
+ }
90
+ if (address.group) {
91
+ str += formatSingleLevel(address.group) + ';';
92
+ }
93
+ return str + '</span>';
94
+ })
95
+ .join(', ');
96
+ return formatSingleLevel([].concat(value || []));
97
+ }
98
+ /**
99
+ * Formats parsed addresses as plain text, display names quoted.
100
+ *
101
+ * @internal
102
+ */
103
+ function formatAddressesText(value) {
104
+ let formatSingleLevel = (addresses) => addresses
105
+ .map(address => {
106
+ let str = '';
107
+ if (address.name) {
108
+ // a quoted-string, so a quote or backslash inside the name is escaped
109
+ str += `"${address.name.replace(/["\\]/g, '\\$&')}"` + (address.group ? ': ' : '');
110
+ }
111
+ if (address.address) {
112
+ let link = address.address;
113
+ if (address.name) {
114
+ str += ' <' + link + '>';
115
+ }
116
+ else {
117
+ str += link;
118
+ }
119
+ }
120
+ if (address.group) {
121
+ str += formatSingleLevel(address.group) + ';';
122
+ }
123
+ return str;
124
+ })
125
+ .join(', ');
126
+ return formatSingleLevel([].concat(value || []));
127
+ }
128
+ /**
129
+ * Parses the value of an address header (`From`, `To`, `Cc`, `Reply-To` and the like) into the
130
+ * {@link AddressObject} `MailParser` and `simpleParser` produce for one: display names have their
131
+ * encoded words decoded, an internationalized (punycode) domain is decoded to Unicode (unless
132
+ * `decodePunycode` is false), and an
133
+ * address part that hides an encoded word is dropped unless it decodes to a plain `local@domain`
134
+ * (RFC 2047 keeps encoded words out of the address, so `=?utf-8?B?...?=@example.com` naming
135
+ * another address is not taken at its word).
136
+ *
137
+ * The value is the header value without the `Name:` prefix, as a string. Line folding may be left
138
+ * in. Raw 8-bit bytes have to be decoded into the string first, eg. `buffer.toString('utf-8')`.
139
+ * Several values (a header that occurs more than once) can be given as an array: each is parsed
140
+ * on its own and the addresses are listed in order.
141
+ *
142
+ * @param value The header value, or several of them
143
+ * @param options See {@link ParseAddressHeaderOptions}
144
+ */
145
+ function parseAddressHeader(value, options) {
146
+ let addresses = [];
147
+ for (let entry of [].concat(value)) {
148
+ if (typeof entry !== 'string' || !entry) {
149
+ continue;
150
+ }
151
+ let parsed = (0, addressparser_1.default)(entry, { flatten: !!options?.flatten });
152
+ decodeAddresses(parsed, libmime_1.default, options?.decodePunycode !== false);
153
+ for (let address of parsed) {
154
+ addresses.push(address);
155
+ }
156
+ }
157
+ return withLazyFormats(addresses);
158
+ }
159
+ /**
160
+ * The AddressObject for parsed addresses, with `html` and `text` built on first read: a caller
161
+ * that only wants the addresses (eg. for an SMTP envelope) pays for neither. Both stay enumerable
162
+ * and assignable, to read, compare, serialize and overwrite like the plain values they were.
163
+ */
164
+ function withLazyFormats(addresses) {
165
+ let html;
166
+ let text;
167
+ const result = { value: addresses };
168
+ Object.defineProperties(result, {
169
+ html: {
170
+ enumerable: true,
171
+ get: () => (html ??= formatAddressesHTML(addresses)),
172
+ set: value => {
173
+ html = value;
174
+ }
175
+ },
176
+ text: {
177
+ enumerable: true,
178
+ get: () => (text ??= formatAddressesText(addresses)),
179
+ set: value => {
180
+ text = value;
181
+ }
182
+ }
183
+ });
184
+ return result;
185
+ }
@@ -1,10 +1,12 @@
1
1
  import MailParser from './mail-parser.js';
2
2
  import simpleParser from './simple-parser.js';
3
- export { MailParser, simpleParser };
3
+ import { parseAddressHeader } from './address-header.js';
4
+ export { MailParser, simpleParser, parseAddressHeader };
4
5
  export type { SimpleParserCallback } from './simple-parser.js';
5
6
  export type * from './types.js';
6
7
  declare const _default: {
7
8
  MailParser: typeof MailParser;
8
9
  simpleParser: typeof simpleParser;
10
+ parseAddressHeader: typeof parseAddressHeader;
9
11
  };
10
12
  export default _default;
@@ -3,10 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.simpleParser = exports.MailParser = void 0;
6
+ exports.parseAddressHeader = exports.simpleParser = exports.MailParser = void 0;
7
7
  const mail_parser_js_1 = __importDefault(require("./mail-parser.js"));
8
8
  exports.MailParser = mail_parser_js_1.default;
9
9
  const simple_parser_js_1 = __importDefault(require("./simple-parser.js"));
10
10
  exports.simpleParser = simple_parser_js_1.default;
11
- exports.default = { MailParser: mail_parser_js_1.default, simpleParser: simple_parser_js_1.default };
11
+ const address_header_js_1 = require("./address-header.js");
12
+ Object.defineProperty(exports, "parseAddressHeader", { enumerable: true, get: function () { return address_header_js_1.parseAddressHeader; } });
13
+ exports.default = { MailParser: mail_parser_js_1.default, simpleParser: simple_parser_js_1.default, parseAddressHeader: address_header_js_1.parseAddressHeader };
12
14
  Object.defineProperty(exports, 'default', { value: exports, enumerable: false, writable: true, configurable: true });