User Control Email Templates in asp.net
23 Mar 2010Just about every project i work on needs to send customized emails and everytime I hate doing it. Inspired by some answers in this stackoverflow question I thought I’d give a simple .ascx based email template system a dig.
First thing I did was set up a base class for template controls to inherit from. This class inherits from UserControl and has the methods to render the control to a string. It also has methods and properties to set up “tags” to replace in the email body.
public class EmailTemplateBase : UserControl { public EmailTemplateBase() { Tags = new Dictionary<string, string>(); } public Dictionary<string, string> Tags { get; set; } protected string GetTagValue(string tagName) { return Tags[tagName].Value; } protected string GetTagValue(string tagName, string defaultValue) { string val = GetTagValue(tagName); return string.IsNullOrEmpty(val) ? defaultValue : val; } public string RenderTemplate() { StringBuilder sb = new StringBuilder(); StringWriter sw = new StringWriter(sb); Html32TextWriter htw = new Html32TextWriter(sw); RenderControl(htw); // Get full body text return sb.ToString(); } }
Below is a simple example from the project I am working on it is used for sending feedback emails This template is really simple but because the rendering uses the same page cycle as a regular control you can style and render the template how ever you like.
<p> Feedback from System sent <%= GetTagValue("sent")%> </p> <p> <strong>Sender: </strong> <%= GetTagValue("sender")%><br /> <strong>Subject: </strong> <%= GetTagValue("subject")%> </p> <p> <strong>Message: </strong> <br /> <%= GetTagValue("message").Replace(Environment.NewLine, "<br />")%> </p>
I created a class to easily load and use the email templates within my code by passing the location of the template on the server.
public class EmailTemplate { private readonly EmailTemplateBase _template; public EmailTemplate(string templateLocation) { Page p = new Page(); _template = (EmailTemplateBase) p.LoadControl(templateLocation); } public Dictionary<string, string> Tags { get { return _template.Tags; } set { _template.Tags = value; } } public string Render() { return _template.RenderTemplate(); } }
Below is how I use the templates in my code, sending using a basic email sender class I have (or better still fluent email).
var template = new Common.Email.EmailTemplate("~/Emails/Templates/Feedback.ascx"); template.Tags.Add("sender", sender); template.Tags.Add("sent", sent); template.Tags.Add("subject", subject); template.Tags.Add("message", message); string body = template.Render(); EmailSender.Send(from, fromName, to, toName, subject, body);
I could probably try encapsulate a bit more of the email sending inside my template (toName, toAddress etc) to clean this up a bit so feel free to tell me how come I suck.