Testing a SendMail activity with WF4

Many applications send email.  After all it is the preferred binding for async app to human communication.  I noticed that many of my colleagues were creating samples that simulate email by dropping a text file into a directory.  Then they would open the file and copy and paste a GUID into a form.  There is a much better way of course.  In the real world people would send an HTML mail with a link that brings you back to the website with the GUID in place.

Nearly everyone has done this with a web site where you register with the site, they send you an email to confirm and then you click a link in the email to complete the registration process.  I decided to build out this scenario using a workflow to manage the registration process but then I ran into the issue of how to test the email.

At first I thought I would just use Hotmail.  This would work for a demonstration but you have to have network connectivity and verifying that the message arrived would require coding to open the mailbox with POP3 and look for a particular message.  Then I found an easier way.  You can configure the SmtpClient to drop mail messages into a folder rather than send them.

Of course, many of you will say “Duh! I can’t believe Ron didn’t know about this…”.  Well it was news to me so I’m sure that some people didn’t know about it either so here is how it works.

First off, here is the very simple SendMail activity (using .NET 4 Beta 1)

    1: public class SendMail : CodeActivity
    2: {
    3:     public InArgument<string> From { get; set; }
    4:     public InArgument<string> Recipients { get; set; }
    5:     public InArgument<string> Subject { get; set; }
    6:     public InArgument<string> Body { get; set; }
    7:     public InArgument<bool> IsBodyHtml { get; set; }
    8:     protected override void Execute(CodeActivityContext context)
    9:     {
   10:         SmtpClient client = new SmtpClient();
   11:         MailMessage message = new MailMessage(From.Get(context),
   12:             Recipients.Get(context), Subject.Get(context), Body.Get(context));
   13:         message.IsBodyHtml = IsBodyHtml.Get(context);
   14:         client.Send(message);
   15:     }
   16: }

Now I want to test my SendMail class.  So I created a Unit Test project and added an app.config file with the necessary configuration magic.

    1: <?xml version="1.0" encoding="utf-8" ?>
    2: <configuration>
    3:   <system.net>
    4:     <mailSettings>
    5:       <smtp deliveryMethod="SpecifiedPickupDirectory">
    6:         <specifiedPickupDirectory pickupDirectoryLocation="c:\maildrop"/>
    7:       </smtp>
    8:     </mailSettings>
    9:   </system.net>
   10: </configuration>

Now all that I need to do is write the test.  I want to be sure that when I send a mail that a file ends up in the c:\maildrop directory.  The file will have a random GUID as the name.  I’m not worried about reading the file to be sure that it contains the correct text.  That would be testing the SmtpClient class which I assume works properly.

    1: [TestMethod]
    2: [DeploymentItem("MyActivities.dll")]
    3: public void ShouldSendMail()
    4: {
    5:  
    6:     // Remove all files from the drop location
    7:     if (Directory.Exists(mailDrop))
    8:         Directory.Delete(mailDrop, true);
    9:     Directory.CreateDirectory(mailDrop);
   10:  
   11:     // Create and send the message
   12:     WorkflowInvoker.Invoke(new MyActivities.SendMail()
   13:     {
   14:         From = "test@tempuri.org",
   15:         Recipients = "foo@bar.org, baz@foo.com",
   16:         Subject = "Test HTML message",
   17:         IsBodyHtml = true,
   18:         Body = messageBody
   19:     });
   20:  
   21:     // Find the message in the drop location
   22:     var messages = Directory.EnumerateFiles(mailDrop);
   23:     Assert.AreEqual(1, messages.Count());
   24: }

And the really cool thing is that you can open this file with Windows Live Mail and click the link if you want to demonstrate how it works.

image

I decided to screencast this code check it out

endpoint.tv Screencast - Spike on Workflow Managed Email Verification