If you're sending email via Exchange Web Services, cache the service URL for a while!

In my recent series of posts about sending emails through Office 365 from an Azure Function, triggered by a blob being uploaded to Azure storage, I noted that:

because of the amount of time Office 365 autodiscover takes, it's not a particularly quick process

There's a few references that a quick search returned that back this up:

  1. EWS Best Practices: Use Autodiscover…  - "It’s good practice to refresh the cached URL for a given mailbox every 24 hours or so"
  2. How to: Set the EWS service URL by using the EWS Managed API - "you might want to cache the URL value you get from Autodiscover and manually set the EWS service URL with this cached value"
  3. Stack Overflow: How to cache Exchange web service API autodiscoverurl? - "please make AutoDiscover request at least once every 24 hours" (in an answer from a Program Manager @ Microsoft for Mail, calendar, & contact APIs for Office 365, Exchange, Outlook.com, Outlook Outlook/Exchange connectivity)

By instrumenting the console app I put together in my post Creating an Azure function that triggers when a blob is uploaded - Sending an email via Office 365  (very quickly and lazily!) to find out how long each email takes to send when run in a loop over 10 iterations:

var durations = new List();
for (int i = 0; i < 10; i++)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    SendEmail(credentials, username, "<RECIPIENT_EMAIL_ADDRESS>", "Subject Line", $"<h1>Content of email generated at {DateTime.Now}</h1>");
    watch.Stop();
    durations.Add(watch.ElapsedMilliseconds);
}

var average = durations.Average();

I got an average duration of 12,246.2 milliseconds, or just over 12 seconds per email. By tweaking the code inside the SendEmail method so that it caches the URL, by adding a property to store it in and tweaking the code that calls the AutodiscoverUrl method:

if (EWSUrl == null)
{
    service.AutodiscoverUrl(fromAddress, RedirectionUrlValidationCallback);
    EWSUrl = service.Url;
}
else
{
    service.Url = EWSUrl;
}

All of a sudden, the average time taken drops down to 1,578.9 milliseconds. Being very lazy (i.e. not going back and checking the values), I can extrapolate that the ten requests took a total of 15,789 milliseconds, so deducting the average from the previous test (time taken when calling Autodiscover) of 12,246 milliseconds gives a remainder of 3,543 milliseconds.

Finally (and stretching the numbers even further into potential inaccuracy) dividing by 9 gives a result of 393 milliseconds. So, by caching the service url, the average time taken to send an email will reduce from c. 12 seconds to c. 1/3 of a second (when the time taken to autodiscover is stripped out from the latter). That's a pretty significant win.

Next up: How do I cache the service URL in an Azure function?

About Rob

I've been interested in computing since the day my Dad purchased his first business PC (an Amstrad PC 1640 for anyone interested) which introduced me to MS-DOS batch programming and BASIC.

My skillset has matured somewhat since then, which you'll probably see from the posts here. You can read a bit more about me on the about page of the site, or check out some of the other posts on my areas of interest.

No Comments

Add a Comment