Skip to content

Migration von handgeschriebenem MJML ​

Diese Anleitung richtet sich an Teams, die E-Mail-Templates bisher in rohem MJML erstellt haben (mit Editoren wie VS Code, einem internen CLI oder einer selbstgebauten Build-Pipeline) und auf Templaticals visuellen Editor wechseln möchten.

Automatischer Importer in Entwicklung

Wir entwickeln einen automatischen @templatical/import-mjml, der ein MJML-Dokument parst und einen Templatical-TemplateContent-Baum erzeugt. Aktiv in Entwicklung. Bis er ausgeliefert ist, dokumentiert diese Seite den manuellen Weg.

MJML → Templatical ist schwerer vollständig zu automatisieren als BeeFree → Templatical, weil MJML eine echte Obermenge dessen ist, was Templaticals JSON-Baum ausdrücken kann (es lässt sich gültiges MJML schreiben, das keinen Templatical-Block-Equivalent hat). Der Importer wird die häufigen Muster abdecken und für alles außerhalb des Mappings auf HtmlBlock zurückfallen.

Was hier eigentlich passiert ​

Diese Migration ist etwas kontraintuitiv. Templaticals Renderer erzeugt MJML als Ausgabe — auf den ersten Blick sehen MJML und Templatical identisch aus. Aber:

  • MJML ist eine Markup-Sprache. Sie schreiben XML-ähnliche Tags (<mj-section>, <mj-column>, <mj-text>) und der MJML-Compiler verwandelt das in tabellenbasiertes HTML.
  • Templatical speichert Templates als JSON-Baum mit typisierten Blöcken (SectionBlock, ParagraphBlock usw.) und rendert diesen Baum beim Export zu MJML.

Um ein MJML-Template in Templatical zu bringen, müssen Sie das MJML parsen und einen äquivalenten JSON-Baum aufbauen. Dafür gibt es noch kein integriertes Werkzeug — siehe "Automatischer Importer in Entwicklung" oben.

Pfad 1 — Visuell mit dem MJML als Referenz neu aufbauen (empfohlen) ​

Haben Sie weniger als 20 MJML-Templates, ist das mit Abstand der schnellste Weg:

  1. Öffnen Sie Ihre MJML-Quelle im Editor Ihrer Wahl.
  2. Öffnen Sie den Templatical-Editor (oder den Playground) daneben.
  3. Kompilieren Sie Ihr MJML einmal zu HTML und sehen Sie es sich an — das ist Ihr visuelles Ziel.
  4. Ziehen Sie die entsprechenden Templatical-Blöcke hinein (siehe Mapping-Tabelle unten).
  5. Kopieren Sie Textinhalte direkt. Bilder über Ihre Medienbibliothek neu hosten.
  6. Bilden Sie Styling über Templaticals Design-Tokens ab, statt über inline mj-attributes.

Die meisten MJML-Templates sind in 10–20 Minuten umgezogen, sobald Sie eines oder zwei gemacht haben.

Pfad 2 — Templaticals Renderer zur Verifikation nutzen ​

Sobald Sie ein Template visuell nachgebaut haben:

ts
import { renderToMjml } from '@templatical/renderer';

const mjml = await renderToMjml(content);
// Vergleichen Sie dieses MJML mit Ihrem ursprünglichen MJML-Quelltext.

Ein Diff zwischen Original und dem von Templatical erzeugten MJML zeigt strukturelle Unterschiede. Eine sinnvolle Sanity-Prüfung vor einer Bulk-Migration.

Pfad 3 — Ein einmaliges Konvertierungs-Skript schreiben ​

Haben Sie Hunderte MJML-Templates und wollen automatische Konvertierung versuchen, bevor der offizielle Importer da ist, ist der praktische Ansatz, einen kleinen XML-/HTML-Parser zu nutzen (htmlparser2, node-html-parser), den MJML-Baum zu durchwandern und für jedes Tag Templaticals Block-Factories aufzurufen.

Hier die grobe Form:

ts
import { parse } from 'node-html-parser';
import {
  createSectionBlock,
  createTitleBlock,
  createParagraphBlock,
  createImageBlock,
  createButtonBlock,
} from '@templatical/types';
import type { TemplateContent, Block } from '@templatical/types';

function mjmlToTemplate(mjml: string): TemplateContent {
  const root = parse(mjml);
  const body = root.querySelector('mj-body');

  const blocks: Block[] = (body?.childNodes ?? [])
    .map((node) => convertNode(node))
    .filter((b): b is Block => b !== null);

  return {
    blocks,
    settings: {
      width: parseInt(body?.getAttribute('width') ?? '600'),
      backgroundColor: body?.getAttribute('background-color') ?? '#ffffff',
    },
  };
}

function convertNode(node: any): Block | null {
  switch (node.tagName?.toLowerCase()) {
    case 'mj-section':
      return convertSection(node);
    case 'mj-text':
      return convertText(node);
    // …weitere Cases — siehe Mapping-Tabelle unten
    default:
      return null; // oder Fallback auf HtmlBlock
  }
}

WARNING

Ein selbst geschriebener Parser wird Edge Cases übersehen — verschachtelte mj-wrapper, Custom Components, bedingte Tags, Includes (mj-include) und Attribut-Vererbung über mj-attributes. Lassen Sie die Konvertierung zuerst auf einer kleinen Stichprobe laufen und vergleichen Sie visuell, bevor Sie im Bulk konvertieren.

MJML-Tag-Mapping ​

MJML-TagTemplatical-BlockHinweise
mj-section (mit mj-columns)SectionBlock mit columnsMehrspaltige Layouts funktionieren gleich; Spaltenbreiten kommen aus MJMLs width-Attribut oder werden gleichmäßig verteilt.
mj-columnSection-SpalteEine Spalte hält eine Liste verschachtelter Blöcke.
mj-textParagraphBlock (oder TitleBlock bei einer Überschrift)Anhand inline-styled Heading-Level entscheiden, ob Title oder Paragraph.
mj-imageImageBlocksrc, alt, href, width, Padding.
mj-buttonButtonBlockhref, background-color, color, Schrift, Padding.
mj-dividerDividerBlockborder-color, border-width, Padding.
mj-spacerSpacerBlockheight.
mj-social (mit mj-social-element)SocialIconsBlockJedes mj-social-element → ein SocialIcon-Eintrag.
mj-navbar (mit mj-navbar-link)MenuBlockJeder Link → MenuItemData.
mj-tableTableBlock<tr>- und <td>-Zeilen/Zellen auf Templaticals Tabellen-Daten abbilden.
mj-rawHtmlBlockHTML-Pass-Through.
mj-wrapperSectionBlock (oft)Ein Wrapper ohne Spalten wird zu einer Section mit einer Spalte.
mj-hero, mj-carousel, mj-accordionHtmlBlock (Fallback)Templatical hat noch keine direkten Entsprechungen — das gerenderte HTML in einen rohen HTML-Block übernehmen oder auf den Importer warten.
mj-head-InhalteTemplate-settingsmj-title, mj-preview, mj-attributes, mj-font, mj-style mappen auf TemplateSettings.preheaderText, eigene Schriften und Theme-Overrides.

Was sich nicht automatisch übertragen lässt ​

  • mj-attributes-Defaults — MJML erlaubt globale Defaults für jedes Tag. Übertragen Sie diese in Templaticals Block-Defaults und Theme-Overrides.
  • mj-include — MJMLs Include-Direktive hat keine direkte Entsprechung. Inkludierten Inhalt während der Konvertierung inlinen.
  • Custom MJML-Components — wenn Sie eigene MJML-Komponenten registriert haben, müssen Sie sie entweder (a) als Templatical Custom Blocks implementieren oder (b) auf HtmlBlock mit dem gerenderten HTML zurückfallen.
  • Bedingte MSO-Tags innerhalb von mj-raw — bewahren Sie sie, indem Sie das ursprüngliche Markup in einen HtmlBlock packen.

Wenn diese Anleitung etwas nicht abdeckt ​

Eröffnen Sie eine Diskussion mit einem geschwärzten Ausschnitt Ihres MJMLs und was Sie erreichen wollen. Wir nutzen diese Rückmeldungen, um zu priorisieren, welche MJML-Muster der automatische Importer zuerst abdeckt.