How (not) to send emails from your web site – Service Bus Queues (Part 2)

February 1, 2016 · 3 minute read

In part 1 we tried (and ultimately failed) to handle customer emails using a database

Now we needed to come up with an alternative.

In many ways this was a lesson in choosing the most appropriate tool for the job and that’s where messaging and queues came in.

“An Englishman, even if he is alone, forms an orderly queue of one”

George Mikes

Our requirement was to take the customer’s attempt to contact us and process it as a background task without keeping the customer waiting in the meantime. This is exactly what queues are really good at.

Before we get into details, here’s what it looked like when we swapped out our database for a queue.

So now instead of writing to a database table, we were sending messages to an Azure Service Bus queue.

var client = QueueClient.CreateFromConnectionString(connectionString, "send-email-queue");

var sendEmailCommand = new SendEmailCommand {
    Subject = "Email from contact us page",
    Body = "Hi, please can you send me more details about the super email sender",
    CustomerEmail = "jon@azureinsights.net"
};

client.Send(new BrokeredMessage(sendEmailCommand));

Once a message is on the queue it will remain there until it is completed or it exceeds it’s time to live (TTL).

We kept the topshelf  service but switched from polling a database to receiving messages from a service bus queue.

  client.OnMessage((message) =>
  {
      try
      {
          var sendEmailCommand = message.GetBody<SendEmailCommand>();
  
          emailer.SendEmail(
              to: "someone@abc.com",
              @from: sendEmailCommand.CustomerEmail, 
              subject: sendEmailCommand.Subject, 
              body: sendEmailCommand.Body);
  
          message.Complete();
      }
      catch (Exception)
      {
          message.Abandon();
      }
  });

Here the emailer service does the actual work of sending an email. Should there be any kind of exception we abandon the message and it remains on the queue ready to be picked up again.

Unlike the database polling approach, messages are locked once a client receives them (meaning no-one else can process them) and then released once processing is abandoned.

If no exceptions are thrown then the message is completed and no other client instance will pick it up.

As a solution, this was much cleaner and more reliable than our initial database-centric approach.

If at first you don’t succeed…

A significant benefit of using queues was that we could control how many times to attempt to deliver the message. In service bus this is handled by the Maximum Delivery Count option.

Once you hit that number of attempts the message is moved to a dead letter queue where it can be reviewed but will not be processed until you decide what to do with it.

Did you say something about the top shelf?

We initially kept on using the Topshelf service because we were already familiar with the technology.

This actually proved to be a short-lived arrangement as we migrated to an Azure Worker role soon after. This is essentially like a windows service but running in the cloud.

However, there is now an alternative solution using Azure Web Jobs.

But what about my data?

One thing we lost with this approach was data for reporting e.g. which customers had been emailed.

In part three, we look at how to remedy this and perform multiple actions on the same message by using Azure’s Topics and Subscriptions.

 

Join the Practical ASP.NET Newsletter

Ship better Blazor apps, faster. One practical tip every Tuesday.

I respect your email privacy. Unsubscribe with one click.