Saturday, March 10, 2012

NServiceBus 3.0 - SMTP Transport

NServiceBus 3.0 is fresh out of GitHub, and I'm wading through the code and testing out different concepts. You might learn something from this code (the code in this blog post ;), but its far from production stable.


With NServiceBus 3.0 there is a FtpTransport that enable us to send/receive messages over FTP instead of MSMQ. RFC 2549 is not supported, but before we start with that, lets try something simpler: Send messages using SMTP.

Looking at the code for FtpMessageQueue, ISendMessages and IReceiveMessages are the interfaces that NServiceBus uses for sending and receiving TransportMessages.

.NET includes a SmtpClient, but no POP3 support, so we will now limit ourself to sending messages. Let's start.

The preferred way I like to host NServiceBus applications, are using the NServiceBus.Host.exe. This host has the concept of one input queue and one error queue. At the moment we will not process any input messages (in lack of an pop3 client), but we will send out messages.


It could be a message that would launch a nuclear bomb, brew coffee or buy a movie ticket, but for the example let's use:

public class MyMessage : IMessage
  public string Foo;
  public string Bar;


There are various ways to interact with the Host, IWantToRunAtStartup is an interface you can decoracte a class with and it will be called at startup. We'll combine the marker interface IConfigureThisEndpoint and IWantCustomInitialization that will setup the smtptransport.

public class Runner :
  public IBus Bus { get; set; }

  public void Run()
    string line;

    while ((line = Console.ReadLine()) != null)
      Bus.Send(new MyMessage { Bar = "bar", Foo = "foo" });

  public void Stop()

  public void Init()


The config file is the preferred place to put any configuration that will affect the application; connectionstrings, paths, ....

<?xml version="1.0" encoding="utf-8" ?>
    <section name="SmtpQueueConfig"
              type="SmtpTransport.SmtpQueueConfig, SmtpTransport" />
    <section name="UnicastBusConfig"
              type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
    <section name="MessageForwardingInCaseOfFaultConfig"
              type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />

  <MessageForwardingInCaseOfFaultConfig ErrorQueue="errors"/>

      SmtpServer = ""
      Port       = "587"
      EnableSsl  = "true"
      From       = ""
      UserName   = ""
      Password   = ""/>

      <add Messages="SmtpTransport" Endpoint="" />


UnicastBusConfig and MessageForwardingInCaseOfFaultConfig is part of NServiceBus, SmtpQueueConfig is created by me and looks like:

public class SmtpQueueConfig : ConfigurationSection
  [ConfigurationProperty("SmtpServer", IsRequired = true)]
  public string SmtpServer
    get { return this["SmtpServer"].ToString(); }
    set { this["SmtpServer"] = value; }

  [ConfigurationProperty("Port", IsRequired = true)]
  public int Port
    get { return (int)this["Port"]; }
    set { this["Port"] = value; }

  [ConfigurationProperty("EnableSsl", IsRequired = true)]
  public bool EnableSsl
    get { return (bool)this["EnableSsl"]; }
    set { this["EnableSsl"] = value; }

  [ConfigurationProperty("From", IsRequired = true)]
  public string From
    get { return this["From"].ToString(); }
    set { this["From"] = value; }

  [ConfigurationProperty("UserName", IsRequired = true)]
  public string UserName
    get { return this["UserName"].ToString(); }
    set { this["UserName"] = value; }

  [ConfigurationProperty("Password", IsRequired = true)]
  public string Password
    get { return this["Password"].ToString(); }
    set { this["Password"] = value; }

No big surprises here. If you now goes back to the Init method of the Runner class you will see that we call .SmtpTransport() on the Configure class. This is an extension method:

public static class ConfigureSmtpQueue
  public static Configure SmtpTransport(this Configure config)
    var smtpQueue = config.Configurer.ConfigureComponent<SmtpMessageQueue>(
    var cfg = Configure.GetConfigSection<SmtpQueueConfig>();

    if (cfg != null)
      smtpQueue.ConfigureProperty(t => t.SmtpServer, cfg.SmtpServer);
      smtpQueue.ConfigureProperty(t => t.Port, cfg.Port);
      smtpQueue.ConfigureProperty(t => t.EnableSsl, cfg.EnableSsl);
      smtpQueue.ConfigureProperty(t => t.From, cfg.From);
      smtpQueue.ConfigureProperty(t => t.UserName, cfg.UserName);
      smtpQueue.ConfigureProperty(t => t.Password, cfg.Password);

    return config;

It's the binding between the configuration and our transport class. Then finally:


public class SmtpMessageQueue : ISendMessages, IReceiveMessages
  public string SmtpServer { get; set; }
  public int Port { get; set; }
  public bool EnableSsl { get; set; }
  public string From { get; set; }
  public string UserName { get; set; }
  public string Password { get; set; }

  public void Send(TransportMessage message, Address address)
    using (var client = new SmtpClient(SmtpServer, Port))
      client.EnableSsl = EnableSsl;
      client.Credentials = new NetworkCredential(UserName, Password);

      var serializer = new JavaScriptSerializer();

      var mailMessage = new MailMessage(From, address.ToString())
                          Subject = "NServiceBus TransportMessage",
                          Body = serializer.Serialize(CreateMailMetaData(message));

        new Attachment(
          new MemoryStream(message.Body),


  private MailMetaData CreateMailMetaData(TransportMessage message)
    return new MailMetaData
      CorrelationId = message.CorrelationId,
      Id = message.Id,
      IdForCorrelation = message.IdForCorrelation,
      ReplyToAddress = message.ReplyToAddress.ToString(),
      TimeToBeReceived = message.TimeToBeReceived,
      Header = message.Headers.Select(
        x => new HeaderPair
               Name = x.Key,
               Value = x.Value }).ToList()

  public void Init(Address address, bool transactional)
    // TODO: add a pop3 client and poll for new messages

  public bool HasMessage()
    return false;

  public TransportMessage Receive()
    return null;

public class MailMetaData
  public string CorrelationId;
  public string Id;
  public string IdForCorrelation;
  public string ReplyToAddress;
  public TimeSpan TimeToBeReceived;
  public List<HeaderPair> Header;

public class HeaderPair
  public string Name;
  public string Value;

Does it work? This is the email in gmail:

Yes! We'll fix the pop3 / receiver next week.

No comments:

Post a Comment