react-email icon indicating copy to clipboard operation
react-email copied to clipboard

<Preview> element sometimes breaks rendering when going onto two lines

Open harryblam opened this issue 9 months ago • 8 comments

Describe the Bug

When the <Preview> component from @react-email/components contains preview text spanning multiple lines (due to extra whitespace or line breaks), it seems to inject hidden filler text with nonstandard Unicode characters (including zero-width spaces and joiners). This results in email clients like Gmail and Apple mail to render the email as empty. Moving the preview text to a single line eliminates the issue.

Which package is affected (leave empty if unsure)

@react-email/components

Link to the code that reproduces this issue

https://gist.github.com/harryblam/672c2b880fc7817c4c56eca2fc745b5d

To Reproduce

When generating the emails with the below code, it breaks (i.e. sends the email with below body)

export default function Email() {
  return (
    <Html>
      <Tailwind config={config}>
        <Head />
        <Preview>
          Testing a multi line preview – This will break things!
        </Preview>
        <Body className="bg-gray-50 my-auto mx-auto font-sans text-foreground text-[16px]">
          <Container className="bg-gray-50">
            <Section className="bg-white p-8">
              <Text className="text-primary">Test</Text>

              <Heading className="text-2xl font-bold !-mb-3">
                Testing previews
              </Heading>

              <Text className="text-sm text-muted-foreground !mb-8">
                Testing testing 123
              </Text>
            </Section>
          </Container>
        </Body>
      </Tailwind>
    </Html>
  );
}

Image

Expected Behavior

When changing the preview to be on one line like so <Preview>This works fine</Preview>, the email is sending fine.

Image

What's your node version? (if relevant)

22.10.2

harryblam avatar Feb 17 '25 15:02 harryblam

How did you insert the new line exactly? I tried with the same Preview, but it doesn't seem to break it, and neither does it with lines breaks. Did you use <br> or something similar?

gabrielmfern avatar Feb 17 '25 16:02 gabrielmfern

How did you insert the new line exactly? I tried with the same Preview, but it doesn't seem to break it, and neither does it with lines breaks. Did you use <br> or something similar?

Hey, thanks for the quick reply.

I'm using the prettier vscode format on save plugin, which handles the newline for me, but I actually think that's a red herring.

As i've retested with the below (no line breaks in the preview, just longer text), and it's still broken for me.

<Html>
      <Tailwind config={config}>
        <Head />
        <Preview>Testing a longer line preview and this will break things!</Preview>
        <Body className="bg-gray-50 my-auto mx-auto font-sans text-foreground text-[16px]">
          <Container className="bg-gray-50">
            <Section className="bg-white p-8">
              <Text className="text-primary">Test</Text>

              <Heading className="text-2xl font-bold !-mb-3">
                Testing previews
              </Heading>

              <Text className="text-sm text-muted-foreground !mb-8">
                Testing testing 123
              </Text>
            </Section>
          </Container>
        </Body>
      </Tailwind>
    </Html>

For extra context, the html looks fine when opening the file in a web browser, however when embedding it in our email, is renders as blank.

Here are the broken and working html files for reference: example-html-files.zip

and we're using the below versions

    "@react-email/components": "0.0.33",
    "react-email": "3.0.7"

harryblam avatar Feb 18 '25 11:02 harryblam

Is the HTML you sent the HTML you get from rendering directly here? Seems like I can't reproduce with the JSX still, looking at in the preview server it's just fine

Also, what's your React version?

gabrielmfern avatar Feb 19 '25 12:02 gabrielmfern

Is the HTML you sent the HTML you get from rendering directly here? Seems like I can't reproduce with the JSX still, looking at in the preview server it's just fine

Also, what's your React version?

The HTML sent in that zip file is what's generated from running the export command.

We're using React 18.

I've noticed when using a preview, it's outputting some random characters in the html (see below screenshot), is that expected? Image

harryblam avatar Feb 19 '25 16:02 harryblam

@harryblam If you're referring to the [U+XXXX] characters, these are expected, the other character from your screenshot I'm not sure but probably is expected. There's only one character that might be causing this, that sometimes only React 18 inserts during rendering for some reason.

Can you test this again but with email export --pretty?

gabrielmfern avatar Feb 21 '25 12:02 gabrielmfern

@harryblam If you're referring to the [U+XXXX] characters, these are expected, the other character from your screenshot I'm not sure but probably is expected. There's only one character that might be causing this, that sometimes only React 18 inserts during rendering for some reason.

Can you test this again but with email export --pretty?

Hello again @gabrielmfern

Magically, having the --pretty in our export script now fixed the issue 🎉. No idea why but 🤷.

Thank you VERY much for your help and reactivity on this one. Much appreciated.

harryblam avatar Feb 24 '25 14:02 harryblam

I am also getting random spacing issues with React-18.

The Preview component ended up putting a lot of space before the text of the email and the subject on gmail desktop, which also started with a random period.

To remove it, I got rid of the [U+XXXX] characters from my exported email.

I do think there is a bug with the framework and, separately, the documentation is not clear enough as to whether render or export should be used. Here it is suggested that we pretty the exported html but in the documentation it states that render is the preferred method. It seems like there should be one method that is default preferred, or at least the use cases could be clearer?

Here are the two emails with and without the generated characters, there is a small difference but it had to be fixed before release:

Image

ui-mattlucas avatar Mar 03 '25 15:03 ui-mattlucas

@ui-mattlucas the recommended way is indeed render, I said for @harryblam to use pretty just to test out a theory on the reason it breaks.

Your problem also seems unrelated to this issue's. Create a separate issue for this and then we can discuss it there

gabrielmfern avatar Mar 03 '25 15:03 gabrielmfern

I’m encountering a similar issue where a \x00 character is inserted in the final HTML just before a ü. I’m using a Preview element, but the \x00 isn’t inserted there. It appears later in a Text element.

It’s difficult to provide a repository to reproduce the issue, as it seems to depend on what comes before the ü. Even a small change in the number of preceding characters can make the problem disappear. Given the complexity of my codebase, isolating the email rendering into a separate repo is tricky. I’ll keep trying, but I hope this information helps you narrow down what might be going wrong.

Edit: Updating to React 19 fixed my issue, as mentioned here.

adriencohen avatar Apr 23 '25 09:04 adriencohen

I think this might've been fixed ever since @react-email/[email protected]/@react-email/render 1.0.2, so I'm closing as completed assuming it has been fixed since there is no reproduction here. If anyone shares a reproduction failing with the same problem as the OP, we'll reopen and fix it.

gabrielmfern avatar Jul 04 '25 14:07 gabrielmfern