So your application needs to send emails.  So you start with this:

var message = new MailMessage();
message.From = new MailAddress("donoreply@example.com");
message.To.Add(new MailAddress("jimbob@example.com"));
message.Subject = "Password Reset";
message.Body = "Click here to reset your password: "
                      + "http://example.com/resetpassword?token=" 
                      + resetToken);
smtpClient.Send(message);

 

And that works OK, until you want to send some more detailed, data-driven emails. 

Duh, that’s what StringBuilder is for
var message = new MailMessage();
message.From = new MailAddress("donoreply@example.com");
message.To.Add(new MailAddress("jimbob@example.com"));
message.Subject = "Order Confirmation";

StringBuilder body = new StringBuilder();
body.AppendLine(string.Format("Hello {0} {1},", 
                    customer.FullName));
body.AppendLine();
body.AppendLine(string.Format("Thank you for your order.  "
                    + "Your order number is {0}.", 
                    order.OrderNumber));
body.AppendLine("Your order contained:");
foreach(var item in order.LineItems)
{
    body.AppendLine(string.Format("\t-{0}: {1}x${2:c}=${3:c}",
                    item.ProductName,item.Quanity,
                    item.UnitPrice,item.SubTotal));
}
body.AppendLine(string.Format("Order Total: ${0:c}", 
                    order.OrderTotal));
message.Body = body.ToString();

smtpClient.Send(message);

Yes, this is certainly the wrong way to do it.  It’s not flexible, you have to change code every time the email content changes, and it’s just plan ugly.

On the other hand, much of the time especially (early in a project), this is just fine.  Step 1 is admitting you have a problem, but step 0 is actually having a problem in the first place to admit to.  If this works for you, run with it until it hurts. 

I have a lot of code running this way in production right now, and it works swimmingly, because if there a content change I can code it, build it, and deploy it to production in 15 minutes.  If your build/deploy change is small enough, there is virtually no difference between content changes and code changes.

 

Back to the real problem please

But let’s say you really do want to be more flexible, and you really do need to be able update the email content without rebuilding/redeploying the whole world.

How about a tokenized string?  Something like:

string emailTemplate = "Hello {FirstName} {LastName},"
                       + "\r\n\r\nThank you for your order...";

That could work, and I’ve started down this path many times before, but looping messes you up.  If you needed to include a list of order line items, how would you represent that in a template?

What else?  If you are in 2003, the obvious answer is a to build an XSLT stylesheet. Serialize that data object as XML, jam it into your XSLT processor, and BAM you have nicely formatted HTML email content.  Except writing those stylesheets are a nightmare.  Maintaining them is even worse.  If you don’t have interns that you hate, you’re going to be stuck with it.

So yes of course you could use XSLT.  Or you could just shoot some heroin.  Both will make you feel good very briefly in the beginning, but both will spiral our of control and turn your whole life into a mess.  Honestly, I would not recommend either.

OK, so how about some MVC templatey type things?

The whole templating idea behind XSLT is actually a good idea, it’s just the execution that is painful.  We have an object, we have a view that contains some markup and some presentation-specific logic, we put them all into a view engine blender and get back some silky smooth content.

If you were in ASP.NET MVC web application, you could use the Razor view engine (or WebForms view engine, if you’re into that kinda thing) to run the object through the view engine and get some HTML, but that plumbing is a little tricky.  Also, what if you are not in an MVC web app, or any web app at all?  If you are looking to offload work from your website to background processes, moving all of your email sending to a background Window service is a great start, but it’s tough to extract out and pull in that Razory goodness.

Luckily some nice folks extracted all of that out into a standalone library (https://github.com/Antaris/RazorEngine), so you can execute Razor views against objects in a few limes of code:

string view = "Hello @Model.CustomerFirstName @Model.CustomerLastName, thank you for your order.";
var model = new { CustomerFirstName="Ty", CustomerLastName="Webb" };
var html = RazorEngine.Razor.Parse(view, model);

 

That is awful pretty. But if course we still need to write wrap that up with some SMTP code, so let’s take it a step farther. 

Razor Chocolate + SMTP Peanut Butter = MMDB.RazorEmail

Let’s say I’m lazy.  Let’s say I just want to do this:

new RazorEmailEngine().SendEmail("Order Receipt", model, view, 
                        new List<string>{"jimbob@example.com"}, 
                        "donoreply@example.com");

I couldn’t find anything that was this simple, so built one.  Here it is: https://github.com/mmooney/MMDB.RazorEmail

Just import that into your project via NuGet (https://nuget.org/packages/MMDB.RazorEmail/), and you can start sending emails right away. 

It works in both web apps and and Windows apps (we wrote it specifically because we needed to support this from a Windows Service).

It can use your app.config/web.config, settings or you can pass in different values.  It also has some rudimentary attachment handleing that will need to be improved.

Take a look, try it out, and let me how how it works for you at @mooneydev

Leave a reply

required

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>