EERP Suite

Getting Started with @marlinjai/email-editor

Installation

pnpm install @marlinjai/email-editor

Quick Start

React Integration

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

function App() {
  const [template, setTemplate] = useState({
    version: '1.0',
    metadata: { subject: 'My Email' },
    sections: [],
  });

  return (
    <EmailEditorReact
      value={template}
      onChange={setTemplate}
      onSave={() => console.log('Saved!', template)}
    />
  );
}

Vanilla JavaScript

import { createEditor } from '@marlinjai/email-editor';
import '@marlinjai/email-editor/styles.css';

const editor = createEditor({
  container: document.getElementById('editor'),
  initialValue: {
    version: '1.0',
    metadata: { subject: 'My Email' },
    sections: [],
  },
  onChange: (template) => {
    console.log('Template changed:', template);
  },
});

// Get compiled HTML
const html = editor.getHTML();

// Clean up
editor.destroy();

Core Concepts

EmailTemplate Structure

interface EmailTemplate {
  version: '1.0';
  metadata: {
    subject?: string;
    previewText?: string;
  };
  sections: Section[];
}

Available Blocks

Drag blocks from the left toolbar onto the canvas. The editor ships with 14 block types:

CategoryBlocks
TextText (rich text via TipTap)
MediaImage, Button, Hero, Carousel, Social
LayoutDivider, Spacer, Accordion, Navbar, Table, Raw HTML
BrandBranded Header, Branded Footer (locked)

Editing Properties

Click any block to select it. The right panel shows editable properties like colors, alignment, and text.

Undo/Redo

  • Cmd+Z (Mac) or Ctrl+Z (Windows) - Undo
  • Cmd+Shift+Z or Ctrl+Shift+Z - Redo

Device Preview

Toggle between desktop and mobile views using the icons in the canvas toolbar.

Theming

Customize the editor's appearance:

const theme = {
  colors: {
    primary: '#944923',
    surface: '#ffffff',
    text: '#1a1a1a',
    border: '#e5e5e5',
  },
  fonts: {
    heading: 'Georgia, serif',
    body: 'Georgia, serif',
  },
};

<EmailEditorReact theme={theme} ... />

Server-Side Compilation

For production use, compile MJML on the server:

// API route (Next.js example)
import { createMJMLCompiler } from '@marlinjai/email-editor-core/server';

export async function POST(request) {
  const template = await request.json();
  const compiler = createMJMLCompiler();
  const { html, mjml } = compiler.compile(template);

  return Response.json({ html, mjml });
}

Custom Blocks

Register your own custom blocks:

import { createEditor } from '@marlinjai/email-editor';

const customBlock = {
  type: 'custom',
  label: 'Custom Block',
  category: 'text',
  defaultProps: { content: 'Hello' },
  propSchema: z.object({ content: z.string() }),
  toMJML: (block) => `<mj-text>${block.content}</mj-text>`,
};

const editor = createEditor({
  container: document.getElementById('editor'),
  blocks: [customBlock],
});

Platform Integration

The platform packages extend the editor into a full email marketing solution. All platform adapters use Data Brain for storage.

Template Management

import { TemplateManager, DataBrainTemplateAdapter } from '@marlinjai/email-templates';

const adapter = new DataBrainTemplateAdapter({
  client: dataBrainClient,
  workspaceId: 'ws_123',
});

const manager = new TemplateManager({ adapter });

// Create a template
const template = await manager.create({
  name: 'Welcome Email',
  content: editorTemplate,
});

// List templates with versioning
const templates = await manager.list({ status: 'published' });

Contact Management

import { WorkspaceScopedContactManager, importCSV } from '@marlinjai/email-contacts';

const contactManager = new WorkspaceScopedContactManager({
  adapter: contactAdapter,
  workspaceId: 'ws_123',
});

// Import contacts from CSV
const result = await importCSV(csvString, {
  mapping: { email: 'Email', firstName: 'First Name' },
  adapter: contactAdapter,
});

// Evaluate segments
import { evaluateSegmentGroup } from '@marlinjai/email-contacts';
const matches = evaluateSegmentGroup(contacts, segmentRules);

Campaign Sending

import { CampaignManager } from '@marlinjai/email-campaigns';
import { ResendSendAdapter } from '@marlinjai/email-send-adapter-resend';

const sendAdapter = new ResendSendAdapter({
  apiKey: process.env.RESEND_API_KEY,
});

const campaignManager = new CampaignManager({
  adapter: campaignAdapter,
  sendAdapter,
});

// Schedule a campaign
await campaignManager.schedule({
  campaignId: 'camp_123',
  scheduledAt: new Date('2026-03-15T10:00:00Z'),
});

Analytics & Tracking

import { AnalyticsTracker, handleOpenTrack, handleClickTrack } from '@marlinjai/email-analytics';
import { injectTrackingPixel, rewriteLinksForTracking } from '@marlinjai/email-campaigns';

// Inject tracking into compiled HTML
const trackedHtml = injectTrackingPixel(html, { campaignId, contactId });
const linkedHtml = rewriteLinksForTracking(trackedHtml, { campaignId, contactId });

// Handle tracking endpoints
app.get('/track/open', (req) => handleOpenTrack(req));
app.get('/track/click', (req) => handleClickTrack(req));

// Generate heatmaps
import { generateHeatmapData } from '@marlinjai/email-analytics';
const heatmap = generateHeatmapData(clickEvents);

Teams & Workspaces

import { WorkspaceManager, ApprovalManager, BrandKitManager } from '@marlinjai/email-teams';

const workspaceManager = new WorkspaceManager({ adapter: teamsAdapter });

// Brand kit for consistent styling
const brandKit = await brandKitManager.get('ws_123');
// => { colors: [...], fonts: [...], logos: [...] }

// Approval workflows
const approval = await approvalManager.submit({
  resourceType: 'campaign',
  resourceId: 'camp_123',
  requestedBy: 'user_456',
});

Automation Sequences

import { AutomationEngine, DataBrainAutomationAdapter } from '@marlinjai/email-automation';

const engine = new AutomationEngine({
  adapter: automationAdapter,
  sendAdapter,
});

// Steps include: send_email, wait, condition, split
// Triggers include: event, schedule, manual

Shared Infrastructure

import { PlatformProvider, useDataBrain, useStorageBrain } from '@email-editor/shared';

// Wrap your app with platform context
function App() {
  return (
    <PlatformProvider
      dataBrain={{ baseUrl: '...', apiKey: '...' }}
      storageBrain={{ baseUrl: '...', apiKey: '...' }}
    >
      <Dashboard />
    </PlatformProvider>
  );
}

Next Steps