MJML.NET

repository·main·Indexed 42 days ago

https://github.com/sebastianstehle/mjml-net

A high-performance unofficial .NET 6 to 9 port of MJML 4 used to translate MJML markup into responsive HTML for email development. It provides the MjmlRenderer and MjmlOptions for customizing rendering behavior, including support for core, head, and body components. Features include an experimental AngleSharp-based post-processor for inline styles and HTML attributes, and a transition to a standard HTML parser in version 2.0.0 to better handle non-valid XML.

Tokens
2.2K
Snippets
8
Records
12
Agent score
5%

What's inside MJML.NET

  1. How to handle non-valid XML in MJML (Pre-v2.0.0)

    main

    MJML syntax is not always strictly valid XML.

    For Version 2.0.0 and later: The engine uses an HTML parser that follows official standards and can accept various HTML inputs without manual sanitization.

    For versions older than 2.0.0: You must sanitize the MJML string before rendering using the FixXML method to ensure the XML parser works correctly. It is recommended to store both the original and the sanitized version if saving to a database.

    // Legacy approach for versions < 2.0.0
    var xml = mjmlRenderer.FixXML(text, options);
    var (html, errors) = mjmlRenderer.Render(xml, options);
  2. Render MJML to HTML with MjmlRenderer

    main

    To render MJML markup into responsive HTML, instantiate an MjmlRenderer, provide your MJML string, and pass an MjmlOptions object. The Render method returns a tuple containing the resulting html string and any errors encountered during parsing.

    using Mjml.Net;
    
    public static void Main (string[] args) {
        var mjmlRenderer = new MjmlRenderer();
    
        string text = @"
            <mjml>
                <mj-head>
                    <mj-title>Hello World Example</mj-title>
                </mj-head>
                <mj-body>
                    <mj-section>
                        <mj-column>
                            <mj-text>
                                Hello World!
                            </mj-text>
                        </mj-column>
                    </mj-section>
                </mj-body>
            </mjml>";
    
        var options = new MjmlOptions
        {
            Beautify = false
        };
    
        var (html, errors) = mjmlRenderer.Render(text, options);
    }
  3. Run the Mjml.Net vs. MJML (JavaScript) benchmark

    main

    To generate the comparison report between Mjml.Net and the original MJML (JavaScript) renderer, run the Mjml.Net.Compare project using the .NET CLI in Release mode.

    Note: This report is automatically generated and should not be edited manually. The benchmark compares in-process rendering performance (excluding beautify, minify, and validation) across various MJML templates.

    dotnet run -c Release --project Mjml.Net.Compare
  4. Compare Mjml.Net performance against MJML (JavaScript)

    main

    You can reproduce the performance comparison between Mjml.Net and the original MJML (Node.js) using the Mjml.Net.Compare project. The comparison measures the time taken to render various benchmark templates in-process.

    dotnet run -c Release --project Mjml.Net.Compare
  5. Use Inline Styles and HTML Attributes via Post-Processors

    main

    MJML supports inline styles and HTML attributes, but these are expensive features that require a post-processing step after the initial rendering. MJML.NET implements this using the AngleSharp library via a separate NuGet package.

    Warning: EXPERIMENTAL FEATURE. There are known bugs in the CSS library; it is not recommended for production use yet.

    To use this feature:

    1. Install the Mjml.Net.PostProcessors package.
    2. Add AngleSharpPostProcessor.Default to the PostProcessors list in your MjmlOptions.
    3. Call mjmlRenderer.AddHtmlAttributes() on your renderer instance.
    4. Crucial: You must use the asynchronous method variants (e.g., RenderAsync) to run post-processors, as they may use async methods.
    // 1. Install-Package Mjml.Net.PostProcessors
    
    var options = new MjmlOptions
    {
        PostProcessors = [AngleSharpPostProcessor.Default]
    };
    
    var mjmlRenderer = new MjmlRenderer();
    
    // 2. Enable HTML attributes post-processing
    mjmlRenderer.AddHtmlAttributes();
    
    // 3. Use the ASYNC method to ensure post-processors run
    var (html, errors) = await mjmlRenderer.RenderAsync(text, options);
  6. Run MJML.NET benchmarks

    main

    To run the internal performance benchmarks for the Mjml.Net.Benchmarks project, execute it in release mode. Note that these tests measure rendering performance and do not include disk I/O for loading or saving templates.

    dotnet run -c Release --project Mjml.Net.Benchmarks
  7. Configure MJML rendering with MjmlOptions

    main

    You can customize the rendering behavior by providing an MjmlOptions instance to the Render method.

    NameData TypeDefaultDescription
    BeautifybooltrueIf true, the output HTML is beautified. Note: This impacts performance (slower).
    Breakpointstring480pxThe default breakpoint used to switch to mobile view.
    FileLoaderIFileLoader?nullA loader for <mj-include path="..." type="..."> tags (e.g., DiskFileLoader, InMemoryFileLoader).
    FontsIReadOnlyDictionary<string, Font[]>PresetA list of supported default fonts.
    ForceOWAQueriesboolfalseIf true, enables media queries for Outlook Web App (OWA).
    IdGeneratorIIdGeneratorPresetThe generator used to create random values for attributes like Ids.
    KeepCommentsboolfalseIf true, preserves HTML comments in the output.
    LaxboolfalseIn lax mode, some XML errors are fixed. Warning: Only use when MJML is passed as a string; do not use in production as it can hurt performance.
    MinifyboolfalseMinifies the HTML. (Deprecated with version 2.0.0)
    PostProcessorsIPostProcessor[]?[]An array of post-processors to run on the HTML after rendering.
    StylesStyle[]?[]A list of custom styles to apply.
    ValidatorFactoryIValidatorFactory?nullThe current validator, which also defines the validation mode.
    XmlEntitiesIReadOnlyDictionary<string, string>PresetA list of supported XML entities. (Deprecated with version 1.16.0)
  8. Handle non-encoded URLs and non-XML HTML tags (Pre-v2.0.0)

    main

    In versions prior to 2.0.0, the XmlReader parser may throw exceptions for non-encoded URLs or HTML tags that are not valid XML (such as <br>).

    Solutions:

    1. For URLs: URL-encode all URLs in the template.
    2. For HTML tags: Convert tags to XHTML format (e.g., use <br /> or <br></br> instead of <br>).
    3. Global Fix: Enable lax mode in your configuration by setting options.Lax = true.
  9. Supported MJML Components in MJML.NET

    main

    MJML.NET aims for 1-2-1 parity with the MJML 4 project. The following components are implemented, tested, and marked as 'Feature Complete':

    Core Components

    • mjml
    • mj-head
    • mj-body
    • mj-include

    Head Components

    • mj-attributes
    • mj-class
    • mj-all
    • mj-breakpoint
    • mj-font
    • mj-html-attributes
    • mj-preview
    • mj-style
    • mj-title

    Body Components

    • mj-accordion
    • mj-button
    • mj-carousel
    • mj-column
    • mj-divider
    • mj-group
    • mj-hero
    • mj-image
    • mj-navbar
    • mj-raw
    • mj-section
    • mj-social
    • mj-spacer
    • mj-table
    • mj-text
    • mj-wrapper
  10. Fix unknown HTML entities (Pre-v1.17.0)

    main

    In versions prior to 1.17.0, using HTML Character Entity Names (e.g., &copy;) may cause unhandled exceptions because the parser uses XmlReader.

    Solution: Replace HTML Character Entity Names with their corresponding HTML Character Entity Numbers (e.g., &#169;).

    Common conversions:

    Entity NameEntity Number
    &nbsp;&#160;
    &lt;&#60;
    &gt;&#62;
    &amp;&#38;
    &quot;&#34;
    &apos;&#39;
    &copy;&#169;
    &reg;&#174;
    &trade;&#8482;