Render simple MVC razor views as email templates

Today I'd like to show you a fairly simple way to render razor views as your email templates. The intent here isn't to take over your marketing campaign with this method but it does work for auto-responder type emails. What we'll do is simply assume we're handling a form submission and we'd like to send a formatted response.

The ingredients

We will create the following items to use for our evil bidding:

  • A service to execute our code from a form handler (controller)
  • A model to handle the to/from/subject/body, etc
  • A  model to use for our razor view
  • A razor view to use with our model
  • A helper to render our view to a string

The service

Let's start by creating a service class to be used inside the form handler controller:

using System.Net.Mail;
using System.Web.Mvc;
using TestMvc2.Helpers;
using TestMvc2.Models;

namespace TestMvc2.Services
{
    public class SimpleEmailService
    {
        public string GetRenderedTemplate(ControllerContext controllerContext, string pathToPartial, object model)
        {
            return TransformationHelper.RenderRazorViewToString(controllerContext, pathToPartial, model);
        }

        public void Send(SimpleMailMessage message)
        {
            using (var mailMessage = new MailMessage()
            {
                From = new MailAddress(message.From),
                Subject = message.Subject,
                IsBodyHtml = message.IsHtml
            })
            {
                //to
                mailMessage.To.Add(message.To);

                //cc
                if (!string.IsNullOrEmpty(message.Cc))
                {
                    mailMessage.CC.Add(message.Cc);
                }

                //bcc
                if (!string.IsNullOrEmpty(message.Bcc))
                {
                    mailMessage.Bcc.Add(message.Bcc);
                }

                mailMessage.Body = message.Body;

                using(var smtp = new SmtpClient()){
                    smtp.Send(mailMessage);
                }
            }
        }
    }
}

The service exposes two methods, 'GetRenderedTemplate' and 'Send'. GetRenderedTemplate requires a controller context which will be available so long as you pass it in from your form handler. It also needs to know the partial you wish to use along with the model that should be paired with it. The template is rendered with a helper:

using System.IO;
using System.Web.Mvc;

namespace TestMvc2.Helpers
{
    /// <summary>
    /// Helper class that handles transformations.
    /// </summary>
    public static class TransformationHelper
    {
        /// <summary>
        /// Renders a named razor view from a given model.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="viewName">Name of the view.</param>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public static string RenderRazorViewToString(ControllerContext context, string viewName, object model)
        {
            using (var sw = new StringWriter())
            {
                var viewResult = System.Web.Mvc.ViewEngines.Engines.FindPartialView(context, viewName);
                var viewContext = new ViewContext(context, viewResult.View, new ViewDataDictionary(model), new TempDataDictionary(), sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }
    }
}

Next we need to define the model that describes our SimpleEmailMessage:

namespace TestMvc2.Models
{
    public class SimpleMailMessage
    {
        public string To;
        public string From;
        public string Cc;
        public string Bcc;
        public string Subject;
        public string Body;
        public bool IsHtml = true;
    }
}

I skipped attachments for brevity but you can easily make them apart of this if you need to send them. The new service should be done in a manner like the following code in your form controller:

var emailService = new SimpleEmailService();

//if you call this from your form handler controller, you'll have the ControllerContext you need for this call
var renderedTemplate = emailService.GetRenderedTemplate(ControllerContext, "~/Views/MailTemplates/Template1.cshtml", new SampleEmailModel
{
    Title = "Mr.",
    Name = "Willy Wonka"
});

emailService.Send(new SimpleMailMessage
{
    To = "[email protected]",
    Cc = "[email protected], [email protected]",
    From = "[email protected]",
    Bcc = "[email protected]",
    Subject = "Blah",
    Body = renderedTemplate,
    IsHtml = true
});

Now that we know how to call our new service, all we need to do is to define a model and a razor view. The model we'll use is very simple and you can change it to suit your taste, the view is just an idea of what you can do:

namespace TestMvc2.Models
{
    public class SampleEmailModel
    {
        public string Title;
        public string Name;
    }
}
//~/Views/MailTemplates/Template1.cshtml

@model TestMvc2.Models.SampleEmailModel

<h2>Hello @Model.Title @Model.Name</h2>
<p>Fusce convallis metus id felis luctus adipiscing. In dui magna, posuere eget, vestibulum et, tempor auctor, justo. Nullam accumsan lorem in dui. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Maecenas ullamcorper, dui et placerat feugiat, eros pede varius nisi, condimentum viverra felis nunc et lorem.</p>

When the code is run, an email will be sent to the recipients that are configured. I've configured my local build to save the emails to a local file for testing purposes. You can do that by updating your 'web.config' SMTP section like this:

<system.net>
    <mailSettings>
      <smtp deliveryMethod="SpecifiedPickupDirectory">
        <specifiedPickupDirectory pickupDirectoryLocation="C:\dev\mail" />
      </smtp>
    </mailSettings>
  </system.net>

If I open up the file that is generated, it will look like this:

X-Sender: [email protected]
X-Receiver: [email protected]
X-Receiver: [email protected]
X-Receiver: [email protected]
X-Receiver: [email protected]
MIME-Version: 1.0
From: [email protected]
To: [email protected]
Cc: [email protected], [email protected]
Date: 11 May 2016 15:12:14 -0400
Subject: Blah
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

=0D=0A=0D=0A<h2>Hello Mr. Willy Wonka</h2>
...

Summary

So that's it! Sending a razor formatted email is pretty easy. You can easily add several templates with several different model types. Once the form submits you can evaluate the submission and send off a confirmation email that has been nicely formatted with a model and a view. Full code examples can be found here.