Rendering & export

Rendering

Rendering & export

A design is JSON. To send it, render it to email-safe HTML on your server with email-craft-sdk, then hand it to any ESP.

tsrender.ts
import { renderDesign, migrateDesign } from "email-craft-sdk";

app.post("/emails/:id/render", async (req, res) => {
  const stored = await db.emails.get(req.params.id);       // { design }
  const design = migrateDesign(stored.design);             // upgrade old schemas safely

  const html = renderDesign(design, {
    fullDocument: true, // complete <html> email
    mergeTags: { first_name: req.query.name ?? "" }         // resolve tokens for this recipient
  });

  res.json({ html });   // send via Postmark / SES / SendGrid / …
});

What you can produce#

  • HTML, renderDesign(design, { fullDocument: true, mergeTags }), email-safe across clients.
  • Design JSON, export/import the raw design (Pro: editor.export_json).
  • AMP for Email, renderAmp(design, { mergeTags }), an interactive AMP4EMAIL document (see below).
  • Document (print/PDF), renderDocument(design, { pageSize }), a paged, letter/A4-width sheet the browser can "Save as PDF" (see the page/document builder below).
  • ZIP bundle, renderEmailZip(design) packs index.html, MJML, AMP, plain text, and the design JSON into one downloadable .zip (see below).
  • MJML / plain text / image / popup overlay, additional outputs from the renderer and Pro export features.

The Export menu & custom exporters#

In the editor, the toolbar Export button downloads any format, HTML, MJML, AMP, plain text, design JSON, or a ZIP bundle. Register your own formats with config.exporters: each exporter turns the design into a file (text or binary), and appears in the menu after the built-ins. Use it to add a PDF service, a CMS payload, or an ESP-specific format without forking the editor.

tsexporters.ts
import { resolveExporters, builtinExporters } from "email-craft-sdk";

const config = {
  exporters: [
    {
      id: "pdf", label: "PDF", extension: "pdf", mimeType: "application/pdf", binary: true, run: async (design) => {
        const html = renderDesign(design, { fullDocument: true });
        return await myPdfService(html);   // returns a Uint8Array
      }
    }
  ]
};
// Headless: resolveExporters(config.exporters) → [...builtins, pdf]
A custom exporter whose id matches a built-in (html, zip, …) replaces it, so you can swap in a smarter HTML/PDF pipeline while keeping the same menu.

ZIP bundle#

renderEmailZip(design) returns the raw bytes of a valid .zip containing index.html, email.mjml, email.amp.html, email.txt, design.json, and a README. The encoder is dependency-free (works in Node and the browser). In the editor it's the ZIP bundle item in the Export menu; via the ref it's editorRef.current?.editor.exportZip(({ zip }) => …).

Page & document builder#

Set config.builder to "email" (default, ~600px), "page" (wider ~1024px landing page), or "document" (letter-width ~880px with padding). It widens the canvas to match what you're building. For document output, renderDocument(design, { pageSize: "letter" | "a4" }) wraps the same blocks in a paged sheet with an @page rule and print styles, print it to PDF from the browser.

tsxdocument.tsx
<EmailEditor config={{ builder: "document" }} />

// Server / headless:
import { renderDocument } from "email-craft-sdk";
const html = renderDocument(design, { pageSize: "a4" });
Always run migrateDesign() before rendering a stored design, it safely upgrades older schema versions so old saved emails keep rendering.

AMP for Email#

renderAmp produces an AMP4EMAIL document, the interactive MIME part you send alongside the HTML fallback. Images become <amp-img> and the carousel block becomes a swipeable <amp-carousel>; the AMP boilerplate, runtime, and any component scripts are included, and all CSS moves into <style amp-custom>.

tsamp.ts
import { renderAmp } from "email-craft-sdk";

const amp = renderAmp(design, { mergeTags: { first_name: "Sam" } });
// Send as the text/x-amp-html part, with renderDesign(...) as the text/html fallback.

// In the editor: the toolbar "Copy AMP" button, or the ref, editorRef.current?.editor.exportAmp(({ amp }) => sendAmpPart(amp));
AMP4EMAIL is stricter than HTML (no !important, no <style> in the body, explicit image dimensions). MailKaro emits a structurally-valid document and stacks slides as the HTML fallback; validate the output with amphtml-validator for a given design before you rely on it in production. Gmail also requires senders to register for AMP email.

Preview vs. send#

The editor's exportHtml is a convenient preview. For production sends, render server-side with real merge-tag values so personalization is accurate.