Razor View Page as Email Template
You do not need any special libraries to render a Razor view to a string in an ASP.NET MVC application.
Here is how you do it in MVC Core 3
public static class ViewToStringRenderer
{
public static async Task<string> RenderViewToStringAsync<TModel>(IServiceProvider requestServices, string viewName, TModel model)
{
var viewEngine = requestServices.GetRequiredService(typeof(IRazorViewEngine)) as IRazorViewEngine;
ViewEngineResult viewEngineResult = viewEngine.GetView(null, viewName, false);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + string.Join("\r\n", viewEngineResult.SearchedLocations));
}
else
{
IView view = viewEngineResult.View;
var httpContextAccessor = (IHttpContextAccessor)requestServices.GetRequiredService(typeof(IHttpContextAccessor));
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new RouteData(), new ActionDescriptor());
var tempDataProvider = requestServices.GetRequiredService(typeof(ITempDataProvider)) as ITempDataProvider;
using var outputStringWriter = new StringWriter();
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model },
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
outputStringWriter,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return outputStringWriter.ToString();
}
}
}
In the controller
string str = await ViewToStringRenderer.RenderViewToStringAsync(HttpContext.RequestServices, $"~/Views/Emails/MyEmailTemplate.cshtml", new MyEmailModel { Prop1 = "Hello", Prop2 = 23 });
In ConfigureServices()
in Startup.cs
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Here is how you do it in MVC 5
public static class ViewToStringRenderer
{
public static string RenderViewToString<TModel>(ControllerContext controllerContext, string viewName, TModel model)
{
ViewEngineResult viewEngineResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + viewEngineResult.SearchedLocations);
}
else
{
IView view = viewEngineResult.View;
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary<TModel>(model), new TempDataDictionary(), stringWriter);
view.Render(viewContext, stringWriter);
return stringWriter.ToString();
}
}
}
}
Then, from the controller
ViewToStringRenderer.RenderViewToString(this.ControllerContext, "~/Views/Emails/MyEmailTemplate.cshtml", model);
After you have the email content, it is easy to send the email using MailMessage
and SmtpClient
.
Email messages only understand two formats: plain text and HTML. Since Razor is neither, it will need to be processed by some engine, so that it gives you back the generated HTML.
That's exactly what happens when you use Razor in ASP.NET MVC, behind the scenes. The Razor file is compiled into a internal C# class, that gets executed, and the result of the execution is the string content of the HTML, that gets sent to the client.
Your problem is that you want and need that processing to run, only to get the HTML back as a string, instead of being sent to the browser. After that you can do whatever you want with the HTML string, including sending it as an e-mail.
There are several packages that include this power, and I've used Westwind.RazorHosting successfully, but you can also use RazorEngine with similar results. I would prefer RazorHosting for standalone non-web applications, and RazorEngine for web applications
Here is a (sanitized) version of some of my code - I'm using Westwind.RazorHosting to send razor-formatted emails from a windows service, using a strongly typed view.
RazorFolderHostContainer host = = new RazorFolderHostContainer();
host.ReferencedAssemblies.Add("NotificationsManagement.dll");
host.TemplatePath = templatePath;
host.Start();
string output = host.RenderTemplate(template.Filename, model);
MailMessage mm = new MailMessage { Subject = subject, IsBodyHtml = true };
mm.Body = output;
mm.To.Add(email);
var smtpClient = new SmtpClient();
await smtpClient.SendMailAsync(mm);
Have you took a look at MVC Mailer
?
It's a free package available from GitHub (https://github.com/smsohan/MvcMailer)
There is a step by step guide for it too https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
It's also on Nuget too. https://www.nuget.org/packages/MvcMailer
Essentially it will parse your razor view into html.