Building Dynamic Html Template Newsletter Application In Asp.Net MVC With Hangfire and Sendgrid

n

nn

nnThis tutorial teaches you how to create and send dynamic newsletter email using Sengrid API and Hangfire.
n
nSendgrid is a cloud-based email service to solve the challenges of reliably delivering emails. You can read more about them on their website.
n
nHangfire make it easy to perform background processing in .NET with no window service or separate process required. It is backed by persistent storage. It is open source.
nnn
nnn
n

nWhat you will learn

nAfter reading this article you will know how to perform background task in Asp.Net MVC application using Hangfire. You will also know how to create a dynamic html template driven email and send to subscribers.
n
n

nWhat we will be building

nWe are going to be building a cart reminder like we have in an e-commerce application. There will be three customers each of which had added products to their cart for more than two days but never complete their order.
n
nThe email sent will contain those products, images, quantity and price. It will also contain an action button to checkout.
n
nSince we now know what we are going to be building let start building it.
n
n

nSign up for Sendgrid

nSign up for a sendgrid account. Generate and copy you API key.
n
n

nThe ASP.Net MVC Project

nCreate an ASP.Net MVC web application and install Sendgrid API like so:
n
n

n

n
n

nThe Database Structure

nThe application database will be very simple. We will have three tables namely Product, Cart and Customer. The product table will hold all the products, the customer table holds all customer and the cart table holds all product that has been added to cart by each customer. The structure of the tables is shown below:
nnn
nnn
n

n

n
n

nInstall and Configure Hangfire

nRight click the references node withing your visual studio and choose Manage NuGet Packages, and search for Hangfire. Make sure you install the one by Sergey Odinokov.
n
nAfter installation, add a startup class to the root of your Web Application by right clicking on the project name and select add class, search for OWIN Startup class and then add it.
n
nModify the newly added Startup class like so:
n
n

using System;nusing System.Threading.Tasks;nusing Hangfire;nusing Microsoft.Owin;nusing Owin;nn[assembly: OwinStartup(typeof(ASPNetNewsLetterHangfire.Startup))]nnnamespace ASPNetNewsLetterHangfiren{n    public class Startupn    {n        public void Configuration(IAppBuilder app)n        {n            GlobalConfiguration.Configurationn                .UseSqlServerStorage("HangFireConnectionString");nn            app.UseHangfireDashboard();n            app.UseHangfireServer();n        }n    }n}nnn

n
nAs I mentioned before, Hangfire uses a persistent storage to track queue jobs, in our own case we have specified SQL Server by calling the UseSqlServerStorage method and passing the connectionstring of our database. Hangfire will create its own tables.
n
n

nSeeding the Database

nI have added three customers and three product in their cart. The database with the data can be found in the source code download.
n
n

nSendgrid Email Service Class

nCreate a folder named helpers within your web application and add a class named EmailHelper like so:
n
n

    public class EmailHelpern    {n        string apiKey = ConfigurationManager.AppSettings["SendGripAPIKey"];n        string fromEmail = ConfigurationManager.AppSettings["FromEmail"];n        string fromEmailDisplayName = ConfigurationManager.AppSettings["FromEmailDisplayName"];nn        public async Task Send(string subject, string to, string body, string cc = null, string bcc = null)n        {nn            var mailClient = new SendGridClient(apiKey);n            var message = new SendGridMessage()n            {n                From = new EmailAddress(fromEmail, fromEmailDisplayName),n                Subject = subject,n                HtmlContent = bodyn            };nn            message.AddTo(new EmailAddress(to));nn            if (!string.IsNullOrWhiteSpace(cc)) { message.AddBcc(new EmailAddress(cc)); }nn            if (!string.IsNullOrWhiteSpace(bcc)) { message.AddBcc(new EmailAddress(bcc)); }nn            var response = await mailClient.SendEmailAsync(message);n            return response.StatusCode.ToString();nn        }n    }nn

n
nIn the code above we got apikey, fromEmail and fromDisplay name from our ApSetting in the web.config.
n
nThe Email HTML Template
nI added two html files in the App_Data folder. The first one is named ProductListTemplate.html and the second one is named MailTemplate.html.
nnn
nnnYou can find the template in the source code.n
nThe next thing is to write the method that will be used to build the template. Create a class within the Helpers folder named TemplateHelper and add the following codes:nn
n

 public class TemplateHelpern    {n        public static string BuildProductListTemplate(string productName, decimal productPrice, string productImage)n        {nnn            var body = string.Empty;n            using (StreamReader reader = new StreamReader(Path.Combine(HttpRuntime.AppDomainAppPath,"~/App_Data/ProductListTemplate.html")))n            {n                body = reader.ReadToEnd();n            }nn            body = body.Replace("{productImage}", productImage)n                .Replace("{productName}", productName)n                .Replace("{productPrice}", productPrice.ToString("#,##.00"));nn            return body;n        }nnn        public static string BuildEmailTemplate(string productList, string customerName)n        {nn            var body = string.Empty;n            using (StreamReader reader = new StreamReader(Path.Combine(HttpRuntime.AppDomainAppPath, "~/App_Data/MailTemplate.html")))n            {n                body = reader.ReadToEnd();n            }nn            body = body.Replace("{customerName}", customerName)n                .Replace("{productList}", productList);nn            return body;n        }n    }nn

nAs you can see, I read the template file into stream and then replace those tokens with the actual value from database.n
n
n
n

nRead Customer Data And Send Mail

nCreate a new Controller named NewsController and add the following code:
n
n

public async Task SendMails()n        {n            var newsEntities = new NewletterEntities();n            var customers = newsEntities.Customers;n            foreach (var item in customers)n            {n                var customerproducts = (from p in newsEntities.Productsn                                        join crt in newsEntities.Cartsn                                        on p.ProductId equals crt.ProductIdn                                        join cust in newsEntities.Customersn                                        on crt.CartId equals cust.CustomerId.ToString()n                                        where cust.CustomerId == item.CustomerIdn                                        select newn                                        {n                                            productName = p.ProductName,n                                            productImage = p.ProductImage,n                                            productPrice = p.Pricen                                        }).ToList();nn                StringBuilder orders = new StringBuilder();n                if (customerproducts.Any())n                {n                    foreach (var prod in customerproducts)n                    {n                        var productTemplate = TemplateHelper.BuildProductListTemplate(prod.productName, prod.productPrice, prod.productImage);nn                        orders.Append(productTemplate);n                    }nn                    var emailBody = TemplateHelper.BuildEmailTemplate(orders.ToString(), item.CustomerName);nn                    var mailService = new EmailHelper();n                    var mailResponse = await mailService.Send("Order Reminder", item.Email, emailBody);n                }n            }n            n        }nn

nNow open the Starup.cs class and add this code:n
nnn
nnn
n

 app.UseHangfireDashboard("/jobs");n            var ctrl = new NewsController();n            RecurringJob.AddOrUpdate(() => ctrl.SendMails(), Cron.MinuteInterval(10));n

nNow the full Startup.cs file should look like this:nn
n

 public class Startupn    {n        public void Configuration(IAppBuilder app)n        {n            GlobalConfiguration.Configurationn                .UseSqlServerStorage("HangFireConnectionString")n                .UseDashboardMetric(DashboardMetrics.FailedCount);nn            app.UseHangfireDashboard("/jobs");n            var ctrl = new NewsController();n            RecurringJob.AddOrUpdate(() => ctrl.SendMails(), Cron.MinuteInterval(10)); //Send Every 10 minutes          n            app.UseHangfireServer();n        }n    }n

nI made a reference to the NewsController and then add Hangfire recurring job and set it to fire every 10 minutes. You can read more in hangfire website for more configurations. The app.UseHangfireDashboard(“/jobs”) will allow us view hangfire recurring jobs via http://yourwebapp:port/jobs.
n
nI hope this helps. Thanks for stopping by.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top