Click here to Skip to main content
13,355,538 members (73,213 online)
Click here to Skip to main content
Add your own
alternative version


132 bookmarked
Posted 4 Nov 2004

Email Templates: A generic solution to handle template files

, 4 Nov 2004
Rate this:
Please Sign up or sign in to vote.
A simple, user-friendly and flexible framework that takes care of all your email template files - once and for all.


Most web applications and quite a few desktop apps need to send emails from time to time: registration and activation mails, error warnings, confirmations etc. If not available through a database or CMS, the contents of these emails are mainly stored in text, HTML or XML files. I always considered this handling of template files to be a tedious task, so I came up with this solution that simplifies things remarkably.

Basically, this library handles the organization of arbitrary - optionally localized - template files for you. I really wanted to keep things simple and get a generic solution that does not rely on a database. As a result, you just have to create a single XML file that links to your templates to get things working.

Using the library at runtime is easy. To retrieve and send a localized template to a given recipient, you're done with three lines of code:

//get the template handler
TemplateHandler handler = TemplateHandler.Instance;

//get a french registration template
MailTemplate template = handler["registration", 
                        new CultureInfo("fr"];

//send the template 
handler.Send(template, "");


Setting up the XML file

All templates of your application are configured in a single XML file. You need to tell the framework where to find this file by adding the key Evolve.TemplateConfiguration to the appSettings section of your application configuration file (web.config / App.config). In web applications, you can use the tilde (~) to specify the virtual root of the application.

  <add key="Evolve.TemplateConfiguration" 

          value="~/mailings/templates.config" />

Here is a simple example of a configuration file. It contains the settings for two template groups:

  • Forum registrations: the email templates are available in English and German.
  • E-card notifications: no localization (only an English template).
<?xml version="1.0" encoding="utf-8" ?> 

  <BaseDirectory>template samples</BaseDirectory>


    <!-- first group, localized templates -->
    <TemplateGroup TemplateGroupId="forumregistration"




        <Template IsDefault="true">
          <Subject>your registration</Subject>

        <Template Locale="de">
          <Subject>Ihre Registrierung</Subject>

    <!-- second group, no localization -->
    <TemplateGroup TemplateGroupId="greetingcard"



         <Template IsDefault="true">
           <Subject>You got an eCard from {0}</Subject>



TemplateConfiguration element

This is the root element of the configuration file. It contains general settings that apply to all templates.

BaseDirectoryOptional but recommended. If set, relative file paths of templates will be determined based on this folder. For web applications, you can use the tilde (~) to specify the virtual root.
SmtpServerOptional but recommended. The SMTP server which should be used to send out the messages.
GroupsContains one or more TemplateGroup declarations.

TemplateGroup element

As you can see, a configuration file contains several TemplateGroup elements. Every template group needs to have a unique ID which is used to request a given template.

TemplateGroupIdUnique ID of the group which is used to request templates from the TemplateHandler controller class at runtime.
SenderThe sender address used for emails.
MailFormatThe format of the mail which can be either Text or Html.
FileThe path of the template file. May be absolute or relative.
TemplatesContains one or more Template declarations.

Template element

Every template group contains a Templates listing with one or more Template elements in it. All templates of a given group contain messages for the same process (e.g., a registration confirmation) but in different languages.

LocaleDefines the language of the template. Examples: en (English), de (German), de-ch (German [Switzerland]), fr-ch (French [Switzerland]). At runtime, you're dealing with corresponding CultureInfo objects.
IsDefaultIf set to true, this template is returned if a template for an unknown CultureInfo is being requested at runtime. In this case, the Locale attribute is not needed.
SubjectThe subject of the mail if the template is being sent via the TemplateHandler.
FileThe path of the template file. May be absolute or relative.

Working with the code


A MailTemplate object encapsulates all settings of a template.

TemplateGroupIdThe group ID as defined in the TemplateGroup element of the XML file.
LocaleThe localization information of the template. On the default template of a template group, this is CultureInfo.InvariantCulture.
SubjectThe subject of the mail according to the configuration file.
BodyThe text that was stored in the template file.

You can easily adjust and format the contents of your MailTemplate objects. Every time you request a MailTemplate from the TemplateHandler, a new instance is being created. For details on formatting content, see Formatting your content.


The TemplateHandler controller class gives you access to specific templates by providing two indexers. They take a TemplateGroupId and an optional CultureInfo parameter for localization purpose. Once you have referenced a MailTemplate object, you can process it in your code and eventually send it to one or more recipients using one of the Send overloads.

TemplateHandler handler = TemplateHander.Instance;

//get the default template of the above sample
MailTemplate template1 = handler["forumregistration"];

//get the german template
MailTemplate template2 = handler["forumregistration", 
                         new CultureInfo("de")];

//this returns also the default template, as there is no french template:
MailTemplate template3 = handler["forumregistration", 
                         new CultureInfo("fr")];

//send the template
handler.Send(template3, "");

Hook into the sending process

While just sending a mail through the TemplateHandler may be adequate in most situations, you might want to have more control in some situations. One solution is to create and send the email messages on your own. Another way is to work with the Send overloads that take a delegate of type TemplateCallbackHandler:

public delegate void TemplateCallbackHandler(MailTemplate template, 
                              MailMessage message);

If you use this feature, a callback handler is called by the framework before the MailMessage is sent to the recipients. This gives you full control over the email. The sample below uses the callback to attach a PDF file to the message before it's being sent to the recipient:

private void Send(MailTemplate template)
  TemplateHandler handler = TemplateHandler.Instance;

  //create delegate  
  TemplateCallbackHandler cb;
  cb = new TemplateCallbackHandler(HandleMessageCallback));

  //send message
  handler.Send(template, "info@xxx.xx", cb);

//this is the callback handler
private void HandleMessageCallback(MailTemplate template, 
                                          MailMessage message)
  //add file
  MailAttachment att = new MailAttachment("terms.pdf");

Formatting your content

Most of your templates will consist of dynamic parts: you need to include IDs and passwords, email addresses etc. The framework makes no assumptions about this. Let's say you need to format the subject of an email. In this sample, I just included the format placeholder {0}:

<Template IsDefault="true">
  <Subject>You got an eCard from {0}</Subject>

To adjust the subject, my code would look like this:

MailTemplate template = handler["greetingcard"];
template.Subject = String.Format(template.Subject, "Mr. Tarantino");

handler.Send(template, "info@xxxx.xx");

This would result in a mail with the following subject: You got an eCard from Mr. Tarantino.

The PropertyMapper helper class

However, I've built a simple helper class that automates the assignment of values to placeholders for you. There's no need to use it but it can come handy. The simple idea behind the PropertyMapper class is that you format your template with keys surrounded by special tags:


Hello #?FirstName?#
Your email address is #?EmailAddress?#

Now, let's assume you have a User class that provides properties that match these keys:

What you can do now is feed a User class and a MailTemplate to the PropertyMapper. It will replace all keys that match public properties of the User class with the corresponding property values: #?FirstName?# gets replaced by the value of the FirstName property, #?EmailAddress?# gets the value of the EmailAddress property, and so on. The code looks like this:

//get a user class
User user = new User(123);

//get a mail template
MailTemplate template = GetUserTemplate();

//create a mapper class with the User instance
PropertyMapper mapper = new PropertyMapper(user);

//map the object properties to the template

A few remarks:

  • Note that the opening tags (#?) and the closing tags (?#) are not the same!.
  • If the template contains keys that match no properties, they will not be changed. If you want to replace keys with properties of two different objects, you can easily exchange the objects and call MapTemplate a second time.
  • MapTemplate replaces keys in both Subject and Body of the template.
  • If a property value is null, the key will be replaced by an empty string.
  • You can also submit a string rather than a MailTemplate object by calling MapContent. The submitted string will not be changed but a new string returned.

MailTemplate lifecycle

The diagram below shows all processes from the retrieval of a template to its transmission:

Points of interest

I haven't covered the internals of the framework in this article. However, in case you want to know how things work, the code is well documented and should be easy to understand. Some points of interest:

  • The configuration file is being parsed using .NET's built-in XML deserialisation (using the XmlSerializer class). I love XML serialization as it makes things so easy! The Evolve.Util.MailTemplates.Xml namespace contains classes that match the elements of the configuration file.
  • The PropertyMapper class uses a Regular Expression to retrieve the placeholders of templates. Of course, there is Reflection involved to access the properties of submitted objects.

The ZIP file contains the source, a sample (WinForms-) application that works upon different templates, and a few NUnit tests.


This is the first release of the library, so there will probably be some enhancements / fixes. If you're using the library, I recommend to check back here from time to time. If you prefer to keep notified, you can subscribe to the corresponding newsletter on my site: Newsletter subscription.


This is a handy little library which can make your life a bit simpler if you're working with file-based templates. It's dead simple - and that's exactly what it needs to be. Enjoy :-).


  • 1.0.0: Nov. 3, 2004.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Philipp Sumi
Architect I'm a gun for hire
Switzerland Switzerland
Philipp is an independent software engineer with great love for all things .NET.
He lives in Winterthur, Switzerland and his home on the web is at

You may also be interested in...


Comments and Discussions

GeneralMy vote of 5 Pin
Marco Alessandro Bertschi15-Jan-13 5:18
memberMarco Alessandro Bertschi15-Jan-13 5:18 
GeneralGood job! [modified] Pin
fabiorhodes7-Feb-10 0:01
memberfabiorhodes7-Feb-10 0:01 
Hi Philipp,
I was surfing the internet searching for a good email template system to include in a new ASP.NET website.

Well, the work you did is cool! Thumbs Up | :thumbsup: Big Grin | :-D

All I had to do is to make a few changes so that the library now uses the System.Net.Mail namespace instead of the deprecated System.Web.Mail. Cool | :cool:

For example, I replaced the MailFormat attribute of TemplateGroup with the new "System.Net.Mail-compliant" Laugh | :laugh: IsMailBodyHtml.

Here is the code from the updated Send method in the TemplateHandler class:
//create a new message
MailMessage msg = new MailMessage();
msg.From = new MailAddress(group.SenderAddress);
msg.Body = template.Body;
msg.Subject = template.Subject;
msg.IsBodyHtml = Convert.ToBoolean(group.IsMailBodyHtml);

Smile | :)

Greetings from Italy

Fabio Daniele[^]

PS: are you interested in a (spare time) collaboration to update and, eventually, add new features to the library? I think I will work on writing an XML schema to enhance the library configuration file validation and for using with the Visual Studio Intellisense, too. Wink | ;)
modified on Sunday, February 7, 2010 5:18 AM

GeneralRe: Good job! Pin
Philipp Sumi20-Feb-10 6:12
memberPhilipp Sumi20-Feb-10 6:12 
GeneralMass utility Pin
thatraja19-Jan-10 3:47
memberthatraja19-Jan-10 3:47 
GeneralRe: Mass utility Pin
Philipp Sumi19-Jan-10 3:48
memberPhilipp Sumi19-Jan-10 3:48 
GeneralVery good. (SMTP Auth) Pin
Jack Sparrow - Pirates Alliance24-Jul-08 22:37
memberJack Sparrow - Pirates Alliance24-Jul-08 22:37 
GeneralRe: Very good. (SMTP Auth) Pin
Philipp Sumi2-May-09 6:26
memberPhilipp Sumi2-May-09 6:26 
GeneralRe: Very good. (SMTP Auth) Pin
Brian1262-Nov-15 14:12
memberBrian1262-Nov-15 14:12 
GeneralVERY NICE Pin
James DC27-Feb-08 23:50
memberJames DC27-Feb-08 23:50 
GeneralRe: VERY NICE Pin
Philipp Sumi27-Feb-08 23:53
memberPhilipp Sumi27-Feb-08 23:53 
Questionchanges Required Pin
kprdotnet26-Feb-08 0:04
memberkprdotnet26-Feb-08 0:04 
GeneralRe: changes Required Pin
Philipp Sumi26-Feb-08 4:12
memberPhilipp Sumi26-Feb-08 4:12 
AnswerRe: changes Required Pin
frugalmail19-Feb-10 17:54
memberfrugalmail19-Feb-10 17:54 
QuestionVersion using System.NET.Mail available? Pin
rghubert5-Dec-07 22:23
memberrghubert5-Dec-07 22:23 
AnswerRe: Version using System.NET.Mail available? Pin
Philipp Sumi5-Dec-07 23:40
memberPhilipp Sumi5-Dec-07 23:40 
GeneralRe: Version using System.NET.Mail available? Pin
rghubert7-Dec-07 2:40
memberrghubert7-Dec-07 2:40 
QuestionTemplates static as well? Pin
pyerwoh18-Jul-06 13:10
memberpyerwoh18-Jul-06 13:10 
AnswerRe: Templates static as well? Pin
Philipp Sumi18-Jul-06 13:46
memberPhilipp Sumi18-Jul-06 13:46 
GeneralSet sender email at runtime Pin
Erik Dahlstrand24-Apr-06 0:04
memberErik Dahlstrand24-Apr-06 0:04 
GeneralRe: Set sender email at runtime Pin
Philipp Sumi24-Apr-06 0:10
memberPhilipp Sumi24-Apr-06 0:10 
QuestionMail Template Library Pin
Robel1019-Apr-06 4:17
memberRobel1019-Apr-06 4:17 
AnswerRe: Mail Template Library Pin
Philipp Sumi19-Apr-06 4:27
memberPhilipp Sumi19-Apr-06 4:27 
QuestionTemplateData Pin
Robel1018-Apr-06 17:06
memberRobel1018-Apr-06 17:06 
AnswerRe: TemplateData Pin
Philipp Sumi18-Apr-06 23:12
memberPhilipp Sumi18-Apr-06 23:12 
Generalinvalid emailSystem.Web.HttpException: Pin
wiseylondon16-Dec-05 7:31
memberwiseylondon16-Dec-05 7:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.180111.1 | Last Updated 5 Nov 2004
Article Copyright 2004 by Philipp Sumi
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid