diff --git a/.changeset/orange-jokes-juggle.md b/.changeset/orange-jokes-juggle.md new file mode 100644 index 0000000000..1f99c3a3c2 --- /dev/null +++ b/.changeset/orange-jokes-juggle.md @@ -0,0 +1,5 @@ +--- +"@react-email/render": patch +--- + +fix(render): strip NULL bytes from readStream output to prevent email truncation diff --git a/packages/render/src/node/read-stream.ts b/packages/render/src/node/read-stream.ts index d58e59b8e8..8c7219a8af 100644 --- a/packages/render/src/node/read-stream.ts +++ b/packages/render/src/node/read-stream.ts @@ -54,5 +54,8 @@ export const readStream = async ( }); } - return result; + // Strip NULL bytes (U+0000) that can appear when React's streaming renderer + // produces chunks that split multi-byte UTF-8 characters at chunk boundaries. + // The pretty() function already does this, but the default non-pretty path did not. + return result.replaceAll('\0', ''); }; diff --git a/packages/render/src/node/render-node.spec.tsx b/packages/render/src/node/render-node.spec.tsx index ee5893a603..d4881e44d9 100644 --- a/packages/render/src/node/render-node.spec.tsx +++ b/packages/render/src/node/render-node.spec.tsx @@ -157,6 +157,43 @@ describe('render on node environments', () => { * * @see https://github.com/resend/react-email/issues/2353 */ + // Regression test for https://github.com/resend/react-email/issues/1667 + // and https://github.com/resend/react-email/issues/1932 + // + // React's streaming renderer can produce chunks that split multi-byte UTF-8 + // characters at chunk boundaries, resulting in NULL bytes (U+0000) in the + // rendered output. Email clients treat NULL as a string terminator, causing + // emails to be truncated mid-content. + it('rendered output contains no NULL bytes with multi-byte characters', async () => { + const MultiByteTemplate = () => { + const paragraphs = Array(30) + .fill(null) + .map((_, i) => ( +
+ 段落{i}:日本語のテキストを含むメールテンプレートのテストです。 + Ärzte und Ünternehmen für Lösung und Grüße aus München. Тестовая + компания приветствует вас в нашем сервисе. 이메일 템플릿 테스트를 + 위한 한국어 텍스트입니다. +
+ )); + + return ( +