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.