PageKit — the self-hosted GrapesJS site builder, sold as source. Get early access

Email builder for developers

Build a Drag-and-Drop Email Builder with GrapesJS

Create a visual email editor for your SaaS, CMS, marketing platform or internal tools. Let users build responsive emails with drag-and-drop blocks while your team controls components, templates, storage, output and publishing.

Drag-and-drop canvasHTML, MJML or project JSONYour database, your ESPOpen source core, BSD-3-Clause

Your users build emails visually. Your application controls the experience.

Live editor

Try the email builder

This is a real GrapesJS editor running on this page — not a video and not a screenshot. Drag a block in from the right, select anything to restyle it, switch to the phone width, then read the markup back out. The header and footer are locked, which is the same pattern the section further down explains.

What you can do here

  1. Blocks
  2. Canvas
  3. Styling
  4. Responsive
  5. Preview
  6. HTML / JSON
Definition

What is a drag-and-drop email builder?

A drag-and-drop email builder is a visual editor that lets users create email layouts from reusable components instead of manually writing HTML tables and email-specific CSS.

The difference is who has to know the rules. Without a builder, whoever writes the email needs to know that layout is done with nested tables, that most styling has to be inline, and that a stray margin can collapse the design in one client. With a builder, those rules are encoded once — by you — into blocks and components, and everyone else just arranges them.

Without a visual builder

Someone hand-writes table markup, then hand-checks it. Every new email starts from a copy of the last one.

welcome.htmlhtml
<table role="presentation" cellpadding="0" cellspacing="0" width="600">
  <tr>
    <td style="padding:32px;font-family:Arial,sans-serif">
      <h1 style="margin:0 0 12px;font-size:26px">Welcome</h1>
      <p style="margin:0;font-size:15px;line-height:1.6">Your content…</p>
    </td>
  </tr>
</table>

With a drag-and-drop builder

Someone arranges blocks. The table markup is generated from components you defined and reviewed once.

  1. Header
  2. Hero
  3. Text
  4. Image
  5. CTA
  6. Footer

The builder is not there to make email easy. It is there to make the hard parts somebody else's decision — yours, made once, at the component level.

The hard part

Why email builders are harder than website builders

A web page runs in a browser you can broadly reason about. An email runs inside whatever client the recipient opened it in, and that client may rewrite your markup, strip your styles, or lay it out with a different engine entirely. A builder for email therefore has to constrain what users can produce, not just make production pleasant.

Where your email has to survive

  • Gmail

    Web, Android and iOS apps behave differently from one another, and the web client processes your styles before rendering.

  • Outlook

    Desktop, web and the newer Windows client are effectively different renderers. Desktop builds on Windows have historically been the strictest target.

  • Apple Mail

    The most permissive of the common clients, which makes it a poor proxy: an email that looks right here can still break elsewhere.

  • Yahoo Mail

    Another webmail client with its own sanitisation rules for styles and markup.

  • Mobile clients

    Narrow viewports, aggressive text scaling, and dark-mode handling that varies by app and OS version.

  • Everything else

    Corporate gateways, regional providers and older clients that never appear in a typical test matrix.

What that forces on the builder

  • Layout is tables, not flexbox or grid

    Your columns, spacers and dividers must be table components. Users should never be able to drop a bare div into the canvas.

  • CSS support is partial and uneven

    Restrict the Style Manager to properties you have actually tested, rather than exposing the browser's full set.

  • Styles are safest inline

    Either author with a preset that inlines on export, or run an inliner in your own pipeline before the email leaves your backend.

  • Media queries are not universally honoured

    Design so the single-column fallback is already acceptable, and treat responsive rules as an improvement rather than a requirement.

  • Images are often blocked by default

    Require alt text on every image component, and never let a block depend on an image to be readable.

  • Dark mode may recolour your email

    Some clients invert or shift colours automatically. Avoid designs that depend on a specific background staying exactly that colour.

  • Web fonts frequently do not load

    Ship a real fallback stack on every text component, and check the email with the fallback rather than the intended face.

  • Scripts do not run, and interactivity is limited

    Anything dynamic belongs behind a link. A builder that offers users interactive blocks is offering them something that will not work.

  • Commercial mail carries legal requirements

    Sender identity and an unsubscribe mechanism are obligations, not design choices. Lock them into the template rather than trusting a checklist.

You are not building an editor that produces beautiful HTML. You are building an editor that cannot produce dangerous HTML.

Client behaviour changes with releases and rendering modes, so this page states no per-client support matrix. Validate against the clients and features your own audience actually uses. Last reviewed 2026-09-03.

The editing layer

Why use GrapesJS for an email builder?

GrapesJS is an open-source (BSD-3-Clause) web builder framework, currently 0.23.6, with roughly 26k+ stars on GitHub. It gives you the parts of an editor that are expensive to build and boring to differentiate on, and gets out of the way for the parts that are actually your product.

Canvas and drag-and-drop

An iframe canvas with selection, drag targets, drop indicators, resizing and a component toolbar — the interaction layer that takes months to get right and that nobody buys your product for.

Components and blocks

Define an email-safe component once, then expose it as a block users drag in. Components carry their own rules: what they accept, what can be edited, what can be styled.

Style and Trait managers

A styling panel you can restrict to the properties email actually supports, and a traits panel for the settings that are not CSS — a link target, an alt text, a merge field.

Layers and assets

A structure tree for nested tables that are hard to select by clicking, and an asset manager you can point at your own media library.

Storage Manager and project state

The whole editor state serialises to project JSON. Point the Storage Manager at your API and the editor stops caring where the data lives.

Commands and plugins

Every editor action is a named command you can call, override or add to — which is how presets, exporters and the 100+ plugins on GJS.Market extend it without a fork.

GrapesJS provides the editing layer. Your application provides the email product.

Architecture

How a drag-and-drop email builder works

One request path, from the person dragging a block to the person opening the mail. Every layer below has one owner, and most integration problems come from putting a responsibility in the wrong one.
  1. Your SaaS / application

    Your product: accounts, tenants, billing, the route the editor is mounted on.

  2. Email builder UI

    Your shell around the editor: template picker, save state, send button, approvals.

  3. GrapesJS

    The visual editing engine. It knows about components and canvases, and nothing about your users.

  4. Editor modules

    The editor subsystems you configure: which blocks exist, what they accept, what can be styled, what can be edited.

    • Blocks
    • Components
    • Styles
    • Traits
  5. Project JSON

    The serialised editor state. This is what you store so an email can be reopened later.

  6. Your backend / API

    Your API: permissions, versioning, merge-tag resolution, validation, campaign records.

  7. HTML / MJML

    The markup you actually send. Generated on demand from the stored project.

  8. Your email provider

    The provider that delivers the mail and reports what happened to it.

  9. Recipient

    The inbox, and whichever client happens to render it.

GrapesJS never talks to your database and never talks to your email provider. It hands you a document; everything after that is your architecture.

Responsibilities

Who owns what

Three owners, no overlap. The most common architectural mistake on this page's topic is expecting the editor to do something in the right-hand columns.

Your application
  • Users and accounts
  • Roles and permissions
  • Template records
  • Storage and versioning
  • Merge-tag resolution
  • Campaigns and scheduling
  • Output validation
GrapesJS
  • Visual canvas
  • Drag and drop
  • Component model
  • Block library
  • Style editing
  • Layer tree
  • Undo / redo
  • Project serialisation
Your email provider
  • Delivery
  • Bounces and complaints
  • Opens, clicks and events

Nothing in the right-hand columns is a GrapesJS gap — those rows were never the editor's job. Treating them as application work from the first sprint is what keeps the integration simple.

Output

HTML, MJML and JSON: what's the difference?

Three artefacts come out of the same canvas, and they are not interchangeable. One is the project you keep, two are the delivery formats you generate from it.

Project JSON

GrapesJS core

The editable representation of the email — components, styles, assets and pages, exactly as the editor holds them.

Best for

  • Saving work in progress
  • Reopening a template for editing
  • Duplicating and versioning
  • Diffing what changed between revisions

How you get it

editor.getProjectData()

This is the one to store. Storing only rendered HTML means the next edit starts from parsed markup rather than from the document the user built.

HTML

grapesjs-preset-newsletter

The table-based markup you hand to a sending provider, with styles inlined so more clients keep them.

Best for

  • The final email that gets sent
  • Handing to an existing pipeline
  • Maximum control over the output

How you get it

editor.runCommand('gjs-get-inlined-html')

The inlining command comes from the newsletter preset, not from the GrapesJS core. Without it you get the canvas markup and a stylesheet, which is not what you want to send.

MJML

grapesjs-mjml

A higher-level markup language for email that compiles down to responsive table HTML.

Best for

  • Authoring responsive email with less markup
  • Keeping stored source readable
  • Compiling to HTML at send time

How you get it

editor.runCommand('mjml-code')

MJML is a separate ecosystem: the editor plugin renders MJML components, and a compiler turns them into HTML. Both are third-party packages you add.

JSON is the project. HTML and MJML are the delivery. Store the first, generate the others.

From canvas to inbox

  1. Visual editor
  2. Project JSON
  3. Your database
  4. Render on send
  5. HTML
  6. Your provider
Rendering at send time rather than at save time is what lets merge tags resolve per recipient — and what lets you fix a footer across every template without re-saving them.
Components

Give users email-safe components

Do not hand users a blank canvas and a div. Ship a small set of components that already encode the table markup, the inline styles and the fallbacks, then let people arrange them. These ten cover most of what marketing and lifecycle email actually needs.

  • Header

    Logo, brand bar, preheader text. Usually locked so every email leaves with the same identity.

  • Hero

    Headline, supporting line and one action. Sized so the message survives without the image loading.

  • Text

    A paragraph block with a real font fallback stack and line height that holds up at phone widths.

  • Image

    Fixed width, explicit dimensions and required alt text, so a blocked image still leaves a readable email.

  • Button

    A table-based button rather than a styled anchor — the difference is visible in stricter clients.

  • Two-column section

    A table row that stacks on narrow viewports, with the stacked order already decided by you.

  • Product card

    Image, name, price and link, driven by fields your backend fills in rather than by copy-paste.

  • Social links

    A fixed row of icons and URLs, editable as settings rather than as markup.

  • Divider

    A rule drawn with a table border rather than an <hr> element, which several clients restyle.

  • Footer

    Sender identity, address and unsubscribe link. Usually locked, because these are obligations.

Let users design visually without requiring them to understand email HTML.

Blocks

Build emails from reusable blocks

A component is the definition; a block is how a user gets one onto the canvas. The block library is the single most powerful lever you have over what people can build — and the easiest one to get wrong by being generous.

The loop your users repeat

  1. Block library
  2. Drag to canvas
  3. Customise
  4. Save as template

An unrestricted canvas

Every element available, every style editable, no opinion about structure.

  • Users produce markup nobody reviewed
  • Support requests about one client rendering
  • Templates drift away from brand within weeks
  • No safe way to change a shared section later

A curated block library

A short list of blocks you have designed, tested and can change centrally.

  • Output stays inside markup you have validated
  • New users are productive without training
  • Brand rules live in the component, not in a document
  • Improving a block improves every email that uses it
Structure

Templates, blocks and components

Three levels, and confusing them is what makes email builders hard to grow. Components are what things are, blocks are how they get added, templates are finished starting points.

  1. Templates
  2. Blocks
  3. Components
  4. A template system your team can grow

Templates

Complete email designs

A whole email a user can start from — newsletter, receipt, onboarding step. Stored as project JSON, cloned on use.

Blocks

Reusable sections

The draggable units a template is assembled from: a hero, an article row, a CTA band, a footer.

Components

Domain-specific elements

The editable primitives inside a block, with their own traits and rules — a product card that knows it has a price.

Build the components first, then the blocks that expose them, then the templates that arrange them. Teams that start at the template level end up with dozens of near-identical designs and no way to change any of them.

A newsletter template, expanded

Newsletter template

  • ├── Header (locked)
  • ├── Hero
  • ├── Article block ×3
  • ├── CTA
  • └── Footer (locked)

Each child is a block; each block is made of components. Change the article block once and every newsletter built from this template picks it up the next time it is opened.

Guardrails

Give users freedom without letting them break the template

Locking in GrapesJS is not a mode or a plan tier — it is a set of options on a component definition. A locked region still renders, still exports, and simply refuses to be dragged, deleted or restyled in the editor.

Company header

Locked

Present in every email, identical in every email. Nobody needs to move it.

Editable content

Editable

Text and images the sender is actually here to write.

Call to action

Editable

Editable label and link, and a short list of colours — not the markup underneath.

Legal footer

Locked

Sender identity and unsubscribe link. An obligation, not a design decision.

The options that produce it

Company header
removable: false, draggable: false
Editable content
editable: true
Call to action
stylable: ['background-color', 'color']
Legal footer
removable: false, copyable: false

What this buys you

  • Brand-safe editing without a review step on every send
  • Compliance content that cannot be deleted by accident
  • A shorter Style Manager, which is also a simpler UI
  • Approved blocks that behave the same in every template
  • Central changes to shared sections without touching drafts
See the controlled no-code pattern

These options govern the editor UI. They are not authorisation. A modified project posted straight at your save endpoint is bound only by what your server validates — so validate the structure, the required regions and the permitted fields on the backend, every time.

Personalisation

Build dynamic email content

Personalised email is two separate problems: letting a user place a placeholder without knowing the syntax, and resolving that placeholder against real data at send time. The editor solves the first one. Only your application can solve the second.

Merge tags in the template

  • {{first_name}}
  • {{company_name}}
  • {{order.total}}
  • {{unsubscribe_url}}

As far as the editor is concerned these are ordinary text. They are stored exactly as written and survive save, reopen and export untouched.

How users insert them

Expose the available fields as a trait on your text component — a dropdown of “First name”, “Company”, “Order total” — and write the token into the content yourself. Users pick a field; they never learn a syntax, and they cannot invent a tag your renderer does not know.

Dynamic blocks

A block can be a placeholder for content that does not exist yet. The user drops in a product card and configures which products it should show; the values arrive when the email is rendered.

  1. 1User places a product card
  2. 2Your backend queries the catalogue at send time
  3. 3Name, price, image and URL are filled in
  4. 4The rendered HTML goes to your provider

GrapesJS provides the editing experience. Your backend resolves dynamic data and merge tags when the email is rendered or sent.

Preview

Preview emails before sending

Two widths cover almost all of the design review: the width the email is authored at, and a phone. Both are a device switch away in the editor, and neither is the same thing as testing.

Desktop600pxThe authoring width. Almost every email template is built at 600px.
Mobile375pxWhere most mail is actually opened. Check the stacked order and the tap targets.

The workflow that actually catches problems

  1. 1Preview in the editorSwitch device, toggle images off, and read the email with the fallback font. This catches structure and hierarchy problems in seconds.
  2. 2Inspect the outputRead the generated markup for anything that should not be there — a stray class, an uninlined rule, a missing alt attribute.
  3. 3Send to a seed listReal accounts on the clients your audience uses. This is the only step that shows you what recipients see.
  4. 4Add a rendering service if it earns its placeThird-party services screenshot a template across many clients at once. Worth it when you ship templates often enough that a seed list becomes the bottleneck.

An in-editor preview is your browser rendering the canvas markup. A mail client renders a transformed version of that markup through its own engine, and the two can differ. Preview is for design review; a seed list or a rendering service is for compatibility.

Validation

Validate before you send

Most email disasters are not rendering bugs. They are a broken link, an unfilled merge tag or a missing unsubscribe. All three are cheap to catch on the server, and expensive to catch in an inbox.

Content

Is the email complete?

Run before a template can move out of draft.

  • Subject line and preheader are present
  • Every image has alt text
  • Every image URL is absolute and publicly reachable
  • No placeholder copy left from the template
  • Required regions are still present in the project
Links

Does everything resolve?

Cheap to automate, and the most common single failure.

  • Every href is absolute and returns a success status
  • No mailto or tel typos
  • Tracking parameters are applied consistently
  • Every merge tag matches a field your renderer knows
  • No tag left unresolved in the rendered output
Compliance

Is it legal to send?

Non-negotiable, so enforce it in code rather than in a checklist.

  • Unsubscribe link present and functional
  • Sender identity and postal address present
  • Consent recorded for the recipients on this send
  • Locked legal footer intact in the saved project
  • Output sanitised if any part of it came from user input
Persistence

Save and restore email projects

The Storage Manager is an interface, not a database. Implement it against your own API and the editor loads, autosaves and restores through endpoints you control — which is the point at which drafts, versions and approvals become possible at all.

The lifecycle your backend defines

  1. Edit
  2. Autosave
  3. Draft
  4. Version
  5. Approved
  6. Published
storage-adapter.tsJS
// The editor hands you project JSON; your backend decides
// what a draft, a version and an approved template mean.
editor.Storage.add('email-api', {
  async load({ templateId }) {
    const res = await fetch(`/api/email-templates/${templateId}`);
    return res.json();               // -> project JSON
  },
  async store(data, { templateId }) {
    await fetch(`/api/email-templates/${templateId}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      // Authorization is enforced server-side. Never trust this call.
      body: JSON.stringify({ project: data }),
    });
  },
});

Autosave is throttled by the number of changes rather than by a timer, so a burst of edits still costs one request. Keep versions as immutable copies of the project JSON — restoring a revision then costs nothing but a load, and a bad edit stops being an incident.

Delivery

Connect your existing email infrastructure

Nothing about this architecture asks you to change how you send mail. The editor produces a document; your backend renders it and hands it to whatever provider you already pay for.

  1. 01

    GrapesJS

    Produces the project and, on request, the markup. Knows nothing about recipients.

  2. 02

    HTML / MJML

    Generated on demand from the stored project, with styles inlined or MJML compiled.

  3. 03

    Your backend

    Resolves merge tags, validates the output, records the campaign, calls the provider.

  4. 04

    Your provider

    Delivers the mail and reports bounces, complaints, opens and clicks back to you.

Examples of where your backend posts

  • Mailgun
  • Postmark
  • SendGrid

Listed alphabetically as illustrations of the last hop. Any provider with an HTTP API or SMTP endpoint fits the same shape, and swapping one for another does not touch the editor.

GrapesJS is the editor, not your email delivery service.

Neither GrapesJS nor GJS.Market ships an integration with any provider named above, and no partnership is implied. Deliverability, authentication and suppression handling remain your provider's and your application's responsibility.

send-campaign.tsts
// Server side. GrapesJS is not in this file — and that is the point.
const template = await db.emailTemplates.find(templateId);

// 1. Your application resolves merge tags. The editor never does.
const html = renderMergeTags(template.html, {
  first_name: user.firstName,
  unsubscribe_url: unsubscribeUrlFor(user),
});

// 2. Your ESP delivers it. Swap the client, keep the editor.
await esp.send({ to: user.email, subject: template.subject, html });
Build vs adopt

Should you build an email editor from scratch?

Not a judgement, a scope check. Every row is something an email builder needs. The left column is work you would own; the right is what GrapesJS gives you before you write a component.

CapabilityFrom scratchWith GrapesJS
Visual canvasBuild itAvailable
Drag and dropBuild itAvailable
Component modelBuild itAvailable
Block libraryBuild itExtensible
Style editingBuild itAvailable
Layer treeBuild itAvailable
Undo / redoBuild itAvailable
Asset managementBuild itAvailable
Storage integrationBuild itConfigurable
Custom componentsBuild itSupported
Plugin architectureBuild itSupported

“Available” means the capability ships with the core and needs configuration, not construction. It does not mean it needs no work: every serious email builder defines its own components, restricts its own styles and writes its own storage adapter. Verified against grapesjs 0.23.6 on 2026-09-03.

Build your email product, not another editor engine.

Marketplace

Extend your email builder with plugins

Real listings from the GJS.Market catalogue, grouped by the stage of the build they belong to. Names, prices and images come straight from the marketplace, so what you see here is what is actually for sale today.

Getting the email out

Export the finished document for handoff, review or an existing build pipeline.

Browse the category

Some capabilities on this page have no plugin behind them, and this section will not invent one: there is no preview or spam-check product, no CSS-inliner product, no merge-tag product and no ready-made email-template product in the catalogue. Those are described here as patterns to implement, or as work our team can do with you.

Stacks

Build your email builder stack

Four builds, assembled only from listings that exist today. Start at the row that matches what you are shipping and add the next layer when it earns its place.

Prices come from the live catalogue at build time. Free listings are marked; paid ones link straight to their product page.

Quick start

Build a drag-and-drop email builder in 5 steps

The shape of the work, in the order it makes sense to do it. Each step links to the guide that covers it properly — this page is a map, not a tutorial.

  1. 1

    Initialise the editor

    Mount GrapesJS on a container, set the two devices email needs, and turn off the default local storage before anything else.

    GrapesJS setup guide
  2. 2

    Define email components

    Write the table-based components your emails are made of, restrict what can be styled, and expose each as a block.

    Email components in depth
  3. 3

    Add templates

    Give users somewhere to start. Store templates as project JSON and clone on use rather than editing the original.

    Template systems
  4. 4

    Store projects

    Implement a storage adapter against your API so drafts, autosave and versions are yours to define.

    Storage plugins
  5. 5

    Render and send

    Generate the markup on send, resolve merge tags server-side, and hand the result to your provider.

    Get help with the build
email-editor.tsts
import grapesjs from 'grapesjs';
import newsletter from 'grapesjs-preset-newsletter';

const editor = grapesjs.init({
  container: '#email-editor',
  height: '100%',
  // Email is authored at a fixed width; give users one extra viewport
  // to check, not a full responsive breakpoint set.
  deviceManager: {
    devices: [
      { id: 'desktop', name: 'Desktop', width: '' },
      { id: 'mobile', name: 'Mobile', width: '375px' },
    ],
  },
  // Curated blocks only: the preset's table sections, plus your own.
  plugins: [
    (ed) => newsletter(ed, { inlineCss: true, showBlocksOnLoad: true }),
  ],
  // Point the editor at your API rather than the browser's localStorage.
  storageManager: {
    type: 'remote',
    autosave: true,
    stepsBeforeSave: 10,
  },
});
email-button.tsts
// An email-safe button: users edit the label and the link,
// never the table markup that makes it render in Outlook.
editor.DomComponents.addType('email-button', {
  isComponent: (el) => el.dataset?.type === 'email-button',
  model: {
    defaults: {
      draggable: '[data-gjs-type="cell"], td',
      // Users may recolour it; they may not restyle it into a div.
      stylable: ['background-color', 'color', 'border-radius'],
      traits: [
        { name: 'href', label: 'Link' },
        { name: 'label', label: 'Button text' },
      ],
      components: `
        <table role="presentation" cellpadding="0" cellspacing="0">
          <tr><td><a href="#">Read the update</a></td></tr>
        </table>`,
    },
  },
});

Both samples run against grapesjs 0.23.6. `grapesjs-preset-newsletter` and `grapesjs-mjml` are separate BSD-3-Clause packages — the core ships no email preset — so install whichever matches the output format you chose above.

Before launch

Production checklist

What separates a working demo from an email builder you can hand to customers. Everything here is your work, not the editor's.

Editor

The editing experience

What users can and cannot do.

  • Curated block library, not the default set
  • Email-safe components with restricted styles
  • Responsive editing at both device widths
  • Templates available from an empty state
  • Locked header, footer and legal regions
Data

Persistence

Nothing a user makes should be losable.

  • Project JSON persisted through your own API
  • Autosave throttled by change count
  • Immutable version history with restore
  • Backups covering the template store
  • A tested path for reopening an old project
Output

What leaves the system

Validated on the server, every time.

  • HTML or MJML output validated before send
  • Every link checked and absolute
  • Every merge tag resolvable
  • Every image URL public and permanent
  • User-supplied HTML sanitised
Email

Deliverability and law

The parts that are not about design.

  • Tested on the clients your audience uses
  • Checked on a phone, not only a desktop
  • Working unsubscribe on every send
  • Sender identity and address in the footer
  • Tracking and consent handled per jurisdiction
Security

Where email builders get compromised

An email builder accepts user-authored markup and sends it to third parties. That combination deserves more care than a typical CRUD feature.

  • Risk

    Trusting the editor's restrictions

    Locked regions, restricted styles and hidden blocks live in the browser. A crafted request can post any project it likes.

    What to do

    Validate the saved project on the server: required regions present, component types on an allowlist, fields within bounds.

  • Risk

    Sending unsanitised custom code

    A code-embed component is a feature request that arrives on every email builder, and it is an injection surface pointed at your customers' inboxes.

    What to do

    Sanitise the stored markup and re-sanitise at render. Restrict who may use a code component, and log every use of it.

  • Risk

    Accepting any uploaded file

    Uploads reached from an editor end up on public URLs that live as long as the email does.

    What to do

    Validate type and size on the server, re-encode images, and serve assets from a domain that carries no session cookies.

  • Risk

    Leaving the send endpoint under-protected

    Rendering and sending are the expensive, irreversible operations. They are usually protected less carefully than the editor route.

    What to do

    Authorise per template and per recipient list, rate-limit sends, and require a second check before anything goes to a full audience.

  • Risk

    Resolving merge tags against whatever is in scope

    A permissive template renderer will happily interpolate a field the sender was never supposed to see.

    What to do

    Resolve against an explicit allowlist of fields for that template, and fail the render on an unknown tag rather than emitting it.

Performance

Keep the email builder fast

The editor is a large dependency living inside your application. These are the levers that matter, in the order they usually pay off.

  • Load the editor lazily

    Import it only on the route that edits an email, and only in the browser. Nothing about the editor belongs in a server render or in your main bundle.

  • Lazy-load optional plugins

    A code viewer, an image editor or an MJML compiler can arrive when the user opens that panel rather than at init.

  • Keep the block library short

    Every block is markup parsed at startup and a card rendered in the palette. A curated set is faster as well as safer.

  • Debounce autosave

    Throttle by change count rather than by keystroke, so a burst of typing produces one request instead of thirty.

  • Keep project data lean

    Reference assets by URL. Base64 images inside project JSON make every load, save and version copy heavier.

  • Watch custom components

    Component logic that runs on every change is the usual cause of a canvas that feels sluggish on long emails.

No figures are quoted here on purpose: the numbers depend on your block count, your component logic and your users' hardware. Measure the editor route in your own application before and after each change.

The decision

Self-hosted email builder vs hosted platform

Now that the architecture is clear, the trade-off is easy to state. A hosted builder is faster to put in front of a customer; a builder you own is a feature of your product rather than a dependency of it.

Hosted email builder platform

An embeddable editor operated by a vendor, integrated through their API and their UI.

What you get

  • Infrastructure operated by the vendor
  • Data residency and retention depend on the provider
  • UI customisation varies by product and plan
  • Custom components vary by product and plan
  • Branding depends on the plan you are on
  • Backend integration through the vendor's API
  • Sending depends on the platform's model
  • The editor stays an external tool inside your product

Fastest route to a working editor, with the roadmap and the pricing owned by someone else.

Compare with a hosted vendor

Your GrapesJS-based builder

An open-source editing layer you configure, extend and deploy as part of your own application.

What you get

  • Infrastructure is yours, wherever you already run
  • Data stays in your database under your policies
  • The UI is your UI, down to the panels and the language
  • Custom components are ordinary application code
  • Branding is whatever your product looks like
  • Backend integration is your own architecture
  • Sending stays with the provider you already use
  • The editor is a native feature, not an embedded tool

More work up front, and an editor that grows with your product instead of around it.

Start building

Hosted platforms differ substantially from one another, which is why the left column says “depends on the provider” rather than making a blanket claim. Check the specific vendor's terms on data location, retention, customisation limits and what happens to your templates if you leave.

Integration

Use the email builder with your application stack

GrapesJS renders into a plain DOM element, so integrating it is a question of which lifecycle hook calls init and which one calls destroy. Your framework powers your application; GrapesJS powers the visual email editing layer.

Start with the GrapesJS tutorial
FAQ

Drag-and-drop email builder questions

What is a drag-and-drop email builder?

A visual editor that lets someone assemble an email from reusable components — header, text, image, button, footer — instead of hand-writing table markup and inline CSS. The rules of email HTML are encoded once, in the components, rather than learned by everyone who writes an email.

Can I build a drag-and-drop email builder with GrapesJS?

Yes. GrapesJS supplies the canvas, drag-and-drop, component model, block library, style and trait panels, layer tree, undo/redo and project serialisation. You supply the email-safe components, the templates, the storage adapter and the send pipeline.

Does GrapesJS support email editing?

The core is a general web builder framework and ships no email preset. Email support comes from plugins: grapesjs-preset-newsletter adds table-based blocks, an email-oriented Style Manager and a CSS-inlining export command, and grapesjs-mjml adds MJML components. Both are separate BSD-3-Clause packages.

Can I use MJML with GrapesJS?

Yes, through the grapesjs-mjml plugin. It renders MJML components live in the canvas using the browser build of the MJML compiler. editor.runCommand('mjml-code') returns the MJML source, and mjml-code-to-html compiles it to HTML.

Can I export HTML emails?

Yes. editor.getHtml() returns the canvas markup, and the newsletter preset adds gjs-get-inlined-html, which returns HTML with the CSS inlined — which is what you want to send. You can also inline in your own backend pipeline if you would rather keep that step server-side.

Can I store email templates in my own database?

Yes, and you should. The Storage Manager is an interface: implement load and store against your API and the editor persists project JSON to your database. Nothing is stored on any third-party service unless you choose to put it there.

Can I create custom email blocks?

Yes. Define a component type with the table markup, the traits and the style restrictions you want, then register a block that inserts it. This is the main lever you have over what users can produce, and it is ordinary application code.

Can I lock parts of an email template?

Yes, with component options such as removable: false, draggable: false, copyable: false and a restricted stylable list. Bear in mind that these govern the editor UI — your server still has to validate that a saved project contains the regions it is required to contain.

Can I use merge tags and dynamic content?

Yes. The editor treats a tag like {{first_name}} as ordinary text and stores it untouched, so you can place tags through a trait dropdown rather than making users learn syntax. Resolving those tags against real data happens in your backend at render time — GrapesJS does not do it.

Can I connect SendGrid, Mailgun or Postmark?

Your backend can, the same way it does today: generate the HTML, resolve the merge tags, call the provider's API. GrapesJS is not in that request path, and neither GrapesJS nor GJS.Market ships an integration with any of those providers.

Does GrapesJS send emails?

No. It is an editor. Delivery, bounces, complaints, suppression lists and engagement events all belong to your email service provider, and the campaign records and scheduling belong to your application.

Can I use the builder in React?

Yes. Mount the editor in an effect against a ref'd container, keep that container out of React's render path, and destroy the instance on unmount. There is an official React wrapper package if you prefer components over manual lifecycle handling.

Can I use it with Vue or Angular?

Yes. GrapesJS renders into a plain DOM element, so integration is a matter of calling init from your framework's mount hook and destroy from its teardown hook. There is no official Vue or Angular wrapper, and none is needed.

Can I white-label the email builder?

Yes. Panels, buttons, icons, the stylesheet and the editor's own interface strings are all configurable, so the editor can look and read like part of your product rather than like an embedded third-party tool.

Should I build an email editor from scratch?

Only if the editing engine itself is your product. If what you are selling is an email product — templates, campaigns, personalisation, delivery — then the canvas, drag-and-drop and component model are undifferentiated work, and adopting an existing engine leaves the budget for the parts customers actually notice.
Services

Need help building your email builder?

If you would rather have this working than research it, our team builds GrapesJS-based email editors as a service — including the parts of this page that have no plugin behind them.

  • GrapesJS integration into an existing application
  • Custom email-safe components
  • MJML integration and compilation
  • Curated block libraries
  • Storage adapters and version history
  • Template systems and starter libraries
  • Merge tags and dynamic blocks
  • White-label editor UI
  • Custom plugins
  • Publishing and approval workflows
Talk to a GrapesJS expert
Get started

Build your email builder

Give your users a visual way to create emails without forcing your development team to build an email editor from scratch.

Build

Start building with GrapesJS

Tell us what the editor has to do and get a scoped plan for the integration.

Start Building
Extend

Explore email plugins

Presets, blocks, templates, storage and asset plugins from the marketplace.

Explore Email Plugins

Your users build the emails. Your product owns the experience.