Transaktionale E-Mail-Templates in Magento 2: Variablen, Layouts, Testing
AI generated
M2
di.xml
Magento 2 · E-Mail-Templates · TransportBuilder · MailHog
Transaktionale E-Mail-Templates in Magento 2
von email_templates.xml bis zum MailHog-Test

Transaktionale E-Mails entscheiden darüber, ob Kunden einer Bestellbestätigung, einer Versandmeldung oder einem Zugangslink vertrauen, und in Magento 2 hängt ihre Zuverlässigkeit von einer sauberen Registrierung über email_templates.xml, korrekt genutzten {{var}}- und {{trans}}-Direktiven sowie einer nachvollziehbaren Store-spezifischen Auflösung der E-Mail-Templates ab. Wer eigene Variablen per Plugin injiziert, Header und Footer über Layout-XML pro Store View steuert und lokal mit MailHog testet, baut robuste E-Mail-Templates statt fragiler Einzelfall-Lösungen.

18 Min. Lesezeit email_templates.xml · TransportBuilder · MailHog Magento 2.4.x · PHP 8.4

1. Transaktionale E-Mails in Magento: Einordnung und Abgrenzung

Eine transaktionale E-Mail ist in Magento 2 jede Nachricht, die als direkte Reaktion auf eine konkrete Aktion im Shop verschickt wird: Bestellbestätigung, Rechnung, Versandbenachrichtigung, Passwort-Reset oder Kontoaktivierung. Im Unterschied zum Newsletter, der über Magento_Newsletter und eine Abonnentenliste läuft, wird eine transaktionale E-Mail immer über den Magento\Framework\Mail\Template\TransportBuilder zusammengestellt und synchron oder über einen Queue-Consumer verschickt, sobald das auslösende Ereignis eintritt. Die technische Basis dafür ist in jedem Fall ein registriertes E-Mail-Template, keine Inline-Zeichenkette im PHP-Code.

Für Agenturen ist diese Unterscheidung wichtig, weil transaktionale E-Mails andere Anforderungen an Zuverlässigkeit und Nachvollziehbarkeit haben als Marketing-Mails: Eine Bestellbestätigung darf nicht in einer Warteschlange hängen bleiben, ein Passwort-Reset-Link muss innerhalb von Sekunden ankommen. Die folgenden Abschnitte behandeln deshalb ausschliesslich die E-Mail-Ebene selbst, also Registrierung, Direktiven, eigene Variablen, Layout-Steuerung, Store-Auflösung und lokales Testing von E-Mail-Templates, ohne auf die Geschäftslogik von Retouren, Rechnungs-PDFs oder Betrugsprüfung einzugehen.

2. Template-Registrierung über email_templates.xml

Jedes Modul, das eine eigene transaktionale E-Mail ausliefern will, deklariert sie in etc/email_templates.xml. Die Datei folgt dem Schema urn:magento:module:Magento_Email:etc/email_templates.xsd und definiert pro template-Knoten eine eindeutige id, ein Label für das Backend, den Dateinamen der zugehörigen .html-Datei, den Typ (html oder text) sowie die area, für die das Template gilt. Diese id ist der Schlüssel, mit dem später TransportBuilder::setTemplateIdentifier() das Template referenziert, sie taucht ausserdem als Auswahlwert in System-Konfigurationsfeldern vom Typ Magento\Config\Model\Config\Source\Email\Template auf.

Die eigentliche .html-Datei liegt unter view/frontend/email/ oder view/adminhtml/email/ für Backend-Mails und wird beim ersten Zugriff geparst, gerendert und im Template-Cache abgelegt. Wichtig für saubere E-Mail-Templates: Der Dateiname in email_templates.xml muss exakt mit dem physischen Dateinamen übereinstimmen, sonst wirft Magento beim Laden eine LocalizedException statt einer stillen Fehlanzeige. Eine zweite, oft übersehene Regel: Ändert sich nur der Inhalt der .html-Datei, reicht ein Cache-Flush, ein erneutes setup:upgrade ist für reine Textänderungen an bereits registrierten E-Mail-Templates nicht nötig.


<?xml version="1.0"?>
<!--
Registers a custom transactional email template for the frontend area.
The "id" is the unique identifier used later by TransportBuilder::setTemplateIdentifier().
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
    <template id="mironsoft_orderfollowup_email_template"
              label="Mironsoft Order Follow-up Email"
              file="order_followup.html"
              type="html"
              module="Mironsoft_EmailTemplates"
              area="frontend"/>
</config>

3. Backend-Override: E-Mail-Templates in Marketing verwalten

Unter Marketing > Communications > E-Mail-Templates kann jeder Administrator ein XML-registriertes Template laden, im WYSIWYG-Editor anpassen und als eigenständige Kopie in der Datenbank speichern. Technisch entsteht dabei eine Zeile in der Tabelle email_template, die über orig_template_code weiterhin auf die ursprüngliche id aus email_templates.xml verweist, aber eigenen Inhalt, eigene Variablen und einen eigenen Titel trägt. Diese datenbankgespeicherte Kopie hat gegenüber dem XML-Template immer Vorrang, sobald sie im relevanten Konfigurationspfad, zum Beispiel Sales Emails > Bestellung > Vorlage für Bestell-E-Mail an Kunden, ausgewählt wurde.

Der Vorteil dieses Mechanismus: Redaktionelle Änderungen an einer transaktionalen E-Mail erfordern keinen Deploy, keinen Code-Cache-Flush und keine Entwicklerressource. Der Nachteil, den Agenturen im Review beachten sollten: Datenbank-Templates werden bei einem Reindex oder Setup-Upgrade nicht automatisch mit neuen Modul-Versionen synchronisiert, sie frieren den Stand zum Zeitpunkt der Anpassung ein. Wer strukturelle Änderungen, etwa neue Variablen oder neue Directive-Logik, an einem bereits im Backend überschriebenen Template vornimmt, muss die Anpassung an beiden Orten pflegen oder die Datenbank-Kopie bewusst zurücksetzen.

4. Directive-Syntax: {{var}} und {{trans}} im Template

Innerhalb einer .html-Datei für E-Mail-Templates verarbeitet Magento den Inhalt nicht als PHP und nicht als reguläres Layout, sondern über Magento\Email\Model\Template\Filter, eine Erweiterung des generischen Template-Filters um E-Mail-spezifische Direktiven. Die Direktive {{var object.getMethod()}} gibt einen Wert direkt aus, wobei object aus den per setTemplateVars() übergebenen Variablen stammt und über Getter-Methoden oder Array-Zugriff ausgelesen werden kann, etwa {{var order.getIncrementId()}} oder {{var customer_name}}. Ohne Escaping-Filter wird der Wert roh eingefügt, weshalb bei nutzergenerierten Inhalten zusätzlich ein Escape-Filter sinnvoll ist.

Die Direktive {{trans "Text mit %platzhalter" platzhalter=$wert}} übernimmt zusätzlich die Übersetzung über die aktive Store-Sprache und erlaubt benannte Platzhalter, die zur Laufzeit ersetzt werden, ähnlich wie __() im PHP-Code, nur innerhalb des Templates. Für strukturelle Wiederverwendung existiert {{template config_path="design/email/header_template"}}, das ein weiteres, in der Systemkonfiguration hinterlegtes Template einbindet, typischerweise für Header und Footer. Wer in einer transaktionalen E-Mail bedingte Inhalte braucht, etwa einen Rabattblock nur bei gesetztem Gutschein, nutzt {{depend var}}...{{/depend}} oder {{if var}}...{{/if}}, beide werden vom selben Filter ausgewertet wie {{var}} und {{trans}}.


{{template config_path="design/email/header_template"}}

<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
    <tr>
        <td class="email-intro">
            <!-- {{trans}} handles translatable strings with named placeholders -->
            <p>{{trans "Hello %name," name=$customer_name}}</p>
            <p>{{trans "your order #%increment_id was shipped on %date." increment_id=$order.getIncrementId() date=$shipping_date}}</p>
        </td>
    </tr>
    <tr>
        <td class="email-tracking">
            <!-- {{var}} outputs a raw variable value, optionally through a filter -->
            <p><a href="{{var tracking_url}}">{{trans "Track your shipment"}}</a></p>
            <p>{{var order.getShippingDescription()}}</p>
        </td>
    </tr>
</table>

{{template config_path="design/email/footer_template"}}

5. Eigene Template-Variablen injizieren

Der naheliegende, aber unsaubere Weg, zusätzliche Daten in eine transaktionale E-Mail zu bekommen, ist das Kopieren und Anpassen einer Core-Sender-Klasse. Sauberer ist ein Plugin auf Magento\Framework\Mail\Template\TransportBuilder::setTemplateVars, das als around-Plugin die übergebenen Variablen um eigene Werte ergänzt, bevor der Originalaufruf weiterläuft. Das Plugin selbst bekommt per Constructor Property Promotion einen eigenen TemplateVariablesProviderInterface injiziert, eine kleine Service-Contract-Schnittstelle mit einer Methode getVariables(), die pro Anwendungsfall, etwa Bestellung, Kunde oder Angebot, unterschiedlich implementiert werden kann.

Alternativ, wenn eine komplett eigene transaktionale E-Mail von Grund auf gebaut wird, lohnt sich eine dedizierte Sender-Klasse statt eines Plugins auf den generischen TransportBuilder. Diese Klasse injiziert TransportBuilder, den eigenen Variablen-Provider und einen Logger direkt über den Konstruktor, baut Template-Identifier, Template-Optionen (area, store) und Template-Variablen in einer einzigen, verketteten Aufrufkette zusammen und kapselt Fehlerbehandlung an einer Stelle. Der entscheidende Architekturpunkt: Die Variablen-Logik gehört in eine eigene, austauschbare Klasse, nicht in die Sende-Methode selbst, damit sie unabhängig testbar bleibt und bei neuen Anforderungen nicht die Versandlogik anfassen muss.


final class OrderFollowupSender
{
    /**
     * @param TransportBuilder $transportBuilder Builds the transport with template and variables.
     * @param TemplateVariablesProviderInterface $variablesProvider Supplies additional custom variables.
     * @param LoggerInterface $logger Logs failed sends without interrupting the caller.
     */
    public function __construct(
        private readonly TransportBuilder $transportBuilder,
        private readonly TemplateVariablesProviderInterface $variablesProvider,
        private readonly LoggerInterface $logger,
    ) {
    }

    /**
     * Sends the order follow-up transactional email for a given order.
     *
     * @param OrderInterface $order Order the follow-up email refers to.
     * @return bool True on success, false if sending failed.
     */
    public function send(OrderInterface $order): bool
    {
        $storeId = (int) $order->getStoreId();

        try {
            $transport = $this->transportBuilder
                ->setTemplateIdentifier('mironsoft_orderfollowup_email_template')
                ->setTemplateOptions(['area' => 'frontend', 'store' => $storeId])
                ->setTemplateVars(array_merge(
                    [
                        'order' => $order,
                        'customer_name' => $order->getCustomerFirstname(),
                    ],
                    $this->variablesProvider->getVariables($order)
                ))
                ->setFrom('sales')
                ->addTo((string) $order->getCustomerEmail())
                ->getTransport();

            $transport->sendMessage();

            return true;
        } catch (\Exception $exception) {
            $this->logger->error($exception->getMessage());

            return false;
        }
    }
}

Damit die zusätzlichen Variablen tatsächlich ankommen, muss der Plugin-Typ in di.xml auf den TransportBuilder registriert werden. Ein sortOrder ist hier meist unkritisch, solange kein zweites Plugin dieselbe Methode ebenfalls verändert.


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Mail\Template\TransportBuilder">
        <plugin name="mironsoft_addCustomTemplateVariables"
                type="Mironsoft\EmailTemplates\Plugin\AddCustomTemplateVariablesPlugin"
                sortOrder="10"/>
    </type>
</config>

6. E-Mail-Layout-XML: Header, Footer und Logo steuern

Der Standardweg, Header, Footer und Logo einer transaktionalen E-Mail zu steuern, führt über Stores > Konfiguration > Allgemein > Transaktions-E-Mails, wo pro Store View ein Logo, ein Logo-Alt-Text sowie ein Header- und Footer-Template hinterlegt werden können. Das reicht für einfaches Branding, stösst aber an Grenzen, sobald Header oder Footer komplexere, block-basierte Struktur brauchen, etwa dynamische Social-Media-Icons oder store-spezifische Rechtstexte, die selbst wieder aus mehreren Bausteinen bestehen.

Für diesen Fall lohnt sich eine eigene Layout-XML-Datei im Bereich area="frontend", zum Beispiel view/frontend/layout/email_orderfollowup_header.xml, die Blöcke wie üblich über referenceContainer und block-Knoten definiert. Die Sender-Klasse emuliert dafür kurzzeitig den Frontend-Kontext des jeweiligen Stores, rendert den Layout-Handle, holt sich per getBlock() das gerenderte HTML von Header und Footer und übergibt es als zusätzliche Template-Variable, etwa header_html, an setTemplateVars(). Im .html-Template greift {{var header_html}} den bereits gerenderten Block einfach ab, ohne dass die E-Mail-Direktiven selbst Block-Logik kennen müssen.

Der Vorteil dieses Zusammenspiels aus Layout-XML und E-Mail-Templates: Header und Footer folgen denselben Konventionen wie das restliche Theme, jede Store View kann eigene Blöcke und eigene .phtml-Dateien nutzen, und Änderungen am Layout landen wie gewohnt über den normalen Theme-Fallback von Store View über Website bis Default, statt über eine separate, schwer wartbare E-Mail-Sonderlogik.


<?xml version="1.0"?>
<!-- view/frontend/layout/email_orderfollowup_header.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <!-- Rendered in area="frontend" per store view during design emulation -->
            <block class="Mironsoft\EmailTemplates\Block\Header"
                   name="email.header"
                   template="Mironsoft_EmailTemplates::email/header.phtml"/>
            <block class="Mironsoft\EmailTemplates\Block\Footer"
                   name="email.footer"
                   template="Mironsoft_EmailTemplates::email/footer.phtml"/>
        </referenceContainer>
    </body>
</page>

7. Multi-Store und Mehrsprachigkeit: Template-Auflösung

Magento löst die tatsächlich verschickte transaktionale E-Mail in einer klaren Reihenfolge auf. Zuerst wird der store-spezifische Konfigurationswert des relevanten System-Config-Pfads gelesen, etwa sales_email/order/template, gescoped auf Store View, Website und Default in dieser Priorität. Zeigt dieser Wert auf eine im Backend gespeicherte Datenbank-Kopie, wird diese verwendet, inklusive ihres eigenen Inhalts und ihrer eigenen Variablen. Zeigt er weiterhin auf den XML-Default, also den in email_templates.xml deklarierten Bezeichner, lädt Magento die physische .html-Datei aus dem aktiven Theme, mit vollem Theme-Fallback bis zum Basis-Theme des Moduls.

Die Sprache der E-Mail-Templates selbst folgt nicht dem Dateisystem-Pfad, sondern der aktiven Store-Locale zur Laufzeit des Sendevorgangs: {{trans}}-Direktiven und __()-Aufrufe im Sender-Code ziehen ihre Übersetzung aus den i18n-CSV-Dateien des Themes beziehungsweise Moduls für genau die Locale, die beim Aufruf von setTemplateOptions(['area' => ..., 'store' => $storeId]) aktiv ist. Deshalb reicht ein einziges .html-Template für mehrere Sprachen aus, solange sämtliche sichtbaren Texte über {{trans}} statt als hartcodierter String im Template stehen. Nur wenn sich Struktur oder Bildsprache zwischen Stores unterscheiden sollen, braucht es tatsächlich unterschiedliche Templates pro Store View, nicht nur unterschiedliche Übersetzungen.

Für Agenturen mit internationalen Shops ist die praktische Konsequenz: Bevor ein zweites, sprachspezifisches Template angelegt wird, lohnt sich die Prüfung, ob nicht schon {{trans}} plus vollständige i18n-Abdeckung ausreicht. Ein zusätzliches Template pro Sprache verdoppelt den Pflegeaufwand bei jeder inhaltlichen Änderung, während eine saubere Übersetzungsdatei zentral bleibt und über den normalen Sprachpaket-Fallback gepflegt wird.

8. Transaktionale E-Mails im Vergleich: unsicher gegen empfohlen

Bei transaktionalen E-Mails entscheidet die gewählte Umsetzung direkt darüber, ob eine E-Mail in allen Clients korrekt aussieht, ob der Checkout bei SMTP-Problemen blockiert und ob Inhalte ohne Deploy pflegbar bleiben. Die folgende Übersicht zeigt verbreitete unsichere Muster neben dem empfohlenen Pattern für dieselbe Aufgabe rund um E-Mail-Templates.

Aufgabe Unsicher / Fehleranfällig Empfohlenes Pattern Vorteil
Inhalt der E-Mail HTML-String im PHP-Code zusammengebaut Registrierung über email_templates.xml Backend-editierbar, übersetzbar, kein Deploy für Textänderungen
Layout im Template CSS Flexbox/Grid, externe Stylesheets Table-basiertes, inline-gestyltes Markup Rendert korrekt in Outlook, Gmail und mobilen Clients
Versandzeitpunkt Synchron im Checkout-Request Asynchron über Message-Queue-Consumer Checkout blockiert nicht bei SMTP-Latenz oder -Ausfall
Eigene Variablen If/Else-Ketten direkt im Sender TemplateVariablesProvider per Plugin/DI Testbar, erweiterbar, ohne Sender-Klasse anzufassen
Multi-Store-Branding Ein globales Template für alle Stores Store-spezifische Overrides mit Fallback-Kette Mehrsprachigkeit und Branding ohne Codeduplikation

Die Tabelle macht deutlich, dass praktisch jede Zeile denselben Grundgedanken verfolgt: Logik, Darstellung und Versand von E-Mail-Templates gehören in separate, über Service Contracts und Plugins austauschbare Bausteine, nicht in eine einzelne, wachsende Methode. Wer diese Trennung von Anfang an einhält, kann später einzelne Bausteine ersetzen, zum Beispiel synchronen Versand gegen einen Queue-Consumer, ohne das gesamte Template neu zu schreiben.

9. Lokales Testing mit MailHog und Preview-Rendering

Im docker-magento-Setup von Mark Shust läuft standardmässig ein MailHog-Container, der jede vom Container abgehende SMTP-Verbindung abfängt, statt sie tatsächlich zuzustellen. Jede transaktionale E-Mail, die im lokalen Environment über TransportBuilder verschickt wird, landet damit automatisch in der MailHog-Weboberfläche, üblicherweise auf Port 8025, statt im echten Postfach eines Kunden, inklusive Header, Rohtext und gerenderter HTML-Ansicht. Für Agenturen ist das der Standardweg, um den kompletten Versandpfad, von der Trigger-Logik über die Directive-Auswertung bis zum tatsächlichen SMTP-Handshake, ohne Risiko zu prüfen.

Für reines Rendering-Testing ohne jeden Versand bietet die Admin-Oberfläche unter Marketing > Communications > E-Mail-Templates eine Preview-Funktion: Beim Öffnen eines Templates wertet Magento serverseitig alle Direktiven mit Beispieldaten aus und zeigt das Ergebnis direkt im Browser, ohne dass ein Mail-Objekt oder eine Transport-Instanz überhaupt erzeugt wird. Für Templates mit anwendungsspezifischen Variablen, die die generische Preview nicht kennt, etwa eigene, per Plugin injizierte Variablen, lohnt sich ein kleines, selbst geschriebenes bin/magento-Kommando, implementiert über die Symfony Console API und registriert über di.xml als CommandListInterface-Eintrag.

Ein solches Kommando lädt das Template über Magento\Email\Model\TemplateFactory, setzt dieselben Variablen wie der produktive Sender und ruft getProcessedTemplate() auf, statt den Umweg über TransportBuilder und einen tatsächlichen Mail-Transport zu gehen. Das Ergebnis lässt sich als .html-Datei nach var/email-preview/ schreiben und direkt im Browser öffnen, komplett ohne SMTP-Verbindung, ohne MailHog und ohne Risiko, versehentlich eine echte Adresse anzuschreiben. In der Praxis kombiniert man beide Wege: die CLI-Preview für schnelle Iterationen an Variablen und Direktiven, MailHog für den vollständigen End-to-End-Test inklusive Betreffzeile, Absenderadresse und Client-Rendering.

10. Zusammenfassung

Eine belastbare transaktionale E-Mail in Magento 2 entsteht nicht durch einen schnell zusammengebauten String im Sender-Code, sondern durch die konsequente Nutzung der dafür vorgesehenen Bausteine: Registrierung über email_templates.xml, Direktiven wie {{var}} und {{trans}} statt hartcodierter Texte, ein eigener TemplateVariablesProvider statt kopierter Core-Klassen, Layout-XML für block-basierte Header und Footer sowie eine klare Store-spezifische Fallback-Kette für Multi-Store-Betrieb. Jeder dieser Bausteine ist einzeln austauschbar, solange die Verantwortlichkeiten sauber getrennt bleiben.

Lokales Testing mit MailHog und eine eigene Preview-Möglichkeit ohne echten Versand runden den Workflow ab: Änderungen an E-Mail-Templates lassen sich so prüfen, bevor sie überhaupt eine echte Adresse erreichen. Wer diese neun Bausteine konsequent anwendet, baut E-Mail-Templates, die sich pflegen, übersetzen und erweitern lassen, ohne bei jeder Anpassung Risiko für den produktiven Versand einzugehen.

Transaktionale E-Mail-Templates in Magento 2: das Wichtigste auf einen Blick

Registrierung

email_templates.xml deklariert die id, das Label und die area. Die id referenziert TransportBuilder::setTemplateIdentifier() im Sender.

Direktiven

{{var}} gibt Werte aus, {{trans}} übersetzt mit Platzhaltern. Beide werden von Magento\Email\Model\Template\Filter ausgewertet.

Eigene Variablen

Ein around-Plugin auf TransportBuilder::setTemplateVars, gespeist aus einem eigenen TemplateVariablesProviderInterface per DI.

Testing

MailHog fängt jede SMTP-Verbindung lokal ab. Eine CLI-Preview rendert Templates ganz ohne Versand.

11. FAQ: Transaktionale E-Mail-Templates in Magento

1Was unterscheidet eine transaktionale E-Mail von einem Newsletter?
Transaktionale E-Mails werden durch ein konkretes Ereignis ausgelöst und über TransportBuilder mit einem registrierten Template verschickt. Newsletter laufen über Magento_Newsletter und eine Abonnentenliste, unabhängig vom einzelnen Kundenereignis.
2Wie registriere ich ein neues E-Mail-Template?
In etc/email_templates.xml einen template-Knoten mit id, label, file, type und area anlegen, die .html-Datei unter view/{area}/email/ ablegen und setup:upgrade ausführen.
3Wie überschreibe ich ein Core-Template ohne Codeänderung?
Im Backend unter Marketing > E-Mail-Templates laden, anpassen und als Kopie speichern. Die Kopie referenziert das Original über orig_template_code, hat aber im Konfigurationspfad Vorrang.
4{{var}} versus {{trans}}?
{{var}} gibt einen Wert direkt aus. {{trans}} übersetzt zusätzlich und unterstützt benannte Platzhalter, vergleichbar mit __() im PHP-Code.
5Eigene Variablen ohne Core-Klassen zu kopieren?
Ein around-Plugin auf TransportBuilder::setTemplateVars mischt zusätzliche Werte aus einem eigenen TemplateVariablesProviderInterface in das Variablen-Array.
6Header, Footer, Logo je Store View?
Einfaches Branding über die Transaktions-E-Mail-Felder in der Store-Konfiguration. Für Blöcke eine Layout-XML im Bereich area=frontend rendern und als Template-Variable übergeben.
7Fallback-Kette bei der Template-Auflösung?
Store View vor Website vor Default. Datenbank-Kopie gewinnt vor dem XML-Default, danach greift der normale Theme-Fallback für die .html-Datei.
8Lokales Testing ohne echten Versand?
MailHog im docker-magento-Setup fängt jede SMTP-Verbindung ab und zeigt jede E-Mail in einer eigenen Weboberfläche, meist auf Port 8025.
9Rendering prüfen ganz ohne Versandversuch?
Die Preview-Funktion im Email-Templates-Grid oder ein eigenes bin/magento-Kommando, das getProcessedTemplate() direkt in eine lokale HTML-Datei schreibt.
10Warum Versand über Message Queue statt synchron?
Synchroner Versand blockiert den Request bei SMTP-Latenz oder -Ausfall. Ein Queue-Consumer hält den Request schnell und erledigt den Versand robust im Hintergrund mit Retry-Logik.

Mironsoft

Magento-2-Entwicklung, E-Mail-Templates und Hyvä-Themes

Transaktionale E-Mails, die zuverlässig ankommen und sauber aussehen?

Wir registrieren E-Mail-Templates sauber über email_templates.xml, injizieren eigene Variablen per Plugin statt Core-Kopien und richten lokales Testing mit MailHog für euer Team ein, damit jede transaktionale E-Mail nachvollziehbar und wartbar bleibt.

Template-Audit

Bestehende E-Mail-Templates, Overrides und Directive-Nutzung prüfen und dokumentieren

Custom Sender

Eigene TransportBuilder-Plugins, Variablen-Provider und Layout-XML für Header/Footer

Testing-Setup

MailHog-Integration und CLI-Preview-Kommandos für risikofreies lokales Testing