Skip to main content

Accessing Public Folder data from a Microsoft Teams Tab application using EWS

For a long time now Public Folders have been a good way to share information and have threaded conversations across organizations. However time and technology have surpassed them somewhat of late, if your using Office365 there was first the introduction of Unified Groups and now Microsoft Teams has come to maturity both of which offer a better user and technical solution to needs Public Folders fulfil. The benefits of these newer technologies is they allow you to do more in the same context while not giving up on the existing features that Public Folders may have been giving you (outside of access in Outlook). But where the rubber meets the road at the coal face its not always as easy to migrate from one solution to another, so in this post I'm going to look at how you can access data (email etc) in an Exchange Public folder from within a Team's Tab application. This type of approach may give you some flexibility and options while your dealing with a Migration between the two or just during that tricky cutover period where you don't have everyone onboard at once.


What it looks like


the Text box is a simple search bar that takes a KQL query so by default it will just return everything but if you entering a query and hit the refresh button you will get filtered results eg





Technical Challenges  

Over the past couple of months I've posted a few Teams tab applications that expose Exchange data using the Graph API as the interface into the Exchange Store. Public Folders aren't yet accessible via the Graph API so to access these you need to use Exchange Web Services. While this isn't too difficult in itself because EWS doesn't support CORS it means you can't write JavaScript code that will run in the client browser to access EWS directly.

Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTPheaders to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin. In the context of a Teams tab application that wants to access Public folders via EWS the source domain will be where the teams tab application pages are being hosted and the target would be EWS outlook.office365.com, because the server where EWS is hosted doesn't support CORS the browser will block this request because the correct headers aren't returned when the request is pre-flighted (http Options request)
To mitigate against CORS you can use a Proxy like this node.js server https://www.npmjs.com/package/cors-anywhere then if your writing your client side code in something like Angular you can proxy your requests via this. Another way which is the one I've chosen is to write all the EWS logic and EWS calls in node.js and then create a simple Rest API for the Node server that can be called from the client side code that runs in Teams. This has a few benefits as there are multiple requests to get the public Folder and correct routing header initially. With this method you can run all these from a cloud hosted server that should have lower latency then the client which should mean better performance and also the service itself can be reused from other applications.

Node.js app

The node.js server is a relatively straight forward app that uses Express and has one route that become the REST endpoint that the Teams Tab application will call. I've used a JavaScript port somebody did of the EWS Managed API https://github.com/gautamsi/ews-javascript-api  which I found was reasonably easy to use and made dealing with the EWS side of the code a lot faster because I could port over existing C# code. One of the least fun things to do when dealing with Public Folder and EWS is to workout the correct routing headers https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/public-folder-access-with-ews-in-exchange but I have some code that will handle this and also finding the Public folder from a path using multiple shallow traversals. To allow paging past 1000 object (or I made the default page size about 100 to maintain reasonable performance) the rest endpoint support calling it again with an EWS folderId as to avoid the discover process a second time. Other then that the EWS code is pretty run of the mill findItems, folderfinds and bind.

Teams Tab application

Like the other Teams tab applications I wrote this use the Teams Tab Silent authentication method but instead of getting a token for the Graph Endpoint its gets it for the EWS endpoint outlook.office65.com. For displaying the email data I've used the tabulator JavaScript library which has a few nice feature I like.  Each of the email is clickable and will open any of the items you click up in a new tab in OWA eg


Using this app

Unlike the previous tab apps I've published which could just be used straight from GitHub this one requires some technical understanding. Firstly you will need to host the node.js server somewhere eg Azure is best place as that gets you as close to the Exchange servers that will be serving the content. Once you have this hosted all the configuration for the app is held in the appconfig.js file https://github.com/gscales/gscales.github.io/blob/master/TeamsPublicFolder/app/Config/appconfig.js


const getConfig = () => {
   var config = {
        clientId : "2417973f-0680-4ea0-a844-e6d414cee4d4",
        redirectUri : "/TeamsPublicFolder/app/silent-end.html",
        authwindow :  "/TeamsPublicFolder/app/auth.html",
 hostRoot: "https://gscales.github.io",
 folderpath: "\\Childfolder\\childfolder",
 ewsproxy: "https://459e25ee.ngrok.io/FolderItems",
   };
   return config;
}

clientId is for the application registration you should create for this app, to access EWS you only need to the following 1 permission


folderpath is the path to the public folder (because this is a js file there is one more \ the normal to escape the path \.

ewsproxy is the REST endpoint of node.js server in this example I was hosted in locally on my pc and then exposting that endpoint using ngrok which is a great tool for prototyping.

You also need to host the Tab application pages somewhere and modify the manifest to indicate where the location is.

other this this the normal

Side Loading - To use custom tab applications you first need to enable side loading of Apps in the Office365 Admin portal ref .The important part is  "Sideloading is how you add an app to Teams by uploading a zip file directly to a team. Sideloading lets you test an app as it's being developed. It also lets you build an app for internal use only and share it with your team without submitting it to the Teams app catalog in the Office Store. "

As this is a custom application you need to use the "upload a custom app" link which is available when you click ManageTeam-Apps tab see

(Note if you don't see  the "upload a custom app" check that you have side loading of apps enabled in your tenant config)

What you upload here is a Zip file containing your manifest file and two images that you manifest refers to for eg
{
   "icons": {
    "outline": "Outline32.png",
    "color": "Colour192.png"
  },

For this sample this is located in https://github.com/gscales/gscales.github.io/tree/master/TeamsPublicFolder/TabPackage

These icons are what is used in the UI to represent your application.

 The files for the tab application can be found on GitHub https://github.com/gscales/gscales.github.io/tree/master/TeamsPublicFolder

The Node.Js solution for the EWS proxy can be found in this repo https://github.com/gscales/TeamsPublicFolder-NodeEWSProxy

There are some todo's that still need to be done eg the pagination is a little clunkily as there is a differences between paging between what is returned (eg in EWS you page back item in lot of 1 to 1000) and paging between all the items in a Public Folder so there is separate footer button to get the next 100 items (from the server) and separate buttons to page the results. Most of these are relativity easy to solve if your interested in using this considering hiring me to complete it and share it with others :).

Hire me - If you would like to do something similar to this or anything else you see on my blog I'm currently available to help with any Office365,Microsoft Teams, Exchange or Active Directory related development work or scripting, please contact me at gscales@msgdevelop.com(nothing too big or small).


Popular posts from this blog

Testing and Sending email via SMTP using Opportunistic TLS and oAuth in Office365 with PowerShell

As well as EWS and Remote PowerShell (RPS) other mail protocols POP3, IMAP and SMTP have had OAuth authentication enabled in Exchange Online (Official announcement here ). A while ago I created  this script that used Opportunistic TLS to perform a Telnet style test against a SMTP server using SMTP AUTH. Now that oAuth authentication has been enabled in office365 I've updated this script to be able to use oAuth instead of SMTP Auth to test against Office365. I've also included a function to actually send a Message. Token Acquisition  To Send a Mail using oAuth you first need to get an Access token from Azure AD there are plenty of ways of doing this in PowerShell. You could use a library like MSAL or ADAL (just google your favoured method) or use a library less approach which I've included with this script . Whatever way you do this you need to make sure that your application registration  https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Graph is limited to a m
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.