Going Postal - Generating email with ASP.NET MVC View Engines

Preamble

The .NET framework provides a simple API for sending email. I assume you are already acquainted with the handy namespace System.Net.Mail. However, dynamically generating the content of an email is still a bit tricky. Code that concatenates strings and variables is no fun to write or read!

What we need is a way to write text (or html) templates which will be rendered with some data. ASP.NET MVC already has exactly this in the form of Views. So let's reuse the view engine infrastructure to create our emails.

I created a simple library called Postal that does just that. Read on to find out more.

Postal in action

First, let's see what an email view will look like. I'm using the excellent Razor view engine (coming with MVC3).

Example.cshtml

To: @View.To
From: example@website.com
Subject: @View.Subject

Hello,
This email was generated using Postal for asp.net mvc on @View.Date.ToShortDateString()
Message follows:
@View.Message

Thanks!

This email is just plain text, but it could contain HTML instead for richer formatting options.

Notice also that we are defining some email headers (To, From, Subject) at the top. Postal makes it easy to define everything about the email in a single file, rather than having to set the headers in code. Postal will parse the headers out of the rendered view and apply them to the outgoing email message.

Since this is a regular Razor view, we can use the handy View dynamic object to access view data. This data is populated from code. Let's see an example controller action that will send this email.

public ActionResult Send(string to, string subject, string message)
{
    dynamic email = new Email("Example");
    email.To = to;
    email.Subject = subject;
    email.Message = message;
    email.Date = DateTime.UtcNow;

    service.Send(email);

    return RedirectToAction("Sent");
}

This code creates a new Email object, passing the name of the email view to use. Postal will look for email views in ~/Views/Emails/. So our email view is at ~/Views/Emails/Example.cshtml.

We've typed the Email object as dynamic. This lets us define the properties we want at runtime, without having to create an explicit view model class. I like this lightweight approach. (If you don't, feel free to send me a pull request!)

The Email object is building up a ViewDataDictionary internally, ready to send to the view for rendering.

Once the email object is ready to send, we're calling the service object. This is a field of the controller.

public class HomeController : Controller
{
    // In real code this should be injected by an IoC container.
    IEmailService service = new EmailService(ViewEngines.Engines);

    // ... action methods here ...
}

The EmailService manages finding the view, rendering the text, parsing the headers and finally sending the email.

Email is sent using the System.Net.Mail.SmtpClient class. You can configure the SMTP settings in web.config. For example, we can simple write the emails to a folder for testing purposes.

<configuration>
    <system.net>
        <mailSettings>
            <smtp deliveryMethod="SpecifiedPickupDirectory">
                <specifiedPickupDirectory pickupDirectoryLocation="c:\email"/>
                <network host="localhost"/>
            </smtp>
        </mailSettings>
    </system.net>
</configuration>

Get the code

Postal is something I put together in an afternoon. So the usual warnings about code you find on the internet apply! That said, head over to GitHub and grab the source:

https://github.com/andrewdavey/postal

There's a sample project in there as well that puts the code from this post together into a basic web application.

If you want to change Postal, fix bugs, etc, please fork the repository and send me pull requests. I love to see people getting involved with open source projects. (Postal has the MIT License.)

For questions and discussion, either follow me on twitter @andrewdavey or leave a comment here.

Would you like access to the sample code repository?

Subscribe to my web development mailing list.

No spam, just occasional web development tips, posts and sample code. Unsubscribe at any time.

Comments
blog comments powered by Disqus