Skip to content

feat(editor): return non-prettified HTML from composeReactEmail#3538

Open
lucasfcosta wants to merge 2 commits into
resend:canaryfrom
lucasfcosta:feat/editor-expose-unformatted-html
Open

feat(editor): return non-prettified HTML from composeReactEmail#3538
lucasfcosta wants to merge 2 commits into
resend:canaryfrom
lucasfcosta:feat/editor-expose-unformatted-html

Conversation

@lucasfcosta
Copy link
Copy Markdown
Contributor

@lucasfcosta lucasfcosta commented May 25, 2026

Currently composeReactEmail returns only the Prettier-formatted HTML. For deeply-nested table-based emails (typical Stripo or Mailchimp exports), Prettier indentation accounts for ~78% of the output bytes — a 55 KB import becomes ~400 KB and pushes past Gmail's 102 KB clipping threshold, breaking open tracking and truncating content.

The compact form is already computed inside the function — it's what render() returns before pretty() runs. This PR additively exposes it as unformattedHtml. The existing html field is unchanged, so no caller breaks.

// Before
const { html, text } = await composeReactEmail({ editor });

// After (existing destructure still works)
const { html, text, unformattedHtml } = await composeReactEmail({ editor });

Measurements (deep Stripo-like input)

Bytes
Input HTML ~53 KB
render() output (= new unformattedHtml) ~57 KB
pretty() output (= existing html) ~393 KB

Notes for reviewers

  • unformattedHtml is non-optional in the return type since the value is always available.
  • No behavior change for html or text.

Summary by cubic

Expose compact, non-prettified HTML from composeReactEmail as unformattedHtml to reduce email size for nested table layouts and avoid Gmail’s 102 KB clipping. html (Prettier-formatted) and text are unchanged; additive and backward-compatible.

  • Migration
    • Use unformattedHtml when persisting or sending; keep html for source display views.

Written for commit e7dc25a. Summary will update on new commits. Review in cubic

Adds a new `unformattedHtml` field on the `composeReactEmail` result,
exposing the output of `render()` before `pretty()` runs.

For deeply-nested table-based emails (typical Stripo or Mailchimp
exports), Prettier indentation accounts for ~78% of the output bytes,
inflating a 55 KB import to ~400 KB and pushing it past Gmail's 102 KB
clipping threshold. The compact form is already computed inside the
function and was being discarded. Consumers that persist or send the
email can now opt into it without touching `html` or `text`, which
remain unchanged.
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 25, 2026

@lucasfcosta is attempting to deploy a commit to the resend Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 25, 2026

🦋 Changeset detected

Latest commit: e7dc25a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@react-email/editor Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 25, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@react-email/editor@3538

commit: e7dc25a

});

describe('unformattedHtml', () => {
it('returns the pre-pretty render() output alongside html and text', async () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a test inside of the existing describe?

Copy link
Copy Markdown
Contributor Author

@lucasfcosta lucasfcosta May 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wrapped a single test in its own describe didn't earn the extra indent. Flattened to a top-level it in e7dc25a alongside the existing top-level describes.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Auto-approved: This change additively exposes the already-computed unformatted HTML from composeReactEmail as a new field, with no modifications to existing behavior, full test coverage, and no risk of breakage.

Re-trigger cubic

…pper

A one-test describe block was overkill for the new field; flatten it to
a top-level `it` alongside the existing groupings.
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Auto-approved: The change is additive and backward-compatible, exposing an already-computed unformattedHtml field without altering existing html or text behavior, and includes a targeted test; the blast radius is limited to the serializer module with no risk to core logic, data integrity, or production...

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants