@mavogel/awscdk-rootmail 0.1.14 → 0.1.16

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 (168) 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/checksums/package.json +3 -3
  5. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +23 -1
  6. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-es/models/CloudWatchLogsServiceException.js +1 -0
  7. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-es/models/errors.js +21 -0
  8. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/models/CloudWatchLogsServiceException.d.ts +1 -0
  9. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/models/errors.d.ts +21 -0
  10. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/ts3.4/models/CloudWatchLogsServiceException.d.ts +1 -0
  11. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-types/ts3.4/models/errors.d.ts +21 -0
  12. package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +4 -4
  13. package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +71 -1
  14. package/node_modules/@aws-sdk/client-route-53/dist-es/models/Route53ServiceException.js +1 -0
  15. package/node_modules/@aws-sdk/client-route-53/dist-es/models/errors.js +69 -0
  16. package/node_modules/@aws-sdk/client-route-53/dist-types/models/Route53ServiceException.d.ts +1 -0
  17. package/node_modules/@aws-sdk/client-route-53/dist-types/models/errors.d.ts +69 -0
  18. package/node_modules/@aws-sdk/client-route-53/dist-types/ts3.4/models/Route53ServiceException.d.ts +1 -0
  19. package/node_modules/@aws-sdk/client-route-53/dist-types/ts3.4/models/errors.d.ts +69 -0
  20. package/node_modules/@aws-sdk/client-route-53/package.json +4 -4
  21. package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +23 -1
  22. package/node_modules/@aws-sdk/client-s3/dist-es/models/S3ServiceException.js +1 -0
  23. package/node_modules/@aws-sdk/client-s3/dist-es/models/errors.js +21 -0
  24. package/node_modules/@aws-sdk/client-s3/dist-types/models/S3ServiceException.d.ts +1 -0
  25. package/node_modules/@aws-sdk/client-s3/dist-types/models/errors.d.ts +21 -0
  26. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/S3ServiceException.d.ts +1 -0
  27. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/errors.d.ts +21 -0
  28. package/node_modules/@aws-sdk/client-s3/package.json +8 -8
  29. package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +36 -1
  30. package/node_modules/@aws-sdk/client-ses/dist-es/models/SESServiceException.js +1 -0
  31. package/node_modules/@aws-sdk/client-ses/dist-es/models/errors.js +34 -0
  32. package/node_modules/@aws-sdk/client-ses/dist-types/models/SESServiceException.d.ts +1 -0
  33. package/node_modules/@aws-sdk/client-ses/dist-types/models/errors.d.ts +34 -0
  34. package/node_modules/@aws-sdk/client-ses/dist-types/ts3.4/models/SESServiceException.d.ts +1 -0
  35. package/node_modules/@aws-sdk/client-ses/dist-types/ts3.4/models/errors.d.ts +34 -0
  36. package/node_modules/@aws-sdk/client-ses/package.json +4 -4
  37. package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +142 -1
  38. package/node_modules/@aws-sdk/client-ssm/dist-es/models/SSMServiceException.js +1 -0
  39. package/node_modules/@aws-sdk/client-ssm/dist-es/models/errors.js +140 -0
  40. package/node_modules/@aws-sdk/client-ssm/dist-types/models/SSMServiceException.d.ts +1 -0
  41. package/node_modules/@aws-sdk/client-ssm/dist-types/models/errors.d.ts +140 -0
  42. package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/SSMServiceException.d.ts +1 -0
  43. package/node_modules/@aws-sdk/client-ssm/dist-types/ts3.4/models/errors.d.ts +140 -0
  44. package/node_modules/@aws-sdk/client-ssm/package.json +4 -4
  45. package/node_modules/@aws-sdk/core/package.json +3 -3
  46. package/node_modules/@aws-sdk/credential-provider-env/package.json +3 -3
  47. package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -3
  48. package/node_modules/@aws-sdk/credential-provider-ini/package.json +10 -10
  49. package/node_modules/@aws-sdk/credential-provider-login/package.json +4 -4
  50. package/node_modules/@aws-sdk/credential-provider-node/package.json +8 -8
  51. package/node_modules/@aws-sdk/credential-provider-process/package.json +3 -3
  52. package/node_modules/@aws-sdk/credential-provider-sso/package.json +5 -5
  53. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +4 -4
  54. package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +4 -4
  55. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +11 -1
  56. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +6 -1
  57. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +6 -1
  58. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +13 -1
  59. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +9 -1
  60. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/cognito-identity/models/CognitoIdentityServiceException.js +1 -0
  61. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/cognito-identity/models/errors.js +9 -0
  62. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/signin/models/SigninServiceException.js +1 -0
  63. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/signin/models/errors.js +4 -0
  64. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/sso/models/SSOServiceException.js +1 -0
  65. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/sso/models/errors.js +4 -0
  66. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/sso-oidc/models/SSOOIDCServiceException.js +1 -0
  67. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/sso-oidc/models/errors.js +11 -0
  68. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/sts/models/STSServiceException.js +1 -0
  69. package/node_modules/@aws-sdk/nested-clients/dist-es/submodules/sts/models/errors.js +7 -0
  70. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/cognito-identity/models/CognitoIdentityServiceException.d.ts +1 -0
  71. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/cognito-identity/models/errors.d.ts +9 -0
  72. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/signin/models/SigninServiceException.d.ts +1 -0
  73. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/signin/models/errors.d.ts +4 -0
  74. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso/models/SSOServiceException.d.ts +1 -0
  75. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso/models/errors.d.ts +4 -0
  76. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso-oidc/models/SSOOIDCServiceException.d.ts +1 -0
  77. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sso-oidc/models/errors.d.ts +11 -0
  78. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sts/models/STSServiceException.d.ts +1 -0
  79. package/node_modules/@aws-sdk/nested-clients/dist-types/submodules/sts/models/errors.d.ts +7 -0
  80. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/cognito-identity/models/CognitoIdentityServiceException.d.ts +1 -0
  81. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/cognito-identity/models/errors.d.ts +9 -0
  82. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/signin/models/SigninServiceException.d.ts +1 -0
  83. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/signin/models/errors.d.ts +4 -0
  84. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/sso/models/SSOServiceException.d.ts +1 -0
  85. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/sso/models/errors.d.ts +4 -0
  86. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/sso-oidc/models/SSOOIDCServiceException.d.ts +1 -0
  87. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/sso-oidc/models/errors.d.ts +11 -0
  88. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/sts/models/STSServiceException.d.ts +1 -0
  89. package/node_modules/@aws-sdk/nested-clients/dist-types/ts3.4/submodules/sts/models/errors.d.ts +7 -0
  90. package/node_modules/@aws-sdk/nested-clients/package.json +4 -4
  91. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +2 -2
  92. package/node_modules/@aws-sdk/token-providers/package.json +4 -4
  93. package/node_modules/@smithy/core/dist-cjs/submodules/client/index.js +33 -11
  94. package/node_modules/@smithy/core/dist-cjs/submodules/endpoints/index.browser.js +2 -1
  95. package/node_modules/@smithy/core/dist-cjs/submodules/endpoints/index.js +2 -1
  96. package/node_modules/@smithy/core/dist-cjs/submodules/schema/index.js +3 -0
  97. package/node_modules/@smithy/core/dist-es/submodules/client/smithy-client/exceptions.js +33 -11
  98. package/node_modules/@smithy/core/dist-es/submodules/endpoints/util-endpoints/cache/EndpointCache.js +2 -1
  99. package/node_modules/@smithy/core/dist-es/submodules/schema/TypeRegistry.js +3 -0
  100. package/node_modules/@smithy/core/dist-types/submodules/client/smithy-client/exceptions.d.ts +1 -0
  101. package/node_modules/@smithy/core/dist-types/ts3.4/submodules/client/smithy-client/exceptions.d.ts +1 -0
  102. package/node_modules/@smithy/core/package.json +1 -1
  103. package/node_modules/@smithy/signature-v4/dist-cjs/index.js +4 -1
  104. package/node_modules/@smithy/signature-v4/dist-es/getCanonicalHeaders.js +4 -1
  105. package/node_modules/@smithy/signature-v4/package.json +3 -3
  106. package/node_modules/mailparser/.release-please-manifest.json +1 -1
  107. package/node_modules/mailparser/CHANGELOG.md +7 -0
  108. package/node_modules/mailparser/package.json +2 -2
  109. package/node_modules/nodemailer/CHANGELOG.md +27 -0
  110. package/node_modules/nodemailer/dist/cjs/base64/index.d.ts +3 -0
  111. package/node_modules/nodemailer/dist/cjs/base64/index.js +80 -41
  112. package/node_modules/nodemailer/dist/cjs/dkim/index.js +43 -29
  113. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +2 -2
  114. package/node_modules/nodemailer/dist/cjs/errors.d.ts +17 -0
  115. package/node_modules/nodemailer/dist/cjs/errors.js +12 -1
  116. package/node_modules/nodemailer/dist/cjs/fetch/index.js +23 -3
  117. package/node_modules/nodemailer/dist/cjs/mailer/index.js +23 -7
  118. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +5 -0
  119. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +20 -0
  120. package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +1 -1
  121. package/node_modules/nodemailer/dist/cjs/mime-node/index.js +165 -105
  122. package/node_modules/nodemailer/dist/cjs/nodemailer.js +12 -9
  123. package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
  124. package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
  125. package/node_modules/nodemailer/dist/cjs/qp/index.d.ts +2 -0
  126. package/node_modules/nodemailer/dist/cjs/qp/index.js +103 -33
  127. package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +54 -14
  128. package/node_modules/nodemailer/dist/cjs/shared/index.d.ts +32 -1
  129. package/node_modules/nodemailer/dist/cjs/shared/index.js +212 -115
  130. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +3 -1
  131. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +88 -68
  132. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +7 -1
  133. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +348 -136
  134. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +3 -0
  135. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +7 -1
  136. package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +106 -17
  137. package/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +8 -2
  138. package/node_modules/nodemailer/dist/esm/base64/index.d.ts +3 -0
  139. package/node_modules/nodemailer/dist/esm/base64/index.js +80 -41
  140. package/node_modules/nodemailer/dist/esm/dkim/index.js +43 -29
  141. package/node_modules/nodemailer/dist/esm/dkim/message-parser.js +2 -2
  142. package/node_modules/nodemailer/dist/esm/errors.d.ts +17 -0
  143. package/node_modules/nodemailer/dist/esm/errors.js +10 -0
  144. package/node_modules/nodemailer/dist/esm/fetch/index.js +23 -3
  145. package/node_modules/nodemailer/dist/esm/mailer/index.js +23 -7
  146. package/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +5 -0
  147. package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +20 -0
  148. package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +1 -1
  149. package/node_modules/nodemailer/dist/esm/mime-node/index.js +166 -106
  150. package/node_modules/nodemailer/dist/esm/nodemailer.js +12 -9
  151. package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
  152. package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
  153. package/node_modules/nodemailer/dist/esm/qp/index.d.ts +2 -0
  154. package/node_modules/nodemailer/dist/esm/qp/index.js +103 -33
  155. package/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +54 -14
  156. package/node_modules/nodemailer/dist/esm/shared/index.d.ts +32 -1
  157. package/node_modules/nodemailer/dist/esm/shared/index.js +207 -115
  158. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +3 -1
  159. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +88 -68
  160. package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +7 -1
  161. package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +348 -136
  162. package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +3 -0
  163. package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +7 -1
  164. package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +106 -17
  165. package/node_modules/nodemailer/dist/esm/smtp-transport/index.js +8 -2
  166. package/node_modules/nodemailer/package.json +1 -1
  167. package/node_modules/uuid/package.json +17 -17
  168. package/package.json +9 -9
@@ -16,23 +16,52 @@ const QP_RANGES = [
16
16
  [0x20, 0x3c], // <SP>!"#$%&'()*+,-./0123456789:;
17
17
  [0x3e, 0x7e] // >?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
18
18
  ];
19
+ // 1 for every byte value that is written as is, see QP_RANGES
20
+ const QP_LITERAL = new Uint8Array(256);
21
+ for (let i = 0; i < 256; i++) {
22
+ QP_LITERAL[i] = checkRanges(i, QP_RANGES) ? 1 : 0;
23
+ }
24
+ const HEX_DIGITS = Buffer.from('0123456789ABCDEF', 'latin1');
25
+ const isWhitespace = (c) => c === 0x20 || c === 0x09;
19
26
  export function encode(buffer) {
20
- if (typeof buffer === 'string') {
21
- buffer = Buffer.from(buffer, 'utf-8');
22
- }
23
- let result = '';
24
- let ord;
25
- for (let i = 0, len = buffer.length; i < len; i++) {
26
- ord = buffer[i];
27
+ return encodeBytes(typeof buffer === 'string' ? Buffer.from(buffer, 'utf-8') : buffer);
28
+ }
29
+ /**
30
+ * Encodes bytes that may be followed by more input
31
+ *
32
+ * @param buffer Bytes to encode
33
+ * @param [next] The byte that follows the buffer, whitespace before it is kept literal unless it
34
+ * is a line break. Without it the buffer ends the input and its trailing whitespace is encoded
35
+ * @param [binary] Keep only CRLF pairs literal. A lone CR or LF is data, not a line break, and
36
+ * anything that rewrites line endings on the way would change it
37
+ * @param [previous] The byte before the buffer, for a buffer that starts with LF
38
+ * @returns Quoted-Printable encoded string
39
+ */
40
+ function encodeBytes(buffer, next, binary, previous) {
41
+ const len = buffer.length;
42
+ // every byte takes three characters at most
43
+ const output = Buffer.allocUnsafe(len * 3);
44
+ let pos = 0;
45
+ for (let i = 0; i < len; i++) {
46
+ const ord = buffer[i];
47
+ const following = i + 1 < len ? buffer[i + 1] : next;
48
+ const lineBreakByte = binary && (ord === 0x0d || ord === 0x0a)
49
+ ? ord === 0x0d
50
+ ? following === 0x0a
51
+ : (i > 0 ? buffer[i - 1] : previous) === 0x0d
52
+ : true;
27
53
  // if the char is in allowed range, then keep as is, unless it is a WS in the end of a line
28
- if (checkRanges(ord, QP_RANGES) &&
29
- !((ord === 0x20 || ord === 0x09) && (i === len - 1 || buffer[i + 1] === 0x0a || buffer[i + 1] === 0x0d))) {
30
- result += String.fromCharCode(ord);
54
+ if (QP_LITERAL[ord] &&
55
+ lineBreakByte &&
56
+ !(isWhitespace(ord) && (following === undefined || following === 0x0a || following === 0x0d))) {
57
+ output[pos++] = ord;
31
58
  continue;
32
59
  }
33
- result += '=' + (ord < 0x10 ? '0' : '') + ord.toString(16).toUpperCase();
60
+ output[pos++] = 0x3d; // =
61
+ output[pos++] = HEX_DIGITS[Math.floor(ord / 16)];
62
+ output[pos++] = HEX_DIGITS[ord % 16];
34
63
  }
35
- return result;
64
+ return output.toString('latin1', 0, pos);
36
65
  }
37
66
  /**
38
67
  * Adds soft line breaks to a Quoted-Printable string
@@ -143,6 +172,10 @@ function checkRanges(nr, ranges) {
143
172
  }
144
173
  return false;
145
174
  }
175
+ // Input is encoded and wrapped this many bytes at a time. wrap() works on strings, and a large
176
+ // chunk handed over at once, such as a whole Buffer attachment, would be held several times over
177
+ // as intermediate strings
178
+ const ENCODE_SLICE_SIZE = 64 * 1024;
146
179
  /**
147
180
  * Creates a transform stream for encoding data to Quoted-Printable encoding
148
181
  *
@@ -158,44 +191,81 @@ export class Encoder extends Transform {
158
191
  this.options.lineLength = this.options.lineLength || 76;
159
192
  }
160
193
  this._curLine = '';
194
+ this._remainingBytes = false;
195
+ this._lastByte = undefined;
161
196
  this.inputBytes = 0;
162
197
  this.outputBytes = 0;
163
198
  }
164
199
  /** @internal */
165
200
  _transform(chunk, encoding, done) {
166
- let qp;
167
- if (encoding !== 'buffer') {
168
- chunk = Buffer.from(chunk, encoding);
169
- }
170
- if (!chunk || !chunk.length) {
201
+ let buf = encoding !== 'buffer' ? Buffer.from(chunk, encoding) : chunk;
202
+ if (!buf || !buf.length) {
171
203
  return done();
172
204
  }
173
- this.inputBytes += chunk.length;
174
- if (this.options.lineLength) {
175
- qp = this._curLine + encode(chunk);
176
- qp = wrap(qp, this.options.lineLength);
177
- qp = qp.replace(/(^|\n)([^\n]*)$/, (match, lineBreak, lastLine) => {
178
- this._curLine = lastLine;
179
- return lineBreak;
180
- });
181
- if (qp) {
182
- this.outputBytes += qp.length;
183
- this.push(qp);
184
- }
205
+ this.inputBytes += buf.length;
206
+ if (this._remainingBytes) {
207
+ buf = Buffer.concat([this._remainingBytes, buf], this._remainingBytes.length + buf.length);
208
+ this._remainingBytes = false;
185
209
  }
186
- else {
187
- qp = encode(chunk);
188
- this.outputBytes += qp.length;
189
- this.push(qp, 'ascii');
210
+ // Whitespace is encoded when it ends a line, and the end of the input counts as one. Hold
211
+ // back the whitespace a chunk ends with until it is known what follows it, so the output
212
+ // does not depend on where the input was split
213
+ let end = buf.length;
214
+ // a binary CR can only be written once it is known whether LF follows
215
+ while (end > 0 && (isWhitespace(buf[end - 1]) || (this.options.binary && buf[end - 1] === 0x0d))) {
216
+ end--;
217
+ }
218
+ if (buf.length - end <= ENCODE_SLICE_SIZE) {
219
+ this._remainingBytes = end < buf.length ? Buffer.from(buf.subarray(end)) : false;
220
+ buf = buf.subarray(0, end);
190
221
  }
222
+ this._encodeSlices(buf);
191
223
  done();
192
224
  }
193
225
  /** @internal */
194
226
  _flush(done) {
227
+ if (this._remainingBytes) {
228
+ this._encodeSlices(this._remainingBytes);
229
+ this._remainingBytes = false;
230
+ }
195
231
  if (this._curLine) {
196
232
  this.outputBytes += this._curLine.length;
197
233
  this.push(this._curLine, 'ascii');
234
+ this._curLine = '';
198
235
  }
199
236
  done();
200
237
  }
238
+ /**
239
+ * Encodes the input in slices of ENCODE_SLICE_SIZE bytes. Each slice is told the byte that
240
+ * follows it, so a slice that ends in whitespace is encoded as if it was not split
241
+ *
242
+ * @internal
243
+ */
244
+ _encodeSlices(buf) {
245
+ for (let start = 0; start < buf.length; start += ENCODE_SLICE_SIZE) {
246
+ const end = Math.min(start + ENCODE_SLICE_SIZE, buf.length);
247
+ this._encodeSlice(buf.subarray(start, end), end < buf.length ? buf[end] : undefined);
248
+ this._lastByte = buf[end - 1];
249
+ }
250
+ }
251
+ /** @internal */
252
+ _encodeSlice(buf, next) {
253
+ let qp;
254
+ if (this.options.lineLength) {
255
+ qp = wrap(this._curLine + encodeBytes(buf, next, this.options.binary, this._lastByte), this.options.lineLength);
256
+ // the last line is kept until it is known whether it needs a soft break
257
+ const lastLF = qp.lastIndexOf('\n');
258
+ this._curLine = qp.substring(lastLF + 1);
259
+ qp = qp.substring(0, lastLF + 1);
260
+ if (qp) {
261
+ this.outputBytes += qp.length;
262
+ this.push(qp, 'ascii');
263
+ }
264
+ }
265
+ else {
266
+ qp = encodeBytes(buf, next, this.options.binary, this._lastByte);
267
+ this.outputBytes += qp.length;
268
+ this.push(qp, 'ascii');
269
+ }
270
+ }
201
271
  }
@@ -1,9 +1,12 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import { pipeline } from 'node:stream';
2
3
  import * as packageData from '../package-info.js';
3
4
  import * as shared from '../shared/index.js';
4
5
  import * as errors from '../errors.js';
5
6
  import LeWindows from '../mime-node/le-windows.js';
6
7
  import LeUnix from '../mime-node/le-unix.js';
8
+ // how long an stdin error waits for the exit code of the process before it is reported
9
+ const STDIN_ERROR_EXIT_WAIT = 1000;
7
10
  /**
8
11
  * Generates a Transport object for Sendmail
9
12
  *
@@ -101,37 +104,75 @@ class SendmailTransport {
101
104
  return callback(E);
102
105
  }
103
106
  if (sendmail) {
107
+ let stream;
108
+ // ended once the whole message was handed to stdin
109
+ const messageWritten = () => !!stream && stream.readableEnded;
110
+ // an EPIPE says less than the exit code that usually follows it, so it is only
111
+ // reported when the process exits without one
112
+ let stdinError = null;
113
+ // releases whatever the message is still being read from
114
+ const release = () => {
115
+ if (stream && !messageWritten()) {
116
+ stream.destroy();
117
+ }
118
+ };
119
+ const fail = (err) => {
120
+ release();
121
+ callback(err);
122
+ };
104
123
  sendmail.on('error', err => {
105
124
  this.logger.error({
106
125
  err,
107
126
  tnx: 'spawn',
108
127
  messageId
109
128
  }, 'Error occurred when sending message %s. %s', messageId, err.message);
110
- callback(err);
129
+ fail(err);
111
130
  });
112
- sendmail.once('exit', code => {
113
- if (!code) {
131
+ // 'close' follows 'exit' with the same arguments, it is only listened to in case the
132
+ // process ends without an 'exit' event
133
+ const onExit = (code, signal) => {
134
+ let err = null;
135
+ if (code) {
136
+ err = new Error(code === 127 ? 'Sendmail command not found, process exited with code ' + code : 'Sendmail exited with code ' + code);
137
+ }
138
+ else if (signal) {
139
+ err = new Error('Sendmail was terminated by ' + signal);
140
+ }
141
+ else if (!messageWritten()) {
142
+ // exiting with 0 before the message was written does not mean it was queued
143
+ err = new Error('Sendmail exited before the message was written');
144
+ }
145
+ else if (stdinError) {
146
+ err = stdinError;
147
+ }
148
+ if (!err) {
114
149
  return callback();
115
150
  }
116
- const err = new Error(code === 127 ? 'Sendmail command not found, process exited with code ' + code : 'Sendmail exited with code ' + code);
117
- err.code = errors.ESENDMAIL;
151
+ err.code = err.code || errors.ESENDMAIL;
118
152
  this.logger.error({
119
153
  err,
120
154
  tnx: 'stdin',
121
155
  messageId
122
156
  }, 'Error sending message %s to sendmail. %s', messageId, err.message);
123
- callback(err);
124
- });
125
- // the close listener is handed the exit code as its first argument, so a non-zero
126
- // code reaching it before the exit listener did counts as the error value
127
- sendmail.once('close', callback);
157
+ fail(err);
158
+ };
159
+ sendmail.once('exit', onExit);
160
+ sendmail.once('close', onExit);
128
161
  sendmail.stdin.on('error', err => {
129
162
  this.logger.error({
130
163
  err,
131
164
  tnx: 'stdin',
132
165
  messageId
133
166
  }, 'Error occurred when piping message %s to sendmail. %s', messageId, err.message);
134
- callback(err);
167
+ if (stdinError) {
168
+ return;
169
+ }
170
+ stdinError = err;
171
+ release();
172
+ // a process that closed its stdin normally exits right after, with a code that
173
+ // tells more than the EPIPE. Report the EPIPE if it does not
174
+ const exitTimer = setTimeout(() => fail(err), STDIN_ERROR_EXIT_WAIT);
175
+ sendmail.once('exit', () => clearTimeout(exitTimer));
135
176
  });
136
177
  const recipients = [].concat(envelope.to || []);
137
178
  if (recipients.length > 3) {
@@ -142,12 +183,11 @@ class SendmailTransport {
142
183
  messageId
143
184
  }, 'Sending message %s to <%s>', messageId, recipients.join(', '));
144
185
  const sourceStream = mail.message.createReadStream();
145
- let stream = sourceStream;
186
+ stream = sourceStream;
146
187
  if (this.options.newline) {
147
188
  // apply the transport-level line ending transform; the message-level
148
189
  // `newline` option is handled by MimeNode in createReadStream()
149
- stream = sourceStream.pipe(this.winbreak ? new LeWindows() : new LeUnix());
150
- sourceStream.once('error', err => stream.emit('error', err));
190
+ stream = pipeline(sourceStream, this.winbreak ? new LeWindows() : new LeUnix(), () => false);
151
191
  }
152
192
  stream.once('error', err => {
153
193
  this.logger.error({
@@ -1,6 +1,7 @@
1
+ import type { NodemailerError } from '../errors.js';
1
2
  import { isProtoKey, copyOwnKeys } from './objects.js';
2
3
  import os from 'node:os';
3
- import type { Readable } from 'node:stream';
4
+ import { type Readable } from 'node:stream';
4
5
  import type { OutgoingHttpHeaders } from 'node:http';
5
6
  export { isProtoKey, copyOwnKeys };
6
7
  /**
@@ -258,3 +259,33 @@ export declare const assign: (...args: ({
258
259
  [key: string]: any;
259
260
  };
260
261
  export declare const encodeXText: (str: string) => string;
262
+ /**
263
+ * Keeps the first error a content stream emits before it is read, so the error is reported
264
+ * when the stream is read instead of being thrown as unhandled. The listener stays attached
265
+ * for good, a stream that emits 'error' more than once never throws the later ones either
266
+ *
267
+ * @param stream Readable stream
268
+ */
269
+ export declare function recordStreamErrors(stream: Readable): void;
270
+ /**
271
+ * Destroys a value if it is a readable stream that was not destroyed yet
272
+ *
273
+ * @param value Any content value
274
+ */
275
+ export declare function destroyStream(value: unknown): void;
276
+ /**
277
+ * Tells why a stream can not be read from start to end anymore. A stream that ended or was
278
+ * destroyed before anyone read it would never emit 'end' to a new reader, or, when piped, would
279
+ * end the destination right away and turn into an empty value without any error
280
+ *
281
+ * @param stream Readable stream
282
+ * @returns The error the stream failed with, an ESTREAM error, or null when it can be read
283
+ */
284
+ export declare function unreadableStreamError(stream: Readable): NodemailerError | null;
285
+ /**
286
+ * Streams a stream value into a Buffer
287
+ *
288
+ * @param stream Readable stream
289
+ * @param callback Callback function with (err, value)
290
+ */
291
+ export declare function resolveStream(stream: Readable, callback: (err: Error | null, value?: Buffer) => void): void;