Skip to main content

Email Templating with .NET

Required Packages

dotnet add package Mjml.Net
dotnet add package dotliquid
Template.mjml
<mjml>
<mj-head>
<mj-font name="Quicksand" href="https://fonts.googleapis.com/css?family=Quicksand" />
<mj-title>{{AppTypeName}} Contact</mj-title>
<mj-attributes>
<mj-all font-family="Quicksand,helvetica" />
</mj-attributes>
</mj-head>
<mj-body background-color="#ffffff">
<mj-section background-color="#ffffff">
<mj-column>
<mj-image width="150px" align="center" src="https://cdn.example.com/logo@2x.png" container-background-color="#ffffff" />
</mj-column>
</mj-section>
<mj-section background-color="#ffffff">
<mj-column>
<mj-text font-size="24px" color="#454FD0">{{AppTypeName}} Contact</mj-text>
<mj-divider border-color="#454FD0"></mj-divider>
<mj-text font-size="18px" color="#38428B">From: {{FromName}}</mj-text>
<mj-text font-size="18px" color="#38428B">Email Address: {{FromEmail}}</mj-text>
<mj-text font-size="18px" color="#38428B">Organisation: {{FromOrganization}}</mj-text>
<mj-text font-size="18px" color="#38428B">Message: {{Message | prettyprint | paragraph}}</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff">
<mj-column>
<mj-divider border-color="#454FD0"></mj-divider>
<mj-text font-size="18px" color="#38428B">At: {{SentAt | date:"dd-MM-yyyy"}}</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
Program.cs
using Bogus;
using DotLiquid;
using Mjml.Net;

var user = new Faker<User>()
.CustomInstantiator(o => new User(o.Random.Guid(), o.Name.FirstName(), o.Internet.Email(), o.Company.CompanyName()))
.Generate();

var message = new Faker<Message>()
.CustomInstantiator(o => new Message(o.Random.Guid(), o.Date.Recent(), o.Commerce.ProductDescription()))
.Generate();

var rawMjml = File.ReadAllText("Template.mjml");

var mjmlRenderer = new MjmlRenderer();
var mjmlOptions = new MjmlOptions
{
Beautify = false,
Minify = true,
KeepComments = false
};

var renderedMjml = mjmlRenderer.Render(rawMjml, mjmlOptions);
if (renderedMjml.Errors.Any())
Console.WriteLine($"Error rendering MJML: {renderedMjml.Errors}");

Console.WriteLine($"Rendered Mjml: {renderedMjml}");

var renderedMjmlHtml = renderedMjml.Html;

var template = Template.Parse(renderedMjmlHtml);

var renderedHtml = template.Render(Hash.FromAnonymousObject(new
{
FromId = user,
FromName = user.FirstName,
FromEmail = user.EmailAddress,
FromOrganization = user.OrganizationName,
Message = message.Content,
SentAt = message.CreatedAt
}));

Console.WriteLine($"Rendered Html: {renderedHtml}");
DemoPlumbing.cs
public record User(Guid Id, string FirstName, string EmailAddress, string OrganizationName);
public record Message(Guid Id, DateTimeOffset CreatedAt, string Content);

Output Non Rendered

...
<div style="font-family:Quicksand,helvetica;font-size:18px;line-height:1;text-align:left;color:#38428B;">
Message: {{Message | prettyprint | paragraph}}
</div>
...
<div style="font-family:Quicksand,helvetica;font-size:18px;line-height:1;text-align:left;color:#38428B;">
At: {{SentAt}}
</div>
...

Output Rendered

...
<div style="font-family:Quicksand,helvetica;font-size:18px;line-height:1;text-align:left;color:#38428B;">
Message: The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality
</div>
...
<div style="font-family:Quicksand,helvetica;font-size:18px;line-height:1;text-align:left;color:#38428B;">
At: 04-11-2023
</div>
...