Town Crier – An open-source e-mail templating engine for .NET

In medieval times, town criers were the primary means of making announcements to a community. Nowadays a man with a bell is a very imaginative – but not particularly practical – means of communication.

One common scenario, especially in the business world, is the need to send out an email to a large number of people. Of course a big anonymous email lacks the friendliness of the local loud-mouthed peasant and so we try to personalise the emails with individuals’ names etc.

I suspect most .NET developers have come across this problem at some point in their career. This generally leads to a lot of messy string concatenation and trying to manhandle the System.Net.Mail.SmtpClient into doing what you want. With text-based emails this is ugly, when HTML is involved it becomes a world of pain.

Town Crier is a project I have been working on to simplify this scenario. The basic workflow for sending a templated e-mail is as follows:

  1. Create an email template.
    This can be either a plain-text or HTML file (or both). Tokens to be replaced are written like this: {%= customersname %}

    Sample email templates:
    Sample HTML e-mail template
    Sample text e-mail template

  2. Write some very simple code in the CLR language of your choice, in this case C#:
    var factory = new MergedEmailFactory(new TemplateParser());
    
    var tokenValues = new Dictionary<string, string>
                          {
                              {"name", "Joe Bloggs"},
                              {"age", "21"}
                          };
    
    MailMessage message = factory
        .WithTokenValues(tokenValues)
        .WithSubject("Test Subject")
        .WithHtmlBodyFromFile(@"templates\sample-email.html")
        .WithPlainTextBodyFromFile(@"templates\sample-email.txt")
        .Create();
    
    var from = new MailAddress("sender@test.com", "Automated Emailer");
    var to = new MailAddress("recipient@test.com", "Joe Bloggs");
    message.From = from;
    message.To.Add(to);
    
    var smtpClient = new SmtpClient();
    smtpClient.Send(message);
    

    Of course it’s then trivial to loop through rows in a database, populate the dictionary and perform a “mail-merge” programatically.

    One final handy tip – there is included a handy extension method to allow you to save the message to a .eml file:

    message.Save(new FileStream(@"output.eml", FileMode.CreateNew));

That’s pretty much it! It’s fairly basic but I’ve found it to be very useful. It’s also my first open-source project so please be nice!

I am releasing it under the Lesser GNU Public Licence. Go grab the sources at GitHub.

CC-GNU LGPL

About these ads

16 thoughts on “Town Crier – An open-source e-mail templating engine for .NET

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #646

  2. Have you thought about using nvelocity as your templating engine? It may well give you much more power and allow you to concentrate on the email sending side

    K

    • I avoided this in order to try to keep things as simple as possible. It’s certainly an interesting idea though – it should be fairly easy to write an implementation of ITemplateParser which uses nvelocity.

  3. Pingback: Southern BITS of Technical Goodness » More Top Notch & Useful Web Resources

  4. I like the direction. If you’re going to go fluent, go all the way!

    MailMessage message = factory
    .WithValues(tokenValues)
    .WithSubject(“Test Subject”)
    .WithHtmlBodyFromFile(@”templates\sample-email.html”)
    .WithPlainTextBodyFromFile(@”templates\sample-email.txt”)
    .To(“recipient@test.com”)
    .To(“recipient2@test.com”, “Joe Schmoe”)
    .Cc(“recipient3@test.com”)
    .From(“sender@test.com”, “Automated Emailer”)
    .Send(new SmtpClient())
    .Save(“filename.txt”);

    For every To/Cc/Bcc call, just add it to the collection.

  5. Did something similar using the StringTemplate library. We needed to put tables in our emails and it had good support for loops, etc.

  6. How about localization? I need to send out an email in the language of the user (we support 12 languages). I would rather not create 12 different pairs of email files. Any suggestions?

    • Interesting question but I’m not quite sure what you’re suggesting. I guess you’re going to have to write the translations at some point. I suppose you could try to pull in the string resources from .resx files but that seems like a lot more effort than just writing the 12 different templates.

  7. Hello, great stuff!

    A couple questions:

    1) Does this use CDO as a backend?
    2) Does this support embedded images?

    • Hi. Glad you like it.
      1) No, it only relies on the .NET mail API. It does support exporting the mails to .eml files. If you want to use exchange I believe you can just save the emails into the mail pickup folder.

      http://technet.microsoft.com/en-us/library/bb124230.aspx

      2) Yes but you will need to upload the images to a publicly accessible URI and use an tag in the email. There isn’t currently any support for automatically uploading the images automatically or importing them from local files on disk.

  8. Question does this have support for conditional segments? Say for example I only want a certain segment to appear depending on some value I have in a database, is this possible?

    • There is no support for this at the moment I’m afraid. You could probably use an MVC view engine such as Razor/NVelocity if you need more advanced functionality.

  9. it would be better if you add 2 more routines like WithHtmlBodyFromString and WithPlainTextBodyFromString. as a result if user mail template save any where or in database then they can load those html or text into string variable and assign those text to those above method which i talk about here. i will be looking for you suggestion. thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s