EEmail Editor

Note (2026-03-22): Data Brain has been archived. Platform packages now consume the DatabaseAdapter interface from @marlinjai/data-table-core. Pair with @marlinjai/data-table-adapter-d1 (Cloudflare D1) or @marlinjai/data-table-adapter-prisma (PostgreSQL) as the concrete adapter.

Installation Instructions

Prerequisites

This monorepo uses pnpm for workspace management. You need to install it first.

Install pnpm

# Using npm
npm install -g pnpm

# Or using Homebrew (macOS)
brew install pnpm

# Or using curl
curl -fsSL https://get.pnpm.io/install.sh | sh -

Setup Steps

1. Install Dependencies

# From the monorepo root
pnpm install

This will install all dependencies for all packages.

2. Build All Packages

pnpm run build

This builds the editor layer (4 packages):

  • packages/core - Schema, MobX State Tree (MST) store, MJML (Mailjet Markup Language) compiler
  • packages/ui - React components
  • packages/blocks - 14 block definitions + 35 prebuilt templates
  • packages/editor - Public API

And the platform layer (8 packages):

  • packages/templates - Template CRUD, versioning, dashboard
  • packages/contacts - Contacts, CSV import, segments, merge fields
  • packages/campaigns - Campaign wizard, scheduling, A/B testing
  • packages/send-adapter-resend - Resend email provider adapter
  • packages/analytics - Tracking, heatmaps, engagement scoring
  • packages/teams - Workspaces, roles, approvals, brand kit
  • packages/shared - Cross-package infrastructure (@email-editor/shared, private and workspace-only, not published)

3. Run Example App

# From the monorepo root
pnpm -F email-editor-nextjs-example dev

Open http://localhost:3000 to see the editor.

Using the Editor in Your App

Basic Integration

pnpm add @marlinjai/email-editor @marlinjai/email-editor-core react react-dom
'use client';

import { useState } from 'react';
import { EmailEditorReact, type TemplateSnapshotOut } from '@marlinjai/email-editor/react';
import '@marlinjai/email-editor/styles.css';

function App({ initial }: { initial?: TemplateSnapshotOut }) {
  const [doc, setDoc] = useState(initial);

  // The editor fills its container, so the container needs a height.
  return (
    <div style={{ height: '80vh' }}>
      <EmailEditorReact
        initialTemplate={initial}
        onChange={setDoc}
        onRequestImage={async () => {
          const picked = await openMyMediaLibrary(); // your own picker
          return picked ? { url: picked.url, alt: picked.alt } : null;
        }}
      />
    </div>
  );
}
  • The editor is uncontrolled: initialTemplate is read once on mount. To load a different document, remount it with a new key.
  • onChange receives the whole document, debounced by 300 ms. Persist it as JSON.
  • onRequestImage is optional: it lets the image block use your own picker or uploader instead of a plain URL field. See packages/editor/README.md for its full contract.

Styles

Import @marlinjai/email-editor/styles.css once. Every rule in it is scoped under .ee-root, so it is safe beside Tailwind CSS 4 or any other host styles, and nothing in your Tailwind configuration needs to change. Brand the editor chrome with the theme prop (it sets the --ee-* design tokens), or override --ee-* tokens on .ee-root in your own CSS.

Next.js (App Router)

The editor runs in the browser only. Load it with next/dynamic and ssr: false from a 'use client' file:

'use client';

import dynamic from 'next/dynamic';
import '@marlinjai/email-editor/styles.css';

const EmailEditorReact = dynamic(
  () => import('@marlinjai/email-editor/react').then((mod) => mod.EmailEditorReact),
  { ssr: false, loading: () => <p>Loading editor...</p> }
);

In next.config.ts, keep MJML out of the server bundle:

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  serverExternalPackages: ['mjml', 'mjml-core', 'mjml-parser-xml', 'mjml-preset-core', 'mjml-validator'],
};

export default nextConfig;

transpilePackages is not needed: the packages ship compiled ECMAScript modules (ESM) and CommonJS. Compile documents on the server with migrateTemplate and createMJMLCompiler, as shown in the Integration guide.

Installing Platform Packages

The platform packages are installed individually as needed:

# Template management
pnpm install @marlinjai/email-templates

# Contact management
pnpm install @marlinjai/email-contacts

# Campaign management
pnpm install @marlinjai/email-campaigns

# Send adapter (Resend provider)
pnpm install @marlinjai/email-send-adapter-resend

# Analytics & tracking
pnpm install @marlinjai/email-analytics

# Teams & workspaces
pnpm install @marlinjai/email-teams

All platform packages consume the DatabaseAdapter interface from @marlinjai/data-table-core. Pair with @marlinjai/data-table-adapter-d1 for Cloudflare D1 or @marlinjai/data-table-adapter-prisma for PostgreSQL. See the Integration guide for setup examples.

Alternative: Use npm with Local Packages

If you prefer npm without workspaces:

  1. Build each package individually:

    cd packages/core && pnpm install && pnpm run build
    cd ../ui && pnpm install && pnpm run build
    cd ../blocks && pnpm install && pnpm run build
    cd ../editor && pnpm install && pnpm run build
  2. Link packages locally:

    cd packages/core && pnpm link --global
    cd ../ui && pnpm link --global @marlinjai/email-editor-core && pnpm link --global
    cd ../blocks && pnpm link --global @marlinjai/email-editor-core && pnpm link --global
    cd ../editor && pnpm link --global @marlinjai/email-editor-core @marlinjai/email-editor-ui @marlinjai/email-editor-blocks && pnpm link --global
  3. Run example:

    cd examples/nextjs
    pnpm link --global @marlinjai/email-editor
    pnpm run dev

Troubleshooting

"Cannot find module" errors

Make sure all packages are built:

pnpm run build

TypeScript errors

Clean and rebuild:

pnpm run clean
pnpm run build

Port already in use

Change the port in examples/nextjs:

PORT=3001 pnpm run dev

MST store not initializing

Ensure you're importing from the correct package:

// Correct - import store from core
import { createRootStore } from '@marlinjai/email-editor-core';

// Correct - use the high-level React wrapper
import { EmailEditorReact } from '@marlinjai/email-editor/react';

Development Workflow

Watch Mode

For active development, run packages in watch mode:

# Terminal 1: Watch core package
cd packages/core
pnpm run dev

# Terminal 2: Watch ui package
cd packages/ui
pnpm run dev

# Terminal 3: Run example app
cd examples/nextjs
pnpm run dev

Changes will rebuild automatically.

Running Tests

# Run all tests
pnpm run test

# Run tests in watch mode
pnpm run test:watch

Next Steps

Once installed, check out:

  1. Quick Start - Quick overview
  2. Integration - Integration patterns
  3. API Reference - API reference