Please view the new stable version of this project Mjml.Net.
An unofficial port of MJML (by MailJet) to .NET Standard. This project is currently in an experimental state and should not be used in a production environment.
MJML
is a markup language created by Mailjet and designed to reduce the pain of coding a responsive email. Its semantic syntax makes the language easy and straightforward while its rich standard components library shortens your development time and lightens your email codebase. MJML’s open-source engine takes care of translating the MJML
you wrote into responsive HTML.
You can find out more about MJML 4 from the official website.
| Official Website | Official Documentation | Official Onboarding |
Firstly, you'll need to reference the MJML.NET
NuGet Package into your project.
PM > Install-Package MjmlDotNet
Secondly, include MJML.NET
namespace into your project.
using MjmlDotNet;
Finally, the boilerplate code.
public void Main()
{
// or DI
IMjmlParser mjmlParser = new MjmlParser();
string mjml = @"
<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>";
string html = mjmlParser.ParseDocument(mjmlString);
}
You can also specify options to the MJML parser. This can be done either at instantiation throught the defaultOptions
parameter or at time of parsing the document. Both options are shown below.
public void Main()
{
// 1. Default Options for every MJML document
MjmlParserOptions defaultOptions = new MjmlParserOptions() {
Minify = true;
Prettify = false;
}
IMjmlParser mjmlParser = new MjmlParser(defaultOptions);
// Or 2. Override at per-document parsing
MjmlParserOptions options = new MjmlParserOptions() {
Minify = true;
Prettify = false;
}
string html = mjmlParser.ParseDocument(mjml, options);
}
Currently, we've not implemented all of the same options. This is because we're still introducing components and refactoring the project. However, the currently supported options are:
Name | Data Type | Default | Description |
---|---|---|---|
Prettify | Boolean | False | Prettifies the output when enabled. |
Minify | Boolean | True | Minifies the output when enabled. This overrides Prettify as this would be ideal default in production environment. |
MJML.NET
tries to implement all functionality 1-2-1
with the MJML 4 project. However, due to JavaScript not being a typed language this means there has been considerate refactoring to the code to make it more aligned with C# typed requirements.
As the project is currently still in experimental state not all MJML components have been added. Please see the below table for a list of all components and the current implementation state:
Type | Component | Implemented | Tests | State |
---|---|---|---|---|
Core | mjml | ✅ | ❌ | Awaiting Tests |
Core | mjml-head | ✅ | ❌ | Awaiting Tests |
Core | mjml-body | ✅ | ❌ | Awaiting Tests |
Core | mjml-include | ❌ | ❌ | Not Implemented |
Head | mjml-attributes | ✅ | ❌ | Awaiting Tests |
Head | mjml-class |
❌ | ❌ | Not Implemented |
Head | mjml-all |
❌ | ❌ | Not Implemented |
Head | mjml-breakpoint | ✅ | ❌ | Awaiting Tests |
Head | mjml-font | ✅ | ❌ | Awaiting Tests |
Head | mjml-html-attributes | ❌ | ❌ | Not Implemented |
Head | mjml-preview | ✅ | ❌ | Awaiting Tests |
Head | mjml-style | ☑️ | ❌ | Partially Complete (Inline Support Required) |
Head | mjml-title | ✅ | ✅ | Complete |
Body | mjml-accordion | ❌ | ❌ | Not Implemented |
Body | mjml-button | ✅ | ❌ | Awaiting Tests |
Body | mjml-carousel | ❌ | ❌ | Not Implemented |
Body | mjml-column | ✅ | ❌ | Awaiting Tests |
Body | mjml-divider | ✅ | ❌ | Awaiting Tests |
Body | mjml-group | ✅ | ❌ | Awaiting Tests |
Body | mjml-hero | ✅ | ❌ | Awaiting Tests |
Body | mjml-image | ✅ | ❌ | Awaiting Tests |
Body | mjml-navbar | ✅ | ❌ | Awaiting Tests |
Body | mjml-raw | ✅ | ❌ | Awaiting Tests |
Body | mjml-section | ☑️ | ❌ | Partially Complete (Background Position Bug) |
Body | mjml-social | ✅ | ❌ | Awaiting Tests |
Body | mjml-spacer | ✅ | ❌ | Awaiting Tests |
Body | mjml-table | ❌ | ❌ | Awaiting Tests (AngleSharp Issue) |
Body | mjml-text | ✅ | ❌ | Awaiting Tests |
Body | mjml-wrapper | ✅ | ❌ | Awaiting Tests |
Testing this project has been rather difficult due to the nature of the output. However, we're still trying to provide valuable tests for components which can validate correct output. For example, if we set the <mj-title>
the outputted HTML document <title>
should match.
Furthermore, this project will fall into the grey area of testing. Because of this, we'll rely heavily on bug reports from usage of MJML.NET
.
We've benchmarked the main components of the library to make sure we're within a suitable execution speed. We'll continue monitoring the execution speed as part of project development. We benchmark based off the default MJML templates.
Method | Mean | Error | StdDev |
---|---|---|---|
TryParseDocument | 37.64 ms | 2.538 ms | 7.483 ms |
ParseDocument | 38.77 ms | 2.549 ms | 7.515 ms |
ParseDocumentAsync | 38.24 ms | 2.157 ms | 6.360 ms |
We really appreciate any contribution to the project to help provide a native version of MJML to C#.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Side Note: In your PR you should summarise your changes, bug fixes or general modifications.
Once again, it's good to share some appreciation to the projects that make MJML.NET
possible.
MIT License
Copyright (c) 2020 Liam Riddell
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.