0

I am looking for recommendations on how to handle the ability to queue and send different types of emails using Azure WebJobs.

Before sending the email there needs to do some business logic to compose, populate and then send. So say that I have 10 different types of emails

2 examples of emails

1) when a booking is confirmed I would like to something like

var note = new BookingConfirmNotification() { BookingId = 2 } 
SomeWayToQueue.Add(note)

2) or when I need reminder the user to do something

var reminder = new ReminderNotification() { UserId = 3 }
SomeWayToQueue.Add(reminder, TimeSpan.FromDays(1)

Is it better to create a queue for each of different types of emails with QueueTrigger on WebJob .. or is there a better way to do this?

Update

So I thought you might be able to add different Function/Methods with different strongly-typed classes to trigger different methods, but that doesnt seem to work.

public void SendAccountVerificationEmail(
        [QueueTrigger(WebJobHelper.EmailProcessorQueueName)] 
        AccountVerificationEmailTask task, TextWriter log)
    {
        log.WriteLine("START: SendAccountVerificationEmail: " + task.UserId);

        const string template = "AccountVerification.cshtml";
        const string key = "account-verification";

        PrepareAndSend(user.Email, "Account confirmation", template, key, task, typeof(AccountVerificationEmailTask));

        log.WriteLine("END: SendAccountVerificationEmail: " + task.UserId);
    }

    public void SendForgottonPasswordEmail(
        [QueueTrigger(WebJobHelper.EmailProcessorQueueName)] 
        ForgottonPasswordEmailTask task, TextWriter log)
    {
        const string template = "ForgottonPassword.cshtml";
        const string key = "forgotton-password";

        PrepareAndSend(user.Email, "Forgotton password", template, key, task, typeof(ForgottonPasswordEmailTask));
    }

This doesn't work - different methods are fired randomly when a message is added to the queue

How can I implement something like this using WebJobs?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
user600314
  • 662
  • 1
  • 5
  • 17

2 Answers2

2

Are you saying the "compose/populate" logic is somewhat heavy, that's why you want to queue it? What process/entity is creating these "send email" tasks?

I could see you having an Azure Queue where email requests are queued. Assuming you're using the WebJobs SDK (you should be if you're dealing with Azure Storage Queues, etc.) you can have a function monitoring that queue that sends the messages. The WebJobs SDK Extensions include a SendGrid email binding. You can see an example close to what you're describing here. This sample sends emails based on incoming queue messages. Using the SDK in this way, you'll get automatic retry support, poison queue handling, etc.

mathewc
  • 13,312
  • 2
  • 45
  • 53
  • mathewc, thanks for the reply. the logic isn't that heavy but it shaves some processing at the website end. Sending emails isn't a problem either.. but more so my question would be, are you recommending having separate queues for different emails or.. ? – user600314 Nov 26 '15 at 17:36
  • Either same queue for all messages with some sort of "type" property in the message, or different queues. I think one queue would be fine - you'll get parallelism on that one queue, so you don't really need multiple queues, unless you foresee the need to have different queue processing parameters for the different message types. – mathewc Nov 26 '15 at 18:07
  • thanks for your reply mathewc, I've made an update to my question above. If you suggest a single queue then how would I do what I'm proposing in my update? – user600314 Nov 29 '15 at 23:08
  • If you're only monitoring a single queue, then you'll only have a single function and your message must include a discriminator value for you to switch on internally. – mathewc Nov 30 '15 at 01:12
1

Regarding your updated question. When multiple consumers consume a queue, they will "round-robin" meaning that the messages are distributed between all the available consumers. This explains why the methods appear to be firing randomly.

Something to think about. You might want to invert things and use queues to capture your user's interactions.

Off the back of that you can perform one or more actions.

For example.

_bus.Send(new BookingCreatedEvent{Ref="SomeRef", Customer="SomeCustomer"});

or

_bus.Send(new BookingCancelledEvent{Ref="SomeRef");

The benefit of this is you can choose what to do on the consuming side. Right now you want to send an email but what if you want to also log to a database or send a record into your CRM?

If you switch to Azure Service Bus Topics/Subscriptions, you can have multiple handlers for the same event.

  public static void SendBookingConfirmation([ServiceBusTrigger("BookingCreated","SendConfirmation")] BookingCreatedEvent bookingDetails)
    {
        // lookup customer details from booking details 
        // send email to customer
    }

  public static void UpdateBookingHistory([ServiceBusTrigger("BookingCreated","UpdateBookingHistory")] BookingCreatedEvent bookingDetails)
    {
        // save booking details to CRM
    }
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jon Hilton
  • 173
  • 2
  • 15