Generating HTML emails with RazorEngine - Part 02 - Basics: generating your first email

This is the second part of a 10-part blog series. You'll find a list of all the posts in this series in the introductory post. Make sure to review the Before we start section in the introductory post.

All the source code is on GitHub. Comment? Bug? Open an issue on GitHub.


As indicated in the introductory post, we'll work from a console application.

The email template

For this example, we'll generate a simple Welcome email. We'll start with a basic model for our email:

namespace ConsoleApplication.Models
{
    public class UserModel
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public bool IsPremiumUser { get; set; }
    }
}

We can then implement our email template in the same way as we would implement an ASP.NET MVC Razor view. Here, we'll use a strongly-typed model:

@model ConsoleApplication.Models.UserModel
 
<!DOCTYPE html>
 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Welcome</title>
</head>
<body>
    <p>
        Hi @Model.Name,
    </p>
    <p>
        Thanks for signing up to <a href="http://awesomesite.com">our awesome site</a>!
    </p>
 
    @if (!Model.IsPremiumUser)
    {
        <p>
            To make the most of it, <a href="http://awesomesite.com/upgrade">upgrade to our premium package now</a>!
        </p>
    }
 
    <p>John, Founder</p>
    
</body>
</html>

As mentioned in the introductory post, place this template in a .cshtml file. Don't worry about any error or warning message the Visual Studio editor might throw at you. They are just a design-time annoyance and won't prevent your app from compiling and running successfully. We'll look at how to get rid of them in the next post.

RazorEngine also supports dynamic models in the same way ASP.NET MVC's Razor View Engine does. The code on GitHub has an example of this.

Note: in your email templates, make sure to always either use fully-qualified type names or import the necessary namespaces with the @using directive. If your template references a class that isn't fully-qualified and that hasn't had its namespace imported, you will get a TemplateCompilationException at runtime. We'll explain why this happens and how we can make things better in the next couple of posts.

Generating the email's HTML body

Generating your email from this template is a simple matter or instantiating RazorEngine's TemplateService class and calling its Parse() method passing the content of the template and your model as parameters:

You're done!

IMPORTANT: Before you go off, make sure that you read at least the next post in this series as there are a few essential features of RazorEngine that you must know in order to use it properly and effectively.

Note: In addition to the TemplateService class, the RazorEngine library also exposes Razor, a static class that implements a very thin facade over the TemplateService interface. For some reason, most of the RazorEngine examples you'll find on the web use the Razor class instead of directly using TemplateService.

I don't really see any reason for using the Razor class so we won't using it in this series. Since Razor is a static class, using it means hiding the RazorEngine dependency deep down the implementation, preventing you from being able to surface this dependency at the class interface level. This complicates testing and maintenance. In addition, most methods in Razor are one-liners that map directly to methods of the same name in TemplateService so using Razor doesn't simplify or shorten the code. As far as I can see, Razor only adds another and largely uncessary level of abstraction.

Things that won't work

That are a number of functionalities that won't work out of the box with RazorEngine, or at least not in the same way as they do with the ASP.NET MVC Razor View Engine. This includes layouts, partials and URL generation. We'll look at how to get these functionalities with RazorEngine in the next posts of this series.

Sending the email

This of course isn't specific to RazorEngine, but the sake of completeness let's send this email.

First add your SMTP settings to your App.config file. We'll include sender information there as well so that we don't have to hardcode it:

You'll probably have different SMTP settings in development and in production. Thankfully, thanks to the awesome job that Sayed Ibrahim Hashimi and Chuck England have done with their SlowCheetah Visual Studio add-on, you can get App.config transforms for your console app (or desktop app or Windows Service) that work in the exact same way as Web.config transform work for ASP.NET applications.

So add SlowCheetah to your project:

PM> Install-Package SlowCheetah

Then right-click your App.config and choose Add Transform. This will add a Debug and a Release transform for your App.config file. Simply add your production settings in the App.Release.config file:

And send:

// Send the email
var email = new MailMessage()
{
    Body = emailHtmlBody,
    IsBodyHtml = true,
    Subject = "Welcome"
};

email.To.Add(new MailAddress(model.Email, model.Name));
// The From field will be populated from the app.config value by default

var smtpClient = new SmtpClient();
smtpClient.Send(email);

Run and if you're using smtp4dev, you should now see the new message pop-up:

Of course, in a real-world application, you'll probably be sending emails asynchronously:

await smtpClient.SendMailAsync(email);

In the next post of this series, we'll look at a few more basic but essential features of RazorEngine that will speed up email generation and make your life easier.