Blog posts in this series:
- Introduction (this post)
- Basics: generating your first email
- More Basics: caching, VS integration & namespace configuration
- Taking a step back: what is Razor and what does RazorEngine actually do?
- URL generation & T4MVC integration with RazorEngine (TBD)
- Layout with RazorEngine (TBD)
- Partials with RazorEngine (TBD)
- On keeping your sanity: inlining CSS with PreMailer.Net (TBD)
- Getting a little help from CsQuery: including subject, sender and recipient information in your email templates (TBD)
- Putting it all together: building a complete email-generation library with RazorEngine, PreMailer.Net and CsQuery (TBD)
I can think of few things in my life as a software developer that have caused me more grief than having to generate HTML emails. I long for the days when you could still argue in favour of plain text emails with clients.
HTML emails are a strange kind of beast. On one side, they're part of just about every web application out there and are often the most unrewarding feature to implement. On the other, they are technically stuck in the mid-90's, are unbelievably painful to implement and are a monstrosity to maintain. And yet, there is very little tooling available to make implementing them less painful.
In the .NET world, things have become slightly better with the introduction of the Razor view engine in ASP.NET MVC 3. Razor has made implementing HTML views in web application almost pleasant. And the ASP.NET team have had the great insight of making the Razor parser independent from ASP.NET, which means that you can use it outside of web applications to generate any type of document. Including HTML emails.
Combined with with the awesome PreMailer.Net library, Razor makes it orders of magnitude easier to implement and maintain dynamically-generated HTML emails compared to the String.Replace() method we've all been using (or, god forbid, XSLT).
Several Razor-based email-generation libraries have poped-up since the introduction of Razor. Postal, MvcMailer and ActionMailer.Net are probably the most popular ones. I've tried several but couldn't find one that I was really happy with. Some only work within the context of an ASP.NET application, others don't play nice with DI containers, others have too many limitations or bugs. I ended up spending more time pouring through their source code to try and understand what was going on than it would have taken me to implement my own solution.
And it turns out that implementing your own Razor-based email-generation library is fairly trivial thanks to the great job that Matthew Abbott did with his RazorEngine library, a wrapper around the Razor parser that makes it easy to use Razor anywhere. Unfortunately, the documentation for RazorEngine is somewhat lacking. So we'll try to address this here.
In this series of blog posts, I'll take you through implementing your own email-generation library with RazorEngine that will let you generate and send emails from any type of application: ASP.NET, console or desktop apps or even Windows Services. RazorEngine lets you implement your emails templates in the exact same way as you would implement an ASP.NET MVC view, including support for layouts, partials, strongly-typed and dynamic models, URL generation and even T4MVC integration.
Before we start
You can get the code on GitHub.
If you're implementing and testing emails on Windows and not already using smtp4dev, go and download it right now.
The code will be based on RazorEngine 3.4, Razor 3.0 and ASP.NET MVC 5.
In this series of blog post and to keep things simple, we'll be generating emails from a console application. Unless otherwise noted, the code should work in the exact same way within the context of an ASP.NET application, a desktop application or a Windows Service.
All the code and Razor templates will be in C# but can be easily adapted for VB.NET.
By convention, we'll suffix our email template files with the
.cshtml extension (just like ASP.NET MVC views) and put them in a folder called
EmailTemplates at the root of the application (i.e. next to the executable for console / desktop apps or Windows Services and at the root of the web app for ASP.NET apps).
To let MSBuild copy your email template files to the right place at build time, place them in an
EmailTemplates folder at the root of your project and set the
Copy to Output Directory property of all template files to
Copy if newer:
To retrieve the path of our email template files in code, we'll use the
AppDomain.CurrentDomain.BaseDirectory property. In console apps, desktop apps and Windows Services, this points to the executable's directory (unless you're doing something funky with app domains). Within ASP.NET applications, where the app domain is created by IIS, that property is set to the root of the web app.
The full path of the EmailTemplates folder can be retrieved easily:
var templateFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "EmailTemplates");
Finally, you'll of course need to add a reference to the RazorEngine library in your project:
PM> Install-Package RazorEngine
In the next post, we'll generate our first Welcome email.