Skip to main content
The composeVueEmail function is the core of the editor’s email export system. It takes the editor’s document tree, walks every node and mark, calls each extension’s renderToVueEmail() method, applies theme styles, wraps everything in an email-ready template, and produces both HTML and plain text output.

Import

Signature

Parameters

Editor
required
The TipTap editor instance. The function reads the editor’s JSON document and walks through each registered extension to serialize nodes and marks.
string
Preview text shown in inbox list views before the email is opened. Leave it out to omit it.
boolean
default:"false"
Renders the email for previewing it in your app instead of sending it, which leaves out the <style> that keeps some content readable in dark-mode email clients.

Return value

Returns a Promise that resolves to an object with: The formatted HTML and the plain text are generated in parallel for performance.
Formatting can make the HTML of deeply nested table layouts several times larger, without changing how it looks. Store and send unformattedHtml, and keep html for displaying the code.

The serialization pipeline

Understanding how composeVueEmail works helps you write better custom extensions and debug rendering issues.

1. Extract document and extensions

The function reads the editor’s JSON document (via editor.getJSON()) and collects all registered extensions into a name-to-extension map for fast lookup.

2. Find the SerializerPlugin

It searches extensions for one that provides a SerializerPlugin — an interface with two methods:
  • getNodeStyles(node, depth, editor) — returns the CSSProperties for a given node
  • BaseTemplate({ previewText, children, editor, previewMode }) — wraps the serialized content in an email structure, returning VNodes
The EmailTheming extension implements this interface. If no plugin is found, styles default to {} and the built-in DefaultBaseTemplate is used.

3. Traverse the document tree

It recursively walks the ProseMirror document. For each node it:
  1. Resolves styles — calls serializerPlugin.getNodeStyles(node, depth, editor) to get theme styles, then merges any inline styles from the node’s attributes
  2. Renders unknown nodes as null — if the node type isn’t registered or isn’t an EmailNode, it returns null
  3. Renders the node — calls the extension’s renderToVueEmail() function, passing children (from recursing into child nodes), style, node, and extension
  4. Wraps with marks — iterates through the node’s marks (bold, italic, link, etc.) and wraps the rendered output with each mark’s renderToVueEmail()

4. Depth tracking

Depth starts at 0 and only increments inside list nodes (bulletList, orderedList). This enables different styling for nested vs. top-level elements — for example, paragraphs inside list items use the listParagraph theme key instead of paragraph.

5. Style resolution order

Styles are resolved in this priority (highest wins):
  1. Inline styles — styles set directly on a node via the editor (e.g., text alignment)
  2. Theme styles — styles from the active theme via getNodeStyles()
  3. Extension defaults — hardcoded styles in each extension’s renderToVueEmail()
Inside each extension’s renderer, these are typically merged:

6. Wrap in BaseTemplate

The serialized content is wrapped in a BaseTemplate that provides the email’s outer structure. The default template renders:
When EmailTheming is active, its BaseTemplate replaces the default — it adds theme-specific body/container styles and can inject global CSS via a <style> tag in the <Head>.

7. Render to HTML and plain text

The VNodes are rendered to an HTML string using the render() function of @vuemaildev/vuemail. Both the formatted HTML and a plain text version (tags stripped, text preserved) are then produced in parallel from that HTML.

Usage

Basic export

With preview text

The preview parameter sets the inbox preview snippet — the text shown before the email is opened:
Leave preview out to omit preview text entirely.

With theming

When the EmailTheming extension is in your extensions array, theme styles are automatically inlined into every node during export:

Full example with export panel

export-panel.vue
Render it inside EditorProvider or EmailEditor, so that useCurrentEditor() finds the editor.

See also

  • EmailNode — defines how nodes serialize via renderToVueEmail()
  • EmailMark — defines how marks serialize via renderToVueEmail()
  • Email Export — guide with full editor + export examples
  • Theming — how EmailTheming provides styles and templates to the serializer