Throttling coming to Outlook API and Microsoft Graph

Update 12/4/17: Updated the post with the current limits.

On April 21, we will be enabling throttling on the Outlook REST APIs (accessed via https://outlook.office.com/api or https://outlook.office365.com/api), and on the Outlook-related endpoints of the Microsoft Graph (accessed via https://graph.microsoft.com). We wanted to give developers some advanced warning to make sure you were prepared!

What's the limit?

The limit is 10000 requests per 10-minute period, per user (or group), per app ID. This means that your app can make at most 10000 requests to a single user's mailbox in a 10-minute period. If your app is requesting data from multiple users simultaneously, requests to one user do not impact the limit for another user.

What APIs are subject to this limit?

Outlook APIs

All APIs accessed via https://outlook.office.com/api or https://outlook.office365.com/api, including:

Microsoft Graph

Only the Outlook-related APIs in the Microsoft Graph are subject to this limit. Microsoft Graph requests to non-Outlook resources (such as OneDrive files) would not count against this limit. The following resources (and their child resources) are subject to the limit:

Can I track my usage?

Each response from the API will contain specific headers that can help you track your current state in regards to the rate limit.

Note: Only the Outlook REST API endpoints return these rate limit tracking headers. The Microsoft Graph endpoint does not return these headers.

Header name Description
Rate-Limit-Limit The maximum number of requests that the app is permitted to make per minute for the current user or group
Rate-Limit-Remaining The number of requests remaining in the current rate limit window
Rate-Limit-Reset The time at which the current rate limit window resets in UTC time

What happens if my app exceeds the limit?

You'll get a 429 response back from the server. The response will include a Retry-After header, which will specify the number of seconds your app must wait until it can make more requests for the particular user or group. It will also include a Rate-Limit-Reason header with a human-readable string that articulates the reason for the throttled request.

How do I avoid being throttled?

If your app is currently making more than the allowed number of requests, there may be some ways that you can reduce the number of requests without reducing the amount of data your app is accessing. Some general tips to reduce requests are:

  • Increasing page size: Using the $top parameter to increase the number of items returned per page when requesting a set of items. The default page size if the $top parameter is omitted is 10, which isn't very efficient if you're requesting a large number of items. You can increase this limit up to 1000.
  • Reduce number of GET for single items: As much as possible, get the data your app needs from lists (such as GET /me/messages) rather than requesting each individual entity (such as GET /me/messages/{message-id}). Using the $select parameter to request the fields your app needs can help you control what data is returned back in lists.

Call to action

Based on the usage rates we've seen to date, we believe that most apps out there will not exceed the limit. However, we encourage you to review your app and determine if you are likely to exceed the limits. If so, you should look at ways to reduce the number of requests or make sure you have error handling in place to handle 429 responses and retry in an appropriate amount of time.

We will be publishing more detailed documentation on these limits in the near future.

Comments

  • Anonymous
    April 10, 2017
    Thanks for the update, it's great to finally have the limits written down clearly with a way to know the status.How will it work alongside the current more vague limitations?I noticed there is some throttling already, except instead of returning a negative answer, i get the answer very slowly until my app decides it's too slow to work with.This seems to be per user and it may or may not be a shared limitation with other APIs like EWS onedrive etc.Can you comment on that?
    • Anonymous
      April 11, 2017
      I don't know any specifics about it, this is the first I'm hearing of any such limit. I'll see what I can find out.
      • Anonymous
        April 12, 2017
        Ok, I chatted with our devs and from what you're describing, that sounds like a shared limit with EWS that is currently in place. The new limiting mechanism described here will replace this scheme, so it should be more transparent and predictable.
        • Anonymous
          April 16, 2017
          Fantastic! thanks
  • Anonymous
    April 13, 2017
    Hi Jason, little bit off topic here but I am trying to find a sample where I can query outlook mail api in javascript using adal. I need to use this code in script editor web part of sharepoint. Could you point me to the right direction.
    • Anonymous
      April 17, 2017
      Sounds like this tutorial may be helpful.
  • Anonymous
    April 17, 2017
    Thanks for the update! The limit of 60 for a group seems too restrictive. Is there any way you can reconsider that limit?
    • Anonymous
      May 08, 2017
      I can pass your comments up to the folks in charge :). However I'd recommend posting this as a suggestion on UserVoice.
  • Anonymous
    April 17, 2017
    Is it possible to increase these limits? 60 requests per minute is awfully little to work with. (e.g. lets mark multiple messages in a user's mailbox as read. So if a user selects 10 messages, and marks alot of them as read. They will either hit the wall or get pretttty close to it.Is there an option to pay microsoft for an increased limit per user per minute?
    • Anonymous
      May 08, 2017
      Thanks for the feedback. No, there's no option to up the limit currently.
  • Anonymous
    April 18, 2017
    How does this affect batch requests ? is the batch counted as one request or are the individual requests counted. Are all request affected ? eg if your copying or moving items your effectively limiting that to 60 items a minutes which isn't going to be great if you have 1000's of items that need to be moved or marking a large number of item Read etc.
    • Anonymous
      May 08, 2017
      No, batch requests don't get around it I'm told. If you send 20 requests in a batch, that counts as 20 requests.
      • Anonymous
        May 09, 2017
        I'd encourage you to rethink that then it doesn't really make sense to apply it across everything as all operations aren't equal. I can see some utility in restricting 60 Gets a minute but for instance what's the point to the batch interfaces. Eg this mean with a batch size of 20 you can't make anymore then 3 requests a minute. Volume requests would be needed for a bunch of different valid enterprise functions like imports,moves,deletes,copies, hygiene, updates and data discovery. Throttling is needed for availability and reliability but at 60 requests a minute that restricts functionality.
        • Anonymous
          May 10, 2017
          The limits didn't go in place as planned. Engineering has heard the feedback and they are now collecting more telemetry to see what rate limits make sense. I'll update the post shortly.
          • Anonymous
            November 27, 2017
            Well, the limits seem to be in place now (at least we're hitting them) and you haven't updated this post.What are the new arbitrary limits we're supposed to work to?
            • Anonymous
              November 27, 2017
              Sorry for the confusion here and the lack of update. The limit is 10K requests every 10 minutes per app per user. That means for your application ID, you would be allowed to make 10k requests to a single user's mailbox every 10 minutes. If you're accessing multiple user's mailboxes, then you get 10k/10min for each one of those. I'm working with engineering to get all the details ironed out so I can update the post.
  • Anonymous
    April 20, 2017
    Do we have any details on concurrent connection limits? Can I post 60 contacts to a user's mailbox in parallel each minute or do I have to spread those 60 over the minute?
    • Anonymous
      May 08, 2017
      Concurrent should be fine.
  • Anonymous
    May 02, 2017
    Hi Jason, is this new rate limit already active? When I make a request to the Outlook API / GraphAPI i don't receive the new rate limit headers. I'm also able to make more than 60 requests per user/minute without a 429 response. I tried the following two requests: "https://outlook.office.com/api/v2.0/users//messages" and "https://graph.microsoft.com/v1.0/users/<USERNAME/messages"
    • Anonymous
      May 10, 2017
      No it isn't. Updating the post.
  • Anonymous
    May 09, 2017
    I've been getting a 429 Rate Limit Error for 'Too many concurrent connections opened'. I've logged the response and have a few questions:1) An example header I get back is this: 'rate-limit-limit': '10000', 'rate-limit-remaining': '9863', 'rate-limit-reset': '2017-05-10T03:43:45.871Z',How is it possible that rate-limit-limit is 10000? In other words if the API could actually service 10k requests in a minute, I wouldn't have this concurrent connections rate limiting issue in the first place.2) There are no 'Retry-After' or 'Rate-Limit-Reason' headers in the response? I figured 'Rate-Limit-Reason' is just the response body.Also - if it matters - these are responses from GET /messages/{messageId}/attachmentsThanks!
    • Anonymous
      May 10, 2017
      Yeah the rate limits aren't being enforced at the moment. I'm updating the post shortly.
  • Anonymous
    May 10, 2017
    Just to chime in here, for our application this would be an issue. We provision the user's university timetable in their calendar, and that requires creating hundreds of calendar events. This is a one-time action (per year), but it does require a greater limit than 60 to give the user a good experience. I would much rather see a limit per app/minute, or a limit per user/5 minutes which is configurable (like Google has).
  • Anonymous
    May 13, 2017
    It is available only for Outlook web rite-now as it Outlook web only has requirement set 1.5 supported, any idea when it would be available for outlook desktop?
  • Anonymous
    August 02, 2017
    Will this restriction apply to service accounts (application accounts that have been granted permission to read the entire exchange data)? Our application is using such an account to query the calendars of hundreds (even thousands) of meeting rooms. How will the limit be calculated? Will we be allowed to perform 60 API calls no matter whose mailbox/calendar we're accessing? Or will we be able to make 60 API calls for each mailbox/calendar? (I would expect the latter)Thanks
    • Anonymous
      August 03, 2017
      Yes it will apply to those applications as well, but remember the restrictions are per mailbox, so you would get the quota for each mailbox, it wouldn't be shared.
      • Anonymous
        November 27, 2017
        The comment has been removed
  • Anonymous
    August 03, 2017
    We are currently developing against the Microsoft Graph API and being throttled (429 responses), but we do not see any of the documented "retry" headers in either the successful or throttled responses. Is this expected?
    • Anonymous
      August 03, 2017
      Obviously, as a result, we can determine how to react to the throttling, apart from backing off for an arbitrary period of time.
      • Anonymous
        August 04, 2017
        What API are you accessing when you get the 429?
        • Anonymous
          August 04, 2017
          The comment has been removed
        • Anonymous
          August 10, 2017
          Hi Jason,Any insight into the missing headers?Thanks.
  • Anonymous
    August 10, 2017
    Is there anything similar for management api?
  • Anonymous
    August 21, 2017
    Hi Jason,Too good article on rate limits and throttling.I was trying to get the throttle error on Graph API's, so that I can implement the handler for the same.I was hitting 50k requests parallel. Using the console application with six different console application instances.So I was hitting almost 50k X 6 = 3 lac request at a time using waitAll, though I was not able to get the single failed request.Could you please assist me on this.I was using https://graph.microsoft.com/v1.0/users({UserID})/mailFolders({FolderID})?$select=displayNameFind out my code snippet, string accessToken = "bla bla accessToken"; Uri usersURI = new Uri("https://graph.microsoft.com/v1.0/users('bla bla userid ')/mailFolders('bla bla mail folder')?$select=displayName"); List TaskList = new List(); Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(DateTime.UtcNow); for (int i = 1; i < 50000; i++) { IRequest request = new Request(usersURI).Authorization(accessToken).Method(HttpMethod.Get); request.ContentType = "application/json"; //var response = await handler.ExecuteAsync(request); //Console.WriteLine($"Iteration #{i} : Status Code : {response.StatusCode}"); //if (response.StatusCode != System.Net.HttpStatusCode.OK) // Console.WriteLine($"ContentString #{i} : {response.ContentString}"); request.Timeout = TimeSpan.FromHours(1); Task cloudFolder = handler.ExecuteAsync(request); TaskList.Add(cloudFolder); Console.WriteLine(i); } Task.WaitAll(TaskList.ToArray()); Console.WriteLine(DateTime.UtcNow); watch.Stop(); if (TaskList.Any(t => t.IsFaulted) || TaskList.Any(t => t.IsCanceled)) { Console.WriteLine($"Requests canceled count :{ TaskList.Count(t => t.IsCanceled) }"); Console.WriteLine($"Requests faulted count :{ TaskList.Count(t => t.IsFaulted) }"); } Console.WriteLine($"Time Elapsed : {watch.Elapsed.TotalSeconds}"); Console.ReadLine();Regards,Hitesh
    • Anonymous
      August 23, 2017
      Per the update to the article, we're not currently enforcing a limit.
  • Anonymous
    December 05, 2017
    Where can I find the limits for the other O365 apps (OneDrive, SharePoint etc.)?
  • Anonymous
    December 08, 2017
    Does $top work with delta queries? I was trying to increase the number of items being returned using $top when performing delta queries, but $top does not seem to have any effect.Can you please let us know technical details to increase items per page when using delta queries? Thanks.