Moonbase.EmailKit.Blocks
1.3.2
See the version list below for details.
dotnet add package Moonbase.EmailKit.Blocks --version 1.3.2
NuGet\Install-Package Moonbase.EmailKit.Blocks -Version 1.3.2
<PackageReference Include="Moonbase.EmailKit.Blocks" Version="1.3.2" />
<PackageVersion Include="Moonbase.EmailKit.Blocks" Version="1.3.2" />
<PackageReference Include="Moonbase.EmailKit.Blocks" />
paket add Moonbase.EmailKit.Blocks --version 1.3.2
#r "nuget: Moonbase.EmailKit.Blocks, 1.3.2"
#:package Moonbase.EmailKit.Blocks@1.3.2
#addin nuget:?package=Moonbase.EmailKit.Blocks&version=1.3.2
#tool nuget:?package=Moonbase.EmailKit.Blocks&version=1.3.2
Full-stack Email Tooling for .NET
Moonbase.EmailKit is a collection of packages to simplify email design and construction in a .NET landscape. It does not require ASP.Net, it only uses Razor components and the Razor HTML renderer, enabling rendering in workers and other non-webserver services.
The packages form several layers of capabilities, meaning you can use exactly how much you need for your use case. There are no dependencies on any other templating engine other than what Microsoft provides.
Moonbase.EmailKit.Components
The components found in this package are all unstyled email-ready components to make building emails easy. They will wrap your layout in the necessary nested tables to ensure compatibility with all email clients, and come with sensible defaults built-in.
Get started by installing the NuGet package:
dotnet add package Moonbase.EmailKit.Components
At this point you can start authoring email templates as Razor components, and eventually render them. Use the components from the package to make the experience easier, but keep in mind you will always have to write some CSS yourself, the components in this package are unstyled. The simplest email you could make looks like this:
@using Moonbase.EmailKit.Components
<Email>
<EmailHead/>
<EmailBody>
<EmailPreview Text="This is the preview text visible in the mail client"/>
<EmailSection>
<EmailText>
This is a simple email template.
</EmailText>
</EmailSection>
</EmailBody>
</Email>
For more example templates, check out the provided sample emails, and be sure to have a look at the available components. All components are configured to forward any attributes to the underlying HTML element, and merge relevant styles applied to the component with the best-practice resets applied by the components themselves. To maximize compatibility with email clients, use inline styles wherever possible.
Moonbase.EmailKit.Components.Markdown
To extend the base component set with a Markdown renderer, you can use this package to add a new EmailMarkdown component.
Get started by installing the NuGet package:
dotnet add package Moonbase.EmailKit.Components.Markdown
Then, just like the other components, you can use the markdown
@using Moonbase.EmailKit.Components
@using Moonbase.EmailKit.Components.Markdown
<Email>
<EmailHead/>
<EmailBody>
<EmailMarkdown Markdown="This is **markdown** powered _markup_!" />
</EmailBody>
</Email>
It will apply the same default styles as the other email components to rendered elements from the Markdown input. To add styling to specific elements, you can add element styles:
@{
var elementStyles = new Dictionary<string, string>
{
{ "img", $"border-radius: 16px;" }
};
}
<EmailMarkdown
Markdown="Here's your image with rounded borders:\n\n"
ElementStyles="@elementStyles"
/>
Moonbase.EmailKit.PreviewServer
To make development of email templates and blocks easier, you may use the preview server to serve an inspector page, showcasing all email templates and blocks available in your assemblies. It's made to be added to an ASP.Net server, so that you can easily add it to any existing project. Hot-reload tooling in ASP.Net with regards to Razor components are a mixed bag, so your mileage with this may vary, but generally speaking it works fairly good, even with these email templates!
Get started by installing the NuGet package:
dotnet add package Moonbase.EmailKit.PreviewServer
Then add the required services to the service collection and map the route at which you want to host the inspector at:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMailKitPreviewServer(opts =>
{
// Specify which emails to preview, optionally use some
// reflection to find all types in the current assembly.
opts.EmailTypes = [typeof(MyEmailTemplate)];
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMailKitPreviewServer("/emails");
}
app.Run();
An example server implementing this preview can be found in the sample AspNetPreview project.
Moonbase.EmailKit.Blocks
Extending on the basic components, putting together a block library to more effectively compose emails using your design system is the natural next step. This package contains both some utilities for rendering these "blocks" in a container email, and also comes with a default set of components that we use to power Moonbase! They can look something like this when composed together:
This email is composed of blocks from our default set, using the block renderer. Get started by installing the NuGet package:
dotnet add package Moonbase.EmailKit.PreviewServer
Then use the renderer to render a series of blocks:
var html = await new BlockRenderer<Context>()
.WithBlock<HeaderBlock, HeaderBlock.Params>(new HeaderBlock.Params(
Title: "Example Title",
Subtitle: "With a subtitle",
ImageUrl: new Uri("https://assets.moonbase.sh/demo/products/juce-app-demo/icon/5128ac40-c270-44ad-ba3d-97026e257ccc.png")))
.WithBlock<SpacerBlock>()
.WithBlock<TextBlock, TextBlock.Params>(new TextBlock.Params("This is a sample email with several blocks"))
.WithBlock<ButtonBlock, ButtonBlock.Params>(new ButtonBlock.Params(new ButtonBlock.ButtonParams("Let's get started", new Uri("https://github.com/Moonbase-sh/Moonbase.EmailKit"))))
.WithBlock<SpacerBlock>()
.WithBlock<FooterBlock, FooterBlock.Params>(new FooterBlock.Params(
Text: "Made with ❤️\nBy Moonbase.sh",
IconUrl: new Uri("https://assets.moonbase.sh/square_transparent-white_no-text.png"),
Links:
[
("Preferences", new Uri("https://app.moonbase.sh/preferences")),
("Unsubscribe", new Uri("https://app.moonbase.sh/unsubscribe"))
]))
.RenderAsync();
To make theming easy, the block renderer takes in a base TContext that hold global context like theme properties.
The default theme can be seen above, but you can easily tweak softness, fonts, and colors.
Ultimately, you should extend this set with blocks that serve your needs, or create your own set(s) entirely.
Background
This package came about when we were looking for better ways to render emails in our various dotnet backend services. We wanted more native constructs to create modern emails, compatible with all mail clients, and with sensible defaults built-in, handling all the nasty nested tables necessary for consistent rendering. Other languages and frameworks have evolved over the years to handle this like MJML, react email, Vue Email and more. Efforts have been made to port for example MJML to .NET, but it relies on templates that are string-based, without the powerful features of Razor with C#. That's why we are exploring what a C#-oriented alternative could look and feel like.
Razor is the most obivous solution to this challenge, given that we can now render Razor components outside of ASP.Net, and can use C# in the templates directly instead of relying on other templating languages. However, there are some challenges we've come across while building this that makes the experience less than ideal.
A huge thanks goes out to creators and maintainers of the above mentioned packages, this project is only possible by extending their work, tweaking and extending it to make it more C#-native.
Current challenges
Razor component attributes cannot handle "complex content"
See: https://github.com/dotnet/razor/issues/7684
This means that while we can build a component library that feels like native components for building emails, you will have to do string interpolation when passing in attributes like styles if they rely on dynamic values.
❌ You cannot do this:
<EmailText
style="font-family: @fontFamily;"
>
This text is using the font family in the <code>fontFamily</code> variable.
</EmailText>
✅ Instead you must do this:
<EmailText
style=@($"font-family: {fontFamily};")
>
This text is using the font family in the <code>fontFamily</code> variable.
</EmailText>
Because of this issue, you lose all intellisense for style rules, classes, etc.
The Razor engine is HTML5 only
See: https://github.com/dotnet/aspnetcore/issues/13793#issuecomment-530493637
Ideally, we'd be able to produce XHTML 1.0 compatible markup, to ensure the widest compatibility possible, but given Razors inherent HTML5-only engine, it will mess with tags. For example, XHTML 1.0 requires closing tags or self-closing tags, but the Razor engine will remove them to optimize for HTML5.
If your .razor template contains this:
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
Razor will actually spit out this, missing the self-closing tag:
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
Razor components must not clash with HTML element names
See: https://github.com/dotnet/razor/issues/7656
Initially, we had a simple Link component to capture the typical link in emails, like we had for many of these wrappers: Head, Body, etc. Since some of these are clashing with lowercased HTML elements, they cause all sorts of weird issues with IntelliSense, making development hard.
This is why all components in this package are prefixed with Email.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Components.Web (>= 8.0.13)
- Moonbase.EmailKit.Components (>= 1.3.2)
- Moonbase.EmailKit.Components.Markdown (>= 1.3.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Moonbase.EmailKit.Blocks:
| Package | Downloads |
|---|---|
|
Moonbase.EmailKit.PreviewServer
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.