Creating a New Email Framework for .NET

For a while, I've been toying with the idea of writing a simple mail sending package for .NET. The only viable solution at the moment is ActionMailer.Net which was initially abandoned but then found a new home at ActionMailerNext . The question I've been asking myself is why create a new framework when ActionMailerNext will do? And it boils down to the following:

  • The library, like its predecessor, is unfortunately in a state of semi abandonment, notably not having incorporated the last major version of RazorEngine and several pull requests going unanswered.
  • It's overly complex, asking you to decide between several MVCx alternatives or a standalone version and then forces the assemblies of Mandrill and SendGrid on you - even if you don't use them. For any given project, this amounts to 5 separate assemblies in your packages.config file!
  • While there is documentation, it's patchy at best.

The good news id that the latest developments on RazorEngine, have made it really easy to get a new framework up and running. The built in functionality allows us easily load and compile Razor templates from the file system and use them to generate the content for an email body. All that's needed is an email specific wrapper and some easy to follow documentation (this last point is especially important as it's where a lot of perfectly good open source projects let themselves down).

The following class is at the core of the new framework. It creates a new instance of RazorEngine and tells it where to look for the templates:

Template Resolution

Templates can be included within your web application, within a console or service based application or (and this is my preference) within a separate class library. Separating them out into a separate class library provides two benefits a) being we share our core email logic across different application types and b) that we can unit test the templates.

It's worth noting that templates from another class library end up in the \bin folder of a web application while ending up in the \bin\debug folder of a console, service or test application. It's therefore necessary to supply both of these paths to RazorEngine to locate our templates, making use of the AppDomain.CurrentDomain.BaseDirectory variable.

N.B The templates can be included in an project within your solution but must have their Build Action set to Content and Copy to Output Directory flag set to Copy always. This ensures that the templates end up the in the same folder as the executing assembly and are included when you package your application.

A simple template (without a layout):

Models

RazorEngine allows you to specify dynamic or typed models to construct the body from a template. I've opted to just allow the use of typed models for now as as the use of dynamic models, although easy, removes all type checking and can often be abused. Again, RazorEngine does all of the hard lifting here and we just need to wrap the method call:

Layouts

If you would like to share the layout of your email across multiple emails, you can do so my making use of the built in layout functionality of RazorEngine. By simply placing the layout in the same folder as your other templates and referencing it through a directive at the top of your partial, it will automatically be loaded, compiled and cached by RazorEngine.

A simple layout & partial document are included below:

Unit Testing:

Bringing everything together, it's fairly trivial to write unit tests for specific emails by mocking out the IDispatcher interface (here using Moq), creating a model and calling the Create method on our RazorMailer class. A simple test is outlined below:

The source for RazorMailer can be found here, nuget here, and a post introducing the framework will follow shortly.

Author image
About Jon Leigh
London Website

Hi, I'm Jon. I'm part of the Engineering team at Moneybox, a London based Fintech startup helping people to save and invest.

In my spare time, I've created CompareVino, a UK supermarket wine comparison website. If you like wine and buy it from a supermarket, you should definitely check it out.

If you want to get in touch, send me a message via Twitter