Skip to content

XL React Email Renderer #1768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Jun 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2ba98b7
Initial React Email Exporter Project Structure
jmarbutt Jun 18, 2025
2f34c70
Pulling in Structure for Email Schema and Example Structure
jmarbutt Jun 18, 2025
c120739
Adjusting the playground layout
jmarbutt Jun 18, 2025
9c32278
Configuring Playground to Render HTML from Exporter
jmarbutt Jun 18, 2025
5fecf71
Getting initial Rendering back on track
jmarbutt Jun 18, 2025
a31cc29
Adding Code Block
jmarbutt Jun 18, 2025
2b58db6
Setting up Numbered list items
jmarbutt Jun 18, 2025
f1987d7
Hiding Audio, Video, File from Email rendering
jmarbutt Jun 18, 2025
72abd03
Setting Styles
jmarbutt Jun 18, 2025
30e44c0
Adding Checkbox rendering
jmarbutt Jun 18, 2025
635972e
Implementing Tables
jmarbutt Jun 18, 2025
7777977
Implementing Block Quote
jmarbutt Jun 18, 2025
5b8a8a0
Removing Todo
jmarbutt Jun 18, 2025
3a4c0a4
Removing Page Break from demo, Adding Icons and Downloads for audio, …
jmarbutt Jun 19, 2025
0f092bc
Using a traditional HTML table in Email Render instead of react-email…
jmarbutt Jun 19, 2025
f5c5a63
Working on Nested Lists tracking
jmarbutt Jun 19, 2025
3396e08
Cleaning up the list logic into its own function
jmarbutt Jun 19, 2025
29ca82b
Resolving issu with extra items in list
jmarbutt Jun 19, 2025
8495168
Simplifying the nested lists function
jmarbutt Jun 19, 2025
77a8ccc
Removing unused example
jmarbutt Jun 19, 2025
5d4e126
Trying to get the test for the render
jmarbutt Jun 19, 2025
129dc4e
Removing Google Fonts
jmarbutt Jun 19, 2025
3bca787
Adding email preview
jmarbutt Jun 19, 2025
72e0dd4
Fixing unit tests
jmarbutt Jun 19, 2025
c9c2f13
Accounting for older mail clients showing table borders
jmarbutt Jun 19, 2025
89afbaf
Correcting type script for older tables
jmarbutt Jun 19, 2025
89ff0f6
Fixing Indentions
jmarbutt Jun 19, 2025
465c5a0
Fixing Snapshot capturing and updated snapshot
jmarbutt Jun 19, 2025
4568410
Updating Test
jmarbutt Jun 19, 2025
2dda9bd
Using mapTableCell
jmarbutt Jun 23, 2025
ae7027e
Updating a few commented items
jmarbutt Jun 23, 2025
ed57add
chore: reformat files
nperez0111 Jun 24, 2025
18784aa
test: add more tests
nperez0111 Jun 24, 2025
4b9fc39
refactor: rename to xl-email-exporter
nperez0111 Jun 24, 2025
3019305
docs: add docs for email export
nperez0111 Jun 24, 2025
9fcfd49
chore: rename other tsconfig files
nperez0111 Jun 24, 2025
f99fd21
chore: must please the linter
nperez0111 Jun 24, 2025
67b5368
Merge branch 'main' into feature/react-email-exporter-v2
nperez0111 Jun 24, 2025
00d1778
feat: add support for toggleListItems
nperez0111 Jun 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/pages/docs/editor-api/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"export-to-pdf": "",
"export-to-docx": "",
"export-to-odt": "",
"export-to-email": "",
"events": "",
"methods": ""
}
108 changes: 108 additions & 0 deletions docs/pages/docs/editor-api/export-to-email.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
title: Export to email
description: Export BlockNote documents to an email.
imageTitle: Export to email
path: /docs/export-to-email
---

import { Example } from "@/components/example";
import { Callout } from "nextra/components";

# Exporting blocks to email

Leveraging the [React Email](https://react.email/) library, it's possible to export BlockNote documents to email, completely client-side.

<Callout type={"info"}>
This feature is provided by the `@blocknote/xl-email-exporter`. `xl-` packages
are fully open source, but released under a copyleft license. A commercial
license for usage in closed source, proprietary products comes as part of the
[Business subscription](/pricing).
</Callout>

First, install the `@blocknote/xl-email-exporter` packages:

```bash
npm install @blocknote/xl-email-exporter
```

Then, create an instance of the `ReactEmailExporter` class. This exposes the following methods:

```typescript
import {
ReactEmailExporter,
reactEmailDefaultSchemaMappings,
} from "@blocknote/xl-email-exporter";

// Create the exporter
const exporter = new ReactEmailExporter(editor.schema, reactEmailDefaultSchemaMappings);

// Convert the blocks to a react-email document
const html = await exporter.toReactEmailDocument(editor.document);

// Use react-email to write to file:
await ReactEmail.render(html, `filename.html`);
```

See the [full example](/examples/interoperability/converting-blocks-to-react-email) with live React Email preview below:

<Example name="interoperability/converting-blocks-to-react-email" />

### Customizing the Email

`toReactEmailDocument` takes an optional `options` parameter, which allows you to customize:

- **preview**: Set the preview text for the email (can be a string or an array of strings)
- **header**: Add content to the top of the email (must be a React-Email compatible component)
- **footer**: Add content to the bottom of the email (must be a React-Email compatible component)
- **head**: Inject elements into the [Head element](https://react.email/docs/components/head)

Example usage:

```tsx
import { Text } from "@react-email/components";
const html = await exporter.toReactEmailDocument(editor.document, {
preview: "This is a preview of the email content",
header: <Text>Header</Text>,
footer: <Text>Footer</Text>,
head: <title>My email</title>,
});
```

### Custom mappings / custom schemas

The `ReactEmailExporter` constructor takes a `schema` and `mappings` parameter.
A _mapping_ defines how to convert a BlockNote schema element (a Block, Inline Content, or Style) to a React-Email element.
If you're using a [custom schema](/docs/custom-schemas) in your editor, or if you want to overwrite how default BlockNote elements are converted to React Email, you can pass your own `mappings`:

For example, use the following code in case your schema has an `extraBlock` type:

```typescript
import { ReactEmailExporter, reactEmailDefaultSchemaMappings } from "@blocknote/xl-email-exporter";
import { Text } from "@react-email/components";

new ReactEmailExporter(schema, {
blockMapping: {
...reactEmailDefaultSchemaMappings.blockMapping,
myCustomBlock: (block, exporter) => {
return <Text>My custom block</Text>;
},
},
inlineContentMapping: reactEmailDefaultSchemaMappings.inlineContentMapping,
styleMapping: reactEmailDefaultSchemaMappings.styleMapping,
});
```

### Exporter options

The `ReactEmailExporter` constructor takes an optional `options` parameter.
While conversion happens on the client-side, the default setup uses two server based resources:

```typescript
const defaultOptions = {
// a function to resolve external resources in order to avoid CORS issues
// by default, this calls a BlockNote hosted server-side proxy to resolve files
resolveFileUrl: corsProxyResolveFileUrl,
// the colors to use in the email
colors: COLORS_DEFAULT, // defaults from @blocknote/core
};
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"playground": true,
"docs": true,
"author": "jmarbutt",
"tags": [""],
"dependencies": {
"@blocknote/xl-email-exporter": "latest",
"@react-email/render": "^1.1.2"
},
"pro": true
}
Loading
Loading