Windows Azure enables you to be more creative by leveraging web/worker roles, parallelism, queuing, service bus, distributed cache, and a lot more. I just want to share an easy way to delegate the email component to Azure Worker Role and Azure Queue storage. Sending email is a very basic and common scenario for web application. Using SmtpClient directly from your website is simple but it does have some drawbacks. For example if an email is generated during a post back, it sometimes requires lot of data from a database. In such scenario, user may experience a long wait time on their browser. One can solve this by using multi-threads approach to send email asynchronously but that may uses up web role resources.
If this is scenario sounds familiar. You may consider delegating the email processing to a separate Azure Worker. By doing a little bit extra work, you will get a lot out of this.
Some benefits are:
- Better asynchronous web performance
- Keep below email server limit
- Better scalability and control
- Email sent retry ability
On a high-level, we need to create email manager class, Azure storage entities and classes for the Email queue, table storage and Azure Worker Role project itself. The following diagram illustrate how this system work:
1. Web Role uses the Email Manager Class to serialize the email message into the Azure Queue
2. Worker Role at a specific interval will check for queued emails
3. Worker Role pop each email from the queue and send it [Retry if necessary]
4. Saved Email message into Table Storage for record keeping
You can download the sample VS 2012 project here.
In the app.config and web.config, you have to change the settings to use proper SMTP server and password to work:
<!-- email stuff -->
<add key="Email.MailTo" value="firstname.lastname@example.org" />
<add key="Email.Address" value="email@example.com" />
<add key="Email.DisplayName" value="MyWebsite" />
<add key="Email.Host" value="smtp.gmail.com" />
<add key="Email.Port" value="587" />
<add key="Email.User" value="firstname.lastname@example.org" />
<add key="Email.Password" value="changeme" />
<add key="Email.UseDefaultCredentials" value="False" />
<add key="Email.EnableSsl" value="True" />
<add key="Email.QueueInterval" value="100000" />
<add key="Email.NumberOfQueueMessage" value="10" />
The Email.QueueInterval is in millisecond, and together with the NumberOfQueueMessage, you can limit the max emails sent per time interval. For this example, we only sent a max of 10 emails in every 100 seconds.
What is next?
With this simple email worker role working, I can imagine there are lots of useful improvements one can do:
1) For example we can modify the code the re-queue failed emails in case the mail server went down, and makes the system more redundant.
2) The worker role can worked to take scheduled email delivery using a different queue.
3) Adding binary serialization to handling attachment
4) Using multiple queues to handle priority
5) Process the queued emails and aggregating emails to same users