.Net Core Email Sender Library with Razor Templates (.cshtml) contained in it

Some time ago we needed to include email sender in our application. There were plenty of email services that we can choose from (MailGun, SendGrid, Mandrill, etc…). We choosed SendGrid since it has 40,000 emails for your first 30 days, then 100 email/day forever.

“six assorted-color mail boxes” by Mathyas Kurmann on Unsplash

Our application consists of multiple separate .net core web applications. We use the SendGrid nuget package for sending emails. So we wanted to manage all the emails from one place for all of the applications. That’s why we made a separate class library as our email client service which also contains all the Razor templates that are required for our application.

Working version of this class library is available on GitHub https://github.com/Gago993/EmailClientLibrary/tree/EmailClientRazorLight

From here I will start explaining the technical implementation of the web class library and how you can easily use it if you need it. On GitHub there are two projects TestWebApp which is the .net core web application and EmailClient which is the .net class library.

The Client Web Application

The TestWebApp (which is you .net code application) need just simple 3 steps for using this email class library.

  1. Add Reference to the Email Class Library
  2. Add email settings in appsettings.json (SendGrid API key and Sender Email)
  3. Configure Service and Configuration Dependency Injection in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
var emailSettings = Configuration.GetSection("EmailSettings");
services.Configure<EmailSettings>(emailSettings);
services.AddTransient<IEmailClientSender, EmailClientSender>();
...
}

After all the above steps are completed the application is ready to use the Email Client Service to send the emails. Next step is to inject the IEmaiClientSender interface in the HomeController

...
private readonly IEmailClientSender emailClientSender;
public HomeController(IEmailClientSender emailClientSender)
{
this.emailClientSender = emailClientSender;
}
...

Example of using this service and sending an email is available in SendEmail controller method.

...
public async Task<IActionResult> SendEmail(EmailViewModel emailViewModel)
{
await emailClientSender.SendHelloWorldEmail(emailViewModel.Email, emailViewModel.Name);
return RedirectToAction("About");
}
...

Email Client Class Library

Now lets go to the Email Client Library. It consists of 4 folders and 2 additional files.

  1. Helpers — Wrapper for the Razor Light Parser and Embeded Resource Reader
  2. Models — View Models classes used in the Templates
  3. Services — Public functions for each email Template that needs to be send
  4. Templates — Email (.cshtml) documents (Email Razor Templates)
  5. Additional EmailClient.cs and EmailSettings.cs classes

So lets get dipper in the implementation. It all starts from the Services/EmailClientSender.cs service which contains the logic for sending all the email templates. In the example HomeController in the Web Application we call the SendHelloWorldEmail method which has the following code.

public async Task SendHelloWorldEmail(string email, string name){
  string template = "Templates.HelloWorldTemplate";
RazorParser renderer = new RazorParser(typeof(EmailClient).Assembly);

var body = renderer.UsingTemplateFromEmbedded(template,new HelloWorldViewModel { Name = name });

await SendEmailAsync(email, "Email Subject", body);
}

Basically it makes two things.

  1. Set the email template path and the viewmodel to the RazorParse and gets parsed html
  2. Call SendEmailAsync private method to send the Email

Now, we are gonna look deeper at this 2 steps.

We use the UsingTemplateFromEmbedded method from the RazorParser.cs helper class.

public string UsingTemplateFromEmbedded<T>(string path, T model)
{
var template = EmbeddedResourceHelper.GetResourceAsString(_assembly, GenerateFileAssemblyPath(path, _assembly));
var result = Parse(template, model);
return result;
}

This method uses EmbeddedResourceHeler to get the email template for the given path. Next thing is to use the RazorLight Engine to Compile the email template with the given model.

async Task<string> ParseAsync<T>(string template, T model)
{
var project = new InMemoryRazorLightProject();
var engine = new EngineFactory().Create(project);
return await engine.CompileRenderAsync<T> (Guid.NewGuid().ToString(), template, model);
}

At the end email template is returned as html ready to be send by the SendGrid library.

Now, we go back to the SendHelloWorldEmail method where after getting the email body (parsed html) it forward it to the SendEmailAsync method.

private async Task SendEmailAsync(string email, string subject, string message)
{
var client = new SendGridClient(_emailSettings.ApiKey);
var from = new EmailAddress(_emailSettings.From);
var to = new EmailAddress(email);
...
var htmlContent = message;
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
  ...
response = await client.SendEmailAsync(msg);
...
}

Here SendGrid library is used for setting the API, from email, to email and the email content (body) and at the end calling the SendEmailAsync with the generated email.

Also another important thing is that all the email templates are set as EmbeddedResources. This can be done in Visual Studio with right click on the email template and in Properties setting the Build Action as Embedded Resource. Or by editing the .csproj file and setting the following tag as in the example below.

...
EmbeddedResource Include="Templates\HelloWorldTemplate.cshtml" />
...
Working version of this class library is available on GitHub https://github.com/Gago993/EmailClientLibrary/tree/EmailClientRazorLight