In most web applications there are needs to send emails to users. And most of the time, these emails have to resemble the look and the feel of the web site, keeping the web site's branding and theme in the email messages as well.
On a recent web application that we were working on there were several emails that needed to be be sent and the client had done designs for the emails. The actual emails that were sent had to fill these templates with the users data and be sent out. These emails resembled the web pages that the user would see on the site.
After searching for the best way to send out templated emails, this is the solution we came up with. We wanted a solution that would stick to the MVC architecture that the site was using.
We created a Controller named EmailController. For each email that needed to be sent, we created an ActionResult method. Each ActionResult had a corresponding View. In this view we placed the HTML for the email template, and populated this View though the data passed to it by the ActionResult. Then using screen scraping, required method would populate the View, scrape the HTML and place it on the body of the email and send it out.
The application structure looked like the following. For brevity I have omitted the rest of the files in the application file structure and showing only the files related to sending the emails.
- <Models>
- <Controllers>
- AccountController.cs
- EmailController.cs
- <Views>
Let's consider the Welcome Email. The EmailController.cs will have the following ActionResult.
1: public ActionResult WelcomeEmail(int id) {
2: if (Request.IsAuthenticated == false)
3: return View("AccessDenied");
4:
5: User u = new UserRepository().Get(HttpContext.User.Identity.Name);
6: if (u != null) {
7: ViewData["email"] = u.Email;
8: ViewData["pss"] = u.Password
9: }
10: return View();
11: }
12:
This method first checks if the request is authenticated, which means the current users is logged in. Then it retrieves the user from the UserRepository by the user name saved in the HTTPContext and populates the ViewData fields for email and password.
The WelcomeEmail.aspx page is a ASPX page which is designed using a Table HTML layout with inline CSS. The reason for using a table layout is when it comes to emails the most assured way to ensure that your email will display as intended is to use the HTML table based layout. Some email clients will not render the DIV's as intended. Also, the CSS has to be inline as most email clients tend to ignore the references to external CSS files.
Then on the Account Controller, which is the actual controller that handles the user registration, we call the WelcomeEmail ActionResult.
1: [AcceptVerbs(HttpVerbs.Post)]
2:
3: public ActionResult Register(User user) {
4:
5: // Validate inputs and create the User Account
6:
7: //Add an Auth Cookie
8:
9: //Send email
10:
11: string subject = "Welcome To Our Site";
12:
13: Helpers.Email.SendTemplatedEmail(
14: System.Configuration.ConfigurationManager.AppSettings["emailAddress"],
15: user.Email,
16: subject,
17: Url.Action("WelcomeEmail", "Email", 0, "http") + "/" +u.UserID);
18:
19: Return View();
20:
21: }
22:
The actual email sending is handled by a Helper Method.
1: public static void SendTemplatedEmail(string from,
2: string to,
3: string subject,
4: string templatePath){
5:
6: MailMessage mm = new MailMessage(from, to);
7: mm.Subject = subject;
8: mm.Body = GetEmailBody(templatePath);
9:
10: if (mm.Body != "") {
11: mm.IsBodyHtml = true;
12: SmtpClient smtp = new SmtpClient();
13: smtp.Send(mm);
14: }
15: }
16:
17: public static string GetEmailBody(string templatePath){
18: System.Net.WebClient objWebClient = new System.Net.WebClient();
19: byte[] aRequestedHTML = null;
20: string strRequestedHTML = null;
21:
22: aRequestedHTML = objWebClient.DownloadData(templatePath);
23: System.Text.UTF8Encoding objUTF8 = new System.Text.UTF8Encoding();
24: strRequestedHTML = objUTF8.GetString(aRequestedHTML);
25:
26: return strRequestedHTML;
27: }
The SendTemplateEmail method calls GetEmailBody method to scrape the HTML from the View. This line objWebClient.DownloadData(templatePath) when executed actually loads the View passed to it in the templatePath variable and passes the HTML which we encode and extract as HTML. Then this extracted HTML is set on the email body and the email is sent.