Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The enduring saga of when to use EWS vs the Rest API in an Outlook Add-in

This question is based on a previous question I asked but with a bit more detail and experience since.

First some background, I have an Outlook Addin that should forward a users message and then move the message to a specific folder. This needs to work in both OWA, and Outlook 2016 environments for on Prem Exchange. It should also work in both of the former clients, as well as Outlook Mobile App for O365 users.

My specific question comes down to detecting when to use EWS vs the Rest API (or even MS Graph API).

Here is a snippet of of my code:

Office.initialize = function() {
    $(document).ready(function() {
        $('#forward').click(forwardMessage);
    });
}; 

function forwardMessage() {
    if(Office.context.mailbox.restUrl) { // The problem child
        forwardEWS(); // Works like a charm
    } else {
        forwardRest(); // Works fine for O365 users
    }
}

function forwardRest() {
    var restHost = Office.context.mailbox.restUrl;
    var restId = getItemRestId();

    Office.context.mailbox.getCallbackTokenAsync({isRest: true}, function(result){
        if (result.status === "succeeded") {
            var accessToken = result.value;

            $.ajax({
                url: restHost + '/v2.0/me/messages/' + restId + '/forward',
                type: 'post',
                headers: {'Authorization': 'Bearer ' + accessToken},
                contentType: 'application/json',
                data: JSON.stringify({
                    'ToRecipients': [
                        {'EmailAddress': { 'Address': '[email protected]' }}
                    ]
                })
            }).done(function (response) {
                sidepane_status('success', 'Message forwarded.');

                moveRest(restHost, accessToken, restId);

            }).fail(function(err) {
                sidepane_status('error', 'Could not forward message');
            });
        } else {
            sidepane_status('error', 'Could not get token');
        }
    });
}

function moveRest(restHost, accessToken, restId) {
    var folder = $('#ews_folder').val();
    $.ajax({
        url: restHost + '/v2.0/me/messages/' + restId + '/move',
        type: 'post',
        headers: {'Authorization': 'Bearer ' + accessToken},
        contentType: 'application/json',
        data: JSON.stringify({ 'DestinationId': folder })
    }).fail(function(err) {
        sidepane_status('error', 'Could not move message to ' + folder);
    });
}

function getItemRestId() {
    if (Office.context.mailbox.diagnostics.hostName === 'OutlookIOS') {
        return Office.context.mailbox.item.itemId;
    } else {
        return Office.context.mailbox.convertToRestId(
            Office.context.mailbox.item.itemId,
            Office.MailboxEnums.RestVersion.v2_0
        );
    }
}

In my previous question, I was told to check the return of Office.context.mailbox.restUrl. If it returned a URL the Rest API could be used and if not use EWS. The issue here is with my on Prem Exchange user, in OWA Office.context.mailbox.restUrl returns nothing, great then I just use EWS. However on Outlook 2016 Office.context.mailbox.restUrl returns https://exch1.mailhost.com/api. This leads to some issues.

The first being in the case of when the On Prem Exchange user in Outlook 2016 returning a Rest URL. Following this article for interacting with the Rest API with the help of OfficeJS, it is not possible with an with an On Prem User to get an access token through OfficeJS with Office.context.mailbox.getCallbackTokenAsync({isRest: true}, function(result){ ... }); and in turn the Rest API cannot be used then.

I would, as a comment in my original question suggested, just use EWS. However, this brings up another problem with mobile. From this article, EWS is not supported in mobile, and Rest must be used. I do understand an on Prem user would not be able to use the Outlook mobile app tho.

The problem arises that I cannot find a way to determine what API to use and in what context. If I key off of Office.context.mailbox.restUrl then both On Prem and O365 users in OWA will correctly use their respective API's and everything is unicorns and rainbows. However, for an On Prem user in Outlook 2016, it will attempt to use the Rest API when it should be using EWS. And finally, if I solely rely on EWS then Addin will not work for O365 users in the Outlook mobile clients.

I'm kinda at a loss after a good month of trial, error, and swimming in the sea that is known as Microsoft documentation. Any help would be greatly appreciated

like image 622
gr347wh173n0r7h Avatar asked Sep 14 '17 00:09

gr347wh173n0r7h


1 Answers

Yes, this is a known issue with restUrl, from the docs:

Note: Outlook clients connected to on-premises installations of Exchange 2016 with a custom REST URL configured will return an invalid value for restUrl.

I understand that makes it a bit more complicated. I would say in the current state of affairs, here's how I would make the call:

  • First check restUrl. If undefined, then EWS is the way to go.
  • If restUrl has a value, then try getCallbackTokenAsync with isRest: true. If that doesn't get a token, then fallback to EWS.

I would then save this is a setting in the user's mailbox (via Office.context.roamingSettings) so on future runs the add-in could skip this "discovery" phase and just use the right API from the start.

On a self-serving side note, I'm working on an ongoing side project to revamp the Outlook add-in docs at https://docs.microsoft.com/en-us/outlook/add-ins/, so hopefully that will help with the whole "swimming in the sea" feeling. I'd love to get your feedback on what specifically is casting you adrift though, if you could contact me on Twitter that would be much appreciated.

like image 154
Jason Johnston Avatar answered Nov 15 '22 08:11

Jason Johnston