@mavogel/awscdk-rootmail 0.1.7 → 0.1.9

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 +18 -16
  167. package/renovate.json5 +59 -0
@@ -39,6 +39,7 @@ export function quoteString(value) {
39
39
  * no need to encode the values in any way. If the value is plaintext but has
40
40
  * longer lines then allowed, then use format=flowed
41
41
  *
42
+ * @param str Multi line string to check
42
43
  * @param lineLength Max line length to check for
43
44
  * @returns Returns true if there is at least one line longer than lineLength chars
44
45
  */
@@ -185,7 +186,10 @@ export function buildHeaderValue(structured) {
185
186
  }
186
187
  });
187
188
  }
188
- else if (/[\s'"\\;:/=(),<>@[\]?]|^-/.test(value)) {
189
+ else if (!value.length || /[\s'"\\;:/=(),<>@[\]?]|^-/.test(value)) {
190
+ // a parameter value is a token or a quoted-string and a token is never empty, so
191
+ // a valueless parameter such as the 'flag' of 'multipart/mixed; flag; boundary=b'
192
+ // goes out as 'flag=""' rather than as the 'flag=' that parses as neither
189
193
  paramsArray.push(param + '=' + JSON.stringify(value));
190
194
  }
191
195
  else {
@@ -207,9 +211,9 @@ export function buildHeaderValue(structured) {
207
211
  * title*0*=utf-8''unicode
208
212
  * title*1*=%20string
209
213
  *
214
+ * @param key Parameter name the generated keys are built from, for example title
210
215
  * @param data String to be encoded
211
216
  * @param [maxLength=50] Max length for generated chunks
212
- * @param [fromCharset='UTF-8'] Source sharacter set
213
217
  * @return A list of encoded keys and headers
214
218
  */
215
219
  export function buildHeaderParam(key, data, maxLength) {
@@ -336,6 +340,26 @@ export function buildHeaderParam(key, data, maxLength) {
336
340
  value: item.line
337
341
  }));
338
342
  }
343
+ /**
344
+ * An RFC 2045 token: printable ASCII without SPACE, the control characters, DEL and the
345
+ * tspecials. A charset name is one, and the name a continuation carries is written into
346
+ * the encoded word the parameter value becomes, so it is checked against this before it
347
+ * goes in. Whitespace used to come off it only because the value was trimmed first.
348
+ */
349
+ const TOKEN = /^[^\x00-\x20\x7f()<>@,;:\\"/[\]?=]+$/;
350
+ /**
351
+ * Whether a string can be a header parameter name.
352
+ *
353
+ * A parameter name is a token, so it is never empty. A "__proto__" name would target the
354
+ * prototype chain of the params object instead of an own property of it and read back as
355
+ * Object.prototype, so it is no name either.
356
+ *
357
+ * @param name Candidate parameter name, already lowercased
358
+ * @return true when the name can be used
359
+ */
360
+ function _isParamName(name) {
361
+ return !!name && !isProtoKey(name);
362
+ }
339
363
  /**
340
364
  * Parses a header value with key=value arguments into a structured
341
365
  * object.
@@ -353,137 +377,227 @@ export function buildHeaderParam(key, data, maxLength) {
353
377
  */
354
378
  export function parseHeaderValue(str) {
355
379
  const response = {
356
- value: false,
380
+ value: '',
357
381
  params: {}
358
382
  };
359
- // Parameter names come from a caller supplied contentType/contentDisposition. A
360
- // "__proto__" name would target the prototype chain of the params object instead of
361
- // an own property of it, and read back as Object.prototype, so it is dropped.
383
+ // A duplicated parameter resolves to its first occurrence, the way a duplicated header
384
+ // does. Letting the last one win disagrees with the receivers that take the first, and
385
+ // the two readings of 'boundary="b"; boundary="c"' name different delimiters. The
386
+ // continuation join below is the only writer of the name it builds, so it tests the
387
+ // name with _isParamName directly rather than taking that rule along from here.
362
388
  const setParam = (name, value) => {
363
- if (!isProtoKey(name)) {
389
+ name = name.toLowerCase();
390
+ if (_isParamName(name) && !Object.prototype.hasOwnProperty.call(response.params, name)) {
364
391
  response.params[name] = value;
365
392
  }
366
393
  };
367
394
  let key = false;
368
395
  let value = '';
369
- let type = 'value';
396
+ let stage = 'value';
370
397
  let quote = false;
371
398
  let escaped = false;
372
399
  let chr;
400
+ // Whitespace seen outside a quoted string is held back until a significant character
401
+ // follows it, so the whitespace around a value is dropped without trimming spaces the
402
+ // sender quoted on purpose. Trimming the stored value instead loses the trailing space
403
+ // of 'filename*0="Annual Report "', which the next continuation section is appended to.
404
+ let pendingSpace = '';
405
+ let quoteClosed = false;
406
+ // Whitespace ahead of the first character of a value is padding and is dropped, the
407
+ // whitespace between two characters of it is content
408
+ const flushSpace = () => {
409
+ if (value.length) {
410
+ value += pendingSpace;
411
+ }
412
+ pendingSpace = '';
413
+ };
414
+ const addChr = (c) => {
415
+ flushSpace();
416
+ value += c;
417
+ };
418
+ const takeValue = () => {
419
+ const taken = value;
420
+ value = '';
421
+ pendingSpace = '';
422
+ quoteClosed = false;
423
+ return taken;
424
+ };
425
+ const storeValue = () => {
426
+ const taken = takeValue();
427
+ if (key === false) {
428
+ response.value = taken;
429
+ }
430
+ else {
431
+ setParam(key, taken);
432
+ }
433
+ };
434
+ // A parameter name with no '=' is a valueless parameter, not the start of the next one.
435
+ // Without this the name keeps growing across the ';' and swallows whatever follows, which
436
+ // is how 'multipart/mixed; flag; boundary="AAA"' lost its boundary to a parameter named
437
+ // 'flag; boundary' and left the node declaring the generated boundary beside the asked
438
+ // for one, so a receiver reading the first of the two found no delimiter it matched.
439
+ const storeEmptyKey = () => {
440
+ setParam(takeValue().trim(), '');
441
+ };
373
442
  for (let i = 0, len = str.length; i < len; i++) {
374
443
  chr = str.charAt(i);
375
- if (type === 'key') {
444
+ if (stage === 'key') {
376
445
  if (chr === '=') {
377
- key = value.trim().toLowerCase();
378
- type = 'value';
379
- value = '';
446
+ key = takeValue().trim();
447
+ stage = 'value';
448
+ continue;
449
+ }
450
+ if (chr === ';') {
451
+ storeEmptyKey();
380
452
  continue;
381
453
  }
382
454
  value += chr;
383
455
  }
384
456
  else {
457
+ if (quoteClosed && chr !== ';') {
458
+ // Nothing behind a closed quoted string reaches the value. RFC 2045 says a
459
+ // parameter value is a token or a quoted string and not both, so what follows
460
+ // one is junk and only the ';' that ends the parameter still counts. Tested
461
+ // ahead of the branches rather than beside the append at the foot of them,
462
+ // where each branch above was a way around it: a second '"' reopened quoting
463
+ // and swallowed the rest of the header, so 'boundary="AAA" "; boundary=BBB"'
464
+ // read as a single boundary of 'AAA ', and the junk of
465
+ // 'boundary="AAA" (unterminated comment' still joined the declared boundary
466
+ // through the escape branch. quoteClosed is only ever set while no quote is
467
+ // open, and this is what keeps one from being opened afterwards.
468
+ escaped = false;
469
+ continue;
470
+ }
385
471
  if (escaped) {
386
- value += chr;
472
+ addChr(chr);
387
473
  }
388
- else if (chr === '\\') {
474
+ else if (quote && chr === '\\') {
475
+ // a backslash only escapes inside a quoted string, everywhere else it is an
476
+ // ordinary character. Treating it as an escape turns the parameter value
477
+ // 'C:\Users\me\report.txt' into 'C:Usersmereport.txt'
389
478
  escaped = true;
390
479
  continue;
391
480
  }
392
481
  else if (quote && chr === quote) {
393
482
  quote = false;
483
+ quoteClosed = true;
394
484
  }
395
485
  else if (!quote && chr === '"') {
396
486
  quote = chr;
487
+ flushSpace();
397
488
  }
398
489
  else if (!quote && chr === ';') {
399
- if (key === false) {
400
- response.value = value.trim();
401
- }
402
- else {
403
- setParam(key, value.trim());
404
- }
405
- type = 'key';
406
- value = '';
490
+ storeValue();
491
+ stage = 'key';
492
+ }
493
+ else if (!quote && (chr === ' ' || chr === '\t')) {
494
+ pendingSpace += chr;
407
495
  }
408
496
  else {
409
- value += chr;
497
+ addChr(chr);
410
498
  }
411
499
  escaped = false;
412
500
  }
413
501
  }
414
- if (type === 'value') {
415
- if (key === false) {
416
- response.value = value.trim();
417
- }
418
- else {
419
- setParam(key, value.trim());
420
- }
502
+ if (stage === 'value') {
503
+ storeValue();
421
504
  }
422
- else if (value.trim()) {
423
- setParam(value.trim().toLowerCase(), '');
505
+ else {
506
+ // a key with no value, as in 'Header-Key: somevalue; key=value; emptykey'
507
+ storeEmptyKey();
424
508
  }
425
509
  // handle parameter value continuations
426
510
  // https://tools.ietf.org/html/rfc2231#section-3
427
- // preprocess values
511
+ // Sections are collected in a list and ordered below rather than written into an array
512
+ // at their own section number. An index write makes the array as long as the number the
513
+ // header asked for, and the join that follows walks all of it, so the 55 byte value
514
+ // "attachment; filename*0*=utf-8''a; filename*4000000000=b" held a core for over two
515
+ // minutes.
516
+ const continuations = new Map();
428
517
  Object.keys(response.params).forEach(key => {
429
- let actualKey, nr, match, value;
430
- if ((match = key.match(/(\*(\d+)|\*(\d+)\*|\*)$/))) {
431
- actualKey = key.substr(0, match.index);
432
- nr = Number(match[2] || match[3]) || 0;
433
- if (isProtoKey(actualKey)) {
434
- // see setParam. Reading it back would yield Object.prototype, which is
435
- // an object, so the initializer below would be skipped and the write
436
- // that follows would throw out of a header build the caller can not catch
437
- delete response.params[key];
438
- return;
439
- }
440
- if (!response.params[actualKey] || typeof response.params[actualKey] !== 'object') {
441
- response.params[actualKey] = {
442
- charset: false,
443
- values: []
444
- };
445
- }
446
- value = response.params[key];
447
- if (nr === 0 && match[0].substr(-1) === '*' && (match = value.match(/^([^']*)'[^']*'(.*)$/))) {
448
- response.params[actualKey].charset = match[1] || 'iso-8859-1';
449
- value = match[2];
450
- }
451
- response.params[actualKey].values[nr] = value;
452
- // remove the old reference
453
- delete response.params[key];
518
+ const match = key.match(/(\*(\d+)|\*(\d+)\*|\*)$/);
519
+ if (!match) {
520
+ // not a continuation parameter, there is nothing to join
521
+ return;
522
+ }
523
+ const actualKey = key.substr(0, match.index);
524
+ const nr = Number(match[2] || match[3]) || 0;
525
+ // RFC 2231 section 4.1: only a section whose name ends in '*' is percent encoded
526
+ const encoded = match[0].substr(-1) === '*';
527
+ // remove the old reference
528
+ let value = response.params[key];
529
+ delete response.params[key];
530
+ if (!_isParamName(actualKey)) {
531
+ // the joined value can not be written back under this name. It is empty when the
532
+ // continuation suffix was all there was of it, as in the bare '*' of 'text/plain; a;*'
533
+ return;
534
+ }
535
+ let continuation = continuations.get(actualKey);
536
+ if (!continuation) {
537
+ continuation = { charset: false, sections: [] };
538
+ continuations.set(actualKey, continuation);
539
+ }
540
+ const charsetMatch = nr === 0 && encoded ? value.match(/^([^']*)'[^']*'(.*)$/) : null;
541
+ if (charsetMatch) {
542
+ // the charset is a token, and anything else named as one is no charset a consumer
543
+ // could resolve, so it reads as the unnamed case rather than being carried into
544
+ // the encoded word below. A "\r\n" of a prefix would otherwise reach a consumer
545
+ // of the parsed value as the charset of a word that no decoder can act on
546
+ continuation.charset = TOKEN.test(charsetMatch[1]) ? charsetMatch[1] : 'iso-8859-1';
547
+ value = charsetMatch[2];
454
548
  }
549
+ continuation.sections.push({ nr, value, encoded });
455
550
  });
456
551
  // concatenate split rfc2231 strings and convert encoded strings to mime encoded words
457
- Object.keys(response.params).forEach(key => {
458
- let value;
459
- if (response.params[key] && Array.isArray(response.params[key].values)) {
460
- value = response.params[key].values.map((val) => val || '').join('');
461
- if (response.params[key].charset) {
462
- // convert "%AB" to "=?charset?Q?=AB?="
463
- response.params[key] =
464
- '=?' +
465
- response.params[key].charset +
466
- '?Q?' +
467
- value
468
- // fix invalidly encoded chars
469
- .replace(/[=?_\s]/g, s => {
470
- const c = s.charCodeAt(0).toString(16);
471
- if (s === ' ') {
472
- return '_';
473
- }
474
- return '%' + (c.length < 2 ? '0' : '') + c;
475
- })
476
- // change from urlencoding to percent encoding
477
- .replace(/%/g, '=') +
478
- '?=';
479
- }
480
- else {
481
- response.params[key] = value;
482
- }
552
+ continuations.forEach((continuation, key) => {
553
+ if (Object.prototype.hasOwnProperty.call(response.params, key)) {
554
+ // The same name was also given as a plain parameter, which the starred keys were
555
+ // just deleted from around, so this write would be the only one in the function
556
+ // to override a name already taken. 'filename=plain.txt; filename*0=evil.txt'
557
+ // resolves to the plain parameter either way round, so the reading does not come
558
+ // down to which of the two spellings the sender put first
559
+ return;
560
+ }
561
+ continuation.sections.sort((a, b) => a.nr - b.nr);
562
+ if (!continuation.charset) {
563
+ // nothing said which charset the percent escapes of an encoded section are in,
564
+ // so every section is passed on as the text it already is
565
+ response.params[key] = continuation.sections.map(section => section.value).join('');
566
+ return;
483
567
  }
568
+ // convert "%AB" to "=?charset?Q?=AB?="
569
+ response.params[key] = '=?' + continuation.charset + '?Q?' + continuation.sections.map(_encodeContinuationSection).join('') + '?=';
484
570
  });
485
571
  return response;
486
572
  }
573
+ /**
574
+ * Renders one parameter value continuation section as the payload of a Q encoded word.
575
+ *
576
+ * A section whose name ends in '*' is percent encoded and its escapes carry the bytes of
577
+ * the value, so they only have to be rewritten into the "=AB" spelling a Q encoded word
578
+ * uses. A section without the '*' is literal text (RFC 2231 section 4.1), so its '%' is a
579
+ * '%' and is escaped along with the characters a Q encoded word can not carry bare.
580
+ * Decoding a literal section invents bytes that never appeared on the wire: it is how the
581
+ * value 'filename*0*=utf-8''safe; filename*1=%2F..%2F..%2Fetc%2Fpasswd' was emitted as a
582
+ * filename every receiving client reads back as 'safe/../../etc/passwd'.
583
+ *
584
+ * @param section One collected continuation section
585
+ * @return The section as Q encoded word payload
586
+ */
587
+ function _encodeContinuationSection(section) {
588
+ const specials = section.encoded ? /[=?_\s]/g : /[=?_\s%]/g;
589
+ return (section.value
590
+ // fix invalidly encoded chars
591
+ .replace(specials, s => {
592
+ const c = s.charCodeAt(0).toString(16);
593
+ if (s === ' ') {
594
+ return '_';
595
+ }
596
+ return '%' + (c.length < 2 ? '0' : '') + c;
597
+ })
598
+ // change from urlencoding to percent encoding
599
+ .replace(/%/g, '='));
600
+ }
487
601
  /**
488
602
  * Returns file extension for a content type string. If no suitable extensions
489
603
  * are found, 'bin' is used as the default extension
@@ -108,10 +108,11 @@ export interface MimeNodeEnvelope {
108
108
  }
109
109
  /**
110
110
  * Envelope as accepted by setEnvelope. Recipients are collected from to, cc and bcc, any
111
- * other field is copied to the envelope as is
111
+ * other field is copied to the envelope as is. A `from` of false is the null sender of a
112
+ * bounce message, it is sent as MAIL FROM:<>
112
113
  */
113
114
  export interface MimeNodeEnvelopeInput {
114
- from?: MimeNodeAddressInput | undefined;
115
+ from?: MimeNodeAddressInput | false | undefined;
115
116
  to?: MimeNodeAddressInput | undefined;
116
117
  cc?: MimeNodeAddressInput | undefined;
117
118
  bcc?: MimeNodeAddressInput | undefined;
@@ -327,4 +328,6 @@ declare namespace MimeNode {
327
328
  type Addresses = MimeNodeAddresses;
328
329
  type Envelope = MimeNodeEnvelope;
329
330
  }
331
+ /** The same aliases as module level exports, for `import * as MimeNode` and `import MimeNode = require()` */
332
+ export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope };
330
333
  export default MimeNode;
@@ -1256,6 +1256,7 @@ class MimeNode {
1256
1256
  *
1257
1257
  * @param addresses An array of address objects
1258
1258
  * @param [uniqueList] An array to be populated with addresses
1259
+ * @param [seenAddresses] Addresses already added to uniqueList, shared with recursive calls to keep deduplication linear
1259
1260
  * @return address string
1260
1261
  * @internal
1261
1262
  */
@@ -1393,7 +1394,7 @@ class MimeNode {
1393
1394
  /**
1394
1395
  * If needed, mime encodes the name part
1395
1396
  *
1396
- * @param name Name part of an address
1397
+ * @param value Name part of an address
1397
1398
  * @returns Mime word encoded string if needed
1398
1399
  * @internal
1399
1400
  */
@@ -1,10 +1,16 @@
1
1
  import Mail from './mailer/index.js';
2
2
  import type { MailDefaults, SentMessageInfo, Transport, TransportOptions } from './mailer/index.js';
3
+ import SMTPPool from './smtp-pool/index.js';
3
4
  import type { SMTPPoolOptions, SMTPPoolSentMessageInfo } from './smtp-pool/index.js';
5
+ import SMTPTransport from './smtp-transport/index.js';
4
6
  import type { SMTPTransportOptions, SMTPSentMessageInfo } from './smtp-transport/index.js';
7
+ import SendmailTransport from './sendmail-transport/index.js';
5
8
  import type { SendmailTransportOptions, SendmailSentMessageInfo } from './sendmail-transport/index.js';
9
+ import StreamTransport from './stream-transport/index.js';
6
10
  import type { StreamTransportOptions, StreamSentMessageInfo } from './stream-transport/index.js';
7
- import type { JSONTransportOptions, JSONSentMessageInfo } from './json-transport/index.js';
11
+ import JSONTransport from './json-transport/index.js';
12
+ import type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo } from './json-transport/index.js';
13
+ import SESTransport from './ses-transport/index.js';
8
14
  import type { SESTransportOptions, SESSentMessageInfo } from './ses-transport/index.js';
9
15
  /**
10
16
  * Connection details of a service endpoint of an Ethereal test account
@@ -43,32 +49,48 @@ export type TransportConfig = SMTPTransportOptions | SMTPPoolOptions | SendmailT
43
49
  * @param defaults Default message fields that are merged into every message
44
50
  * @returns Mail instance wrapping the transport
45
51
  */
46
- export declare function createTransport(transporter: SMTPPoolOptions & {
52
+ export declare function createTransport(transporter: SMTPPool | (SMTPPoolOptions & {
47
53
  pool: true;
48
- }, defaults?: MailDefaults): Mail<SMTPPoolSentMessageInfo>;
49
- export declare function createTransport(transporter: SendmailTransportOptions & {
54
+ }), defaults?: MailDefaults): Mail<SMTPPoolSentMessageInfo, SMTPPoolOptions>;
55
+ export declare function createTransport(transporter: SendmailTransport | (SendmailTransportOptions & {
50
56
  sendmail: true | string;
51
- }, defaults?: MailDefaults): Mail<SendmailSentMessageInfo>;
52
- export declare function createTransport(transporter: StreamTransportOptions & {
57
+ }), defaults?: MailDefaults): Mail<SendmailSentMessageInfo, SendmailTransportOptions>;
58
+ export declare function createTransport(transporter: StreamTransport | (StreamTransportOptions & {
53
59
  streamTransport: true;
54
- }, defaults?: MailDefaults): Mail<StreamSentMessageInfo>;
60
+ }), defaults?: MailDefaults): Mail<StreamSentMessageInfo, StreamTransportOptions>;
55
61
  export declare function createTransport(transporter: JSONTransportOptions & {
56
62
  jsonTransport: true;
57
- }, defaults?: MailDefaults): Mail<JSONSentMessageInfo>;
58
- export declare function createTransport(transporter: SESTransportOptions & {
63
+ skipEncoding: true;
64
+ }, defaults?: MailDefaults): Mail<JSONSentMessageObjectInfo, JSONTransportOptions>;
65
+ export declare function createTransport(transporter: JSONTransport | (JSONTransportOptions & {
66
+ jsonTransport: true;
67
+ }), defaults?: MailDefaults): Mail<JSONSentMessageInfo, JSONTransportOptions>;
68
+ export declare function createTransport(transporter: SESTransport | (SESTransportOptions & {
59
69
  SES: object;
60
- }, defaults?: MailDefaults): Mail<SESSentMessageInfo>;
61
- export declare function createTransport<T = SentMessageInfo>(transporter: Transport<T>, defaults?: MailDefaults): Mail<T>;
62
- export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail<SMTPSentMessageInfo>;
63
- export declare function createTransport(transporter?: TransportConfig | Transport<any> | string, defaults?: MailDefaults): Mail<any>;
70
+ }), defaults?: MailDefaults): Mail<SESSentMessageInfo, SESTransportOptions>;
71
+ export declare function createTransport(transporter: SMTPTransport, defaults?: MailDefaults): Mail<SMTPSentMessageInfo, SMTPTransportOptions>;
72
+ export declare function createTransport<T = SentMessageInfo, D extends TransportOptions = TransportOptions>(transporter: Transport<T, D>, defaults?: MailDefaults): Mail<T, D>;
73
+ export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail<SMTPSentMessageInfo, SMTPTransportOptions>;
74
+ export declare function createTransport(transporter?: TransportConfig | Transport<any, any> | string, defaults?: MailDefaults): Mail<any, any>;
64
75
  /**
65
76
  * Creates a test account from the Ethereal service (https://ethereal.email)
66
77
  *
67
- * @param apiUrl Optional API endpoint, defaults to https://api.nodemailer.com
68
- * @param callback Callback function to run with the account object. If not set, a Promise is returned
78
+ * @param callback Callback function to run with the account object
69
79
  */
70
80
  export declare function createTestAccount(callback: TestAccountCallback): void;
81
+ /**
82
+ * Creates a test account from the Ethereal service (https://ethereal.email)
83
+ *
84
+ * @param apiUrl API endpoint, defaults to https://api.nodemailer.com
85
+ * @param callback Callback function to run with the account object
86
+ */
71
87
  export declare function createTestAccount(apiUrl: string | false | null | undefined, callback: TestAccountCallback): void;
88
+ /**
89
+ * Creates a test account from the Ethereal service (https://ethereal.email)
90
+ *
91
+ * @param [apiUrl] API endpoint, defaults to https://api.nodemailer.com
92
+ * @returns Promise that resolves with the account object
93
+ */
72
94
  export declare function createTestAccount(apiUrl?: string | false | null): Promise<TestAccount>;
73
95
  /**
74
96
  * Resolves the Ethereal web URL for a message sent through an Ethereal test account
@@ -98,5 +120,5 @@ export type { SMTPTransportOptions, SMTPSentMessageInfo };
98
120
  export type { SMTPPoolOptions, SMTPPoolSentMessageInfo };
99
121
  export type { SendmailTransportOptions, SendmailSentMessageInfo };
100
122
  export type { StreamTransportOptions, StreamSentMessageInfo };
101
- export type { JSONTransportOptions, JSONSentMessageInfo };
123
+ export type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo };
102
124
  export type { SESTransportOptions, SESSentMessageInfo };
@@ -1,3 +1,3 @@
1
1
  export declare const name = "nodemailer";
2
- export declare const version = "10.0.10";
2
+ export declare const version = "10.0.14";
3
3
  export declare const homepage = "https://nodemailer.com/";
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/build.js from package.json. Do not edit by hand.
2
2
  export const name = 'nodemailer';
3
- export const version = '10.0.10';
3
+ export const version = '10.0.14';
4
4
  export const homepage = 'https://nodemailer.com/';
@@ -175,6 +175,7 @@ const basicToDigit = function (codePoint) {
175
175
  * @see `basicToDigit()`
176
176
  * @private
177
177
  * @param digit The numeric value of a basic code point.
178
+ * @param flag Non-zero to use the uppercase form of the code point.
178
179
  * @returns The basic code point whose value (when used for
179
180
  * representing integers) is `digit`, which needs to be in the range
180
181
  * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
@@ -15,6 +15,8 @@ export interface QPEncoderOptions {
15
15
  /** Maximum length for lines, set to false to disable wrapping */
16
16
  lineLength?: number | false | undefined;
17
17
  }
18
+ /** The name @types/nodemailer used for QPEncoderOptions */
19
+ export type EncoderOptions = QPEncoderOptions;
18
20
  /**
19
21
  * Creates a transform stream for encoding data to Quoted-Printable encoding
20
22
  *
@@ -5,6 +5,8 @@ import { Transform } from 'node:stream';
5
5
  * @param buffer Buffer to convert
6
6
  * @returns Quoted-Printable encoded string
7
7
  */
8
+ // the shortest line wrap() can make progress with: a complete =XX sequence and the soft break
9
+ const MIN_LINE_LENGTH = 4;
8
10
  // usable characters that do not need encoding
9
11
  // https://tools.ietf.org/html/rfc2045#section-6.7
10
12
  const QP_RANGES = [
@@ -41,7 +43,9 @@ export function encode(buffer) {
41
43
  */
42
44
  export function wrap(str, lineLength) {
43
45
  str = (str || '').toString();
44
- lineLength = lineLength || 76;
46
+ // a line has to hold a complete =XX sequence plus the soft break, shorter lengths
47
+ // (or a negative one) would loop without consuming input
48
+ lineLength = Math.max(Number(lineLength) || 76, MIN_LINE_LENGTH);
45
49
  if (str.length <= lineLength) {
46
50
  return str;
47
51
  }
@@ -95,6 +99,11 @@ export function wrap(str, lineLength) {
95
99
  }
96
100
  }
97
101
  }
102
+ if (!line.length) {
103
+ // the trimming above emptied the line, which only happens for an incomplete
104
+ // escape at the very end of the input. Take it as is rather than loop on it
105
+ line = str.substr(pos, lineLength);
106
+ }
98
107
  if (pos + line.length < len && line.substr(-1) !== '\n') {
99
108
  if (line.length === lineLength && line.match(/[=][\da-f]{2}$/i)) {
100
109
  line = line.substr(0, line.length - 3);
@@ -64,4 +64,6 @@ declare namespace SendmailTransport {
64
64
  type MailOptions = SendMailOptions;
65
65
  type SentMessageInfo = SendmailSentMessageInfo;
66
66
  }
67
+ /** The same aliases as module level exports, for `import * as SendmailTransport` and `import SendmailTransport = require()` */
68
+ export type { SendmailTransportOptions as Options, SendMailOptions as MailOptions, SendmailSentMessageInfo as SentMessageInfo };
67
69
  export default SendmailTransport;
@@ -21,6 +21,32 @@ export interface SESTransportOptions extends TransportOptions {
21
21
  SendEmailCommand: new (input: any) => unknown;
22
22
  };
23
23
  }
24
+ /** The SESv2Client shape the transport needs */
25
+ export type SESTransportClient = SESTransportOptions['SES']['sesClient'];
26
+ /** The SendEmailCommand constructor shape the transport needs */
27
+ export type SESTransportSendEmailCommand = SESTransportOptions['SES']['SendEmailCommand'];
28
+ /**
29
+ * SendEmailCommand parameters, the shape of the `ses` message option that is merged into
30
+ * the API call. Any further SendEmailCommandInput field is accepted as well
31
+ */
32
+ export interface SESSendEmailRequest {
33
+ FromEmailAddress?: string | undefined;
34
+ Destination?: {
35
+ ToAddresses?: string[] | undefined;
36
+ CcAddresses?: string[] | undefined;
37
+ BccAddresses?: string[] | undefined;
38
+ } | undefined;
39
+ ReplyToAddresses?: string[] | undefined;
40
+ Content?: unknown;
41
+ EmailTags?: Array<{
42
+ Name?: string | undefined;
43
+ Value?: string | undefined;
44
+ }> | undefined;
45
+ ConfigurationSetName?: string | undefined;
46
+ ListManagementOptions?: unknown;
47
+ FeedbackForwardingEmailAddress?: string | undefined;
48
+ [key: string]: unknown;
49
+ }
24
50
  /**
25
51
  * The value the SES transport hands to the send callback
26
52
  */
@@ -47,7 +73,7 @@ declare class SESTransport extends EventEmitter {
47
73
  name: string;
48
74
  version: string;
49
75
  logger: Logger;
50
- constructor(options?: SESTransportOptions);
76
+ constructor(options: SESTransportOptions);
51
77
  getRegion(cb: (err: Error | null, region?: string | false) => void): void;
52
78
  /**
53
79
  * Compiles a mailcomposer message and forwards it to SES
@@ -59,9 +85,14 @@ declare class SESTransport extends EventEmitter {
59
85
  /**
60
86
  * Verifies SES configuration
61
87
  *
62
- * @param callback Callback function
88
+ * @returns Promise that resolves to true if the configuration is usable
63
89
  */
64
90
  verify(): Promise<true>;
91
+ /**
92
+ * Verifies SES configuration
93
+ *
94
+ * @param callback Callback function
95
+ */
65
96
  verify(callback: VerifyCallback): void;
66
97
  }
67
98
  /**
@@ -71,5 +102,11 @@ declare namespace SESTransport {
71
102
  type Options = SESTransportOptions;
72
103
  type MailOptions = SendMailOptions;
73
104
  type SentMessageInfo = SESSentMessageInfo;
105
+ type SESv2ClientLike = SESTransportClient;
106
+ type SendEmailCommandConstructorLike = SESTransportSendEmailCommand;
107
+ type SendEmailRequestLike = SESSendEmailRequest;
108
+ type MailSesOptions = SESSendEmailRequest;
74
109
  }
110
+ /** The same aliases as module level exports, for `import * as SESTransport` and `import SESTransport = require()` */
111
+ export type { SESTransportOptions as Options, SendMailOptions as MailOptions, SESSentMessageInfo as SentMessageInfo, SESTransportClient as SESv2ClientLike, SESTransportSendEmailCommand as SendEmailCommandConstructorLike, SESSendEmailRequest as SendEmailRequestLike, SESSendEmailRequest as MailSesOptions };
75
112
  export default SESTransport;