Generic Email Templates
Almost every website like to communicate with its users by automatic emails for example “Registration Details”, “Forget Password” or even “Newsletters“. So you need to have some kind of mechnisim to design a template for each email type visually and will able to parse them before sending.
I have worked on this on some project and i thought it may be helpful for others.
Database Design

Data Access Layer
These are the methods we need to implement in our Data Access Layer.
/// <summary>
/// To Load Email Template by Code
/// </summary>
/// <param name=”code”></param>
/// <returns></returns>
public Model.EmailTemplate EmailTemplateLoadByCode(string code) {}/// <summary>
/// To Load Email Template by ID
/// </summary>
/// <param name=”templateID”></param>
/// <returns></returns>
public Model.EmailTemplate EmailTemplateLoad(int templateID){}/// <summary>
/// To Update Email Tempalte
/// </summary>
/// <param name=”template”></param>
/// <returns></returns>
public bool EmailTemplateUpdate(Model.EmailTemplate template){}/// <summary>
/// To Load All Variables of a Tempalte
/// </summary>
/// <param name=”templateId”></param>
/// <returns></returns>
public DataTable EmailVariableLoadByTemplate(int templateId){}/// <summary>
/// To Get a Variable Value based on Primary key value
/// </summary>
/// <param name=”tablename”></param>
/// <param name=”field”></param>
/// <param name=”pkey”></param>
/// <param name=”pkeyValue”></param>
/// <param name=”fieldValue”></param>
public void GetTemplateVariableValue(string tablename, string field, string pkey, string pkeyValue, ref string fieldValue){}
Only the last method is tricky so i am adding its proceedure as well.
Create proc [dbo].[EmailTemplate_GetTemplateVariableValue]( @tablename varchar(100), @field varchar(100)
, @pkey varchar(100), @pkeyValue varchar(100))
as
exec(’select ‘ + @field + ‘ from ‘ + @tablename +’ Where ‘ + @pkey + ‘=’ + @pkeyValue )
Business Logic Layer
Just need to wrap the DAL methods or its up to you how you handle them.
Email Parser
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Text.RegularExpressions ;
namespace EmailTemplates{
public class Parser
{
public static string Parse(int templateid, System.Collections.Specialized.NameValueCollection valuesCollection){
Model.EmailTemplate template = BLL.EmailTemplateLoad(templateid);
if (template != null)return ReplaceVariables(template.EmailTemplateID, template.BodyText, valuesCollection);
return string.Empty;}
private static string ReplaceVariables(int templateId,string bodyText, System.Collections.Specialized.NameValueCollection valuesCollection){
const string HEADER = “{{HEADER}}”;const string FOOTER = “{{FOOTER}}”;char[] ch = new char[1];ch[0] =
‘,’;string[] pkeyValue = null;
string fieldValue = string.Empty;string pattern = string.Empty;
string temp = string.Empty;try
{
StringBuilder mailbody = new StringBuilder();if (bodyText.Trim().Length > 0){
System.Data.DataTable dtVariable = BLL.EmailVariableLoadByTemplate(templateId );mailbody.Append(bodyText );
for (int j = 0; j < dtVariable.Rows.Count; j++){
pattern = “{{” + dtVariable.Rows[j]["VariableName"].ToString() + “}}”;
Regex reExp = new Regex(pattern, RegexOptions.IgnoreCase);MatchCollection matches = reExp.Matches(bodyText ); for (int i = 0; i < matches.Count; i++){
if (matches[i].Value.ToUpper() == HEADER){
mailbody.Replace(matches[i].Value, ReplaceHeaderFooter(Enum.GetName(typeof(EnumModel.EmailTempate), EnumModel.EmailTempate.HEADER)));}
else if (matches[i].Value.ToUpper() == FOOTER){
mailbody.Replace(matches[i].Value, ReplaceHeaderFooter(Enum.GetName(typeof(EnumModel.EmailTempate), EnumModel.EmailTempate.FOOTER)));}
else
{
fieldValue = string.Empty;temp = valuesCollection.Get(dtVariable.Rows[j]["ClassMemberName"].ToString());pkeyValue = temp.Split(ch);
if (pkeyValue.Length == 1){
GetTemplateVariableValue(dtVariable.Rows[j]["TableName"].ToString(), dtVariable.Rows[j]["FieldName"].ToString(), dtVariable.Rows[j]["PriKey"].ToString(), pkeyValue[0], ref fieldValue);
if (dtVariable.Rows[j]["VariableType"] != DBNull.Value){
if (Convert.ToByte(dtVariable.Rows[j]["VariableType"]) == Convert.ToByte(Enum.Parse(typeof(EnumModel.VariableType), EnumModel.VariableType.Password.ToString()))){
string password = Common.Utility.DecryptString(fieldValue);mailbody.Replace(matches[i].Value, password);
}
else if (Convert.ToByte(dtVariable.Rows[j]["VariableType"]) == Convert.ToByte(Enum.Parse(typeof(EnumModel.VariableType), EnumModel.VariableType.Date.ToString()))){
mailbody.Replace(matches[i].Value, Convert.ToDateTime(fieldValue).ToLongDateString());}
else if (Convert.ToByte(dtVariable.Rows[j]["VariableType"]) == Convert.ToByte(Enum.Parse(typeof(EnumModel.VariableType), EnumModel.VariableType.Time.ToString()))){
mailbody.Replace(matches[i].Value, Convert.ToDateTime(fieldValue).ToLongTimeString());}
else if (Convert.ToByte(dtVariable.Rows[j]["VariableType"]) == Convert.ToByte(Enum.Parse(typeof(EnumModel.VariableType), EnumModel.VariableType.DateTime.ToString()))){
mailbody.Replace(matches[i].Value, fieldValue);
}
else if (Convert.ToByte(dtVariable.Rows[j]["VariableType"]) == Convert.ToByte(Enum.Parse(typeof(EnumModel.VariableType), EnumModel.VariableType.Encrypted.ToString()))){
mailbody.Replace(matches[i].Value, Common.Utility.EncryptString(fieldValue));
}
}
else
{
mailbody.Replace(matches[i].Value, fieldValue);
}
}
}
}
}
return mailbody.ToString();}
}
catch (Exception ex) { }return string.Empty;}
public static string ReplaceHeaderFooter(string code){
Model.EmailTemplate template = BLL.EmailLoadByCode(code);
if (template != null)return template.BodyText;
return string.Empty;}
private static void GetTemplateVariableValue(string tablename, string field, string pkey, string pkeyValue, ref string fieldValue){
if (tablename.Trim().Length > 0 && field.Trim().Length > 0)BLL.GetTemplateVariableValue(tablename, field, pkey, pkeyValue, ref fieldValue);else
fieldValue = String.Empty;}
}
public class EnumModel
{
// Here you need to specify the TemplateKey column value from EmailTemplate Table
public enum EmailTempate
{
Header,
Footer,
NewsLetter,
UserRegisteration,
ForgotPassword,
MassEmal,
ProfileApproved,
}
//Possible Variable Types are handled in parser but if needed can be supported more.
public enum VariableType
{
Password = 1,
Date = 2,
Time = 3,
DateTime = 4,
Encrypted = 5,
}
//This is a ClassMemberName from EmailVariable Table
public enum VariableClassMemberName
{
SubscriberID,
UserId,
PackageId,
StatusID,
CompanyID,
}
}
}
Here Header and Footer are EmailTemplates but can be treated as a Variable to be included in other emails for consistent layout of all templates like if you want to have a flash banner and some links on the top and copyrights statement on bottom of every template then instead of doing this in all templates just create a Header and Footer template and just add a variable in each template and it will automatically placed there. In this way you create as many sections of your each template as you would like to.
UI
I have designed the UI for editing the template just like following but its up to you how you design the UI.

Thanks to Telerik for their wonderful RichTextBox control
Calling Code
System.Collections.Specialized.NameValueCollection values = new System.Collections.Specialized.NameValueCollection();
values.Add(EnumModel.VariableClassMemberName.UserId.ToString(), user.UserID.ToString());
Note that in above code we are adding the value of UserId whose password needs to be sent.
Now call the Parser.Parse method to get the bodytext for email.
like this
string mailBody=Parser.Parse(forgotPasswordEmailId, values);
finally write some your own code to send email with this mail body :)
Filed under: .NET | 1 Comment
Tags: automatic, email, generic, newsletters, parser, templates
some sample email template designs http://www.campaignmonitor.com/gallery/