Using RegEx to extract MIME parts from a Microsoft Graph API email stream

In this article I will demonstrate how a Regular Expression can be used to extract all MIME content references from within an HTML Stream.

Introduction

In the previous article we looked at how the base64 encoded version of an embedded MIME Image can be extracted from the Microsoft Graph. In this article we will start to look at how we are going to  automate the solving of that problem by identifying all the MIME encoded images from within the graph API HTML stream.

Regular expressions

RegEx is mentally challenging to most of us, and that is why some beautiful people created Stackoverflow and Google. I was able to find this solution to a similar problem of extracting tag attributes from an HTML string.

Modifying this slightly for my needs in context of the graph I was able to come up with the following:

var content = data.body.content;
var cids = content.match(/cid["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)?/g);

and this will take an HTML stream with different kinds of MIME reference and return them all as an array.

Here is the sample HTML string with just the images highlightedc1

and here’s the result of the test in firebug logging the cids array

c2

 

Conclusion

In this article we have seen that with a simple Regular expression we can extract the Image src attributes relating to the MIME parts within the MS Graph API feed.

Caveat: This assumes a lot about the structure of the API and that is will continue to conform to this structure.

 

Setting up a secure, custom domain, node.js site on Azure

In this article I will demonstrate the necessary steps to set up a node.js server running https, hosted in Azure.

Introduction

This article is a combination of my own work and a conglomeration of reference point blog articles which I had to find to achieve all of this.

Creating a node.js site on Azure

If you follow the instructions on this site you should be able to create an azure site (Get started with Node.js web apps in Azure App Service)

a1

Creating a custom domain

Once you have registered your new domain (in my case marky.co) you need to go to the azure portal and follow the instructions posted here (Configuring a custom domain name for an Azure cloud service). You cannot do this on your free tier though and this where you have to chose your plan carefully. To be able to interact with Office Add-Ins I need my service to be SSL enabled.

a2 a3

Once you have selected a Basic plan you should get the following options

a4

Assign your site and as the instructions stated – you can “Bring your domain” by changing the CName within your domain name provider DNS management tools.

a5

Adding SSL

There are a number of methods for getting an SSL certificate but I have taken to doing it for free – you can use the same process I detailed here for exposing your node server to manually collect the letsencrypt certificates  (Using Let’s Encrypt to create an SSL certificate for my Bluemix hosted web site) to create the .pem files.

To turn the .pem files into .pfx files you need to follow the openssl instructions here (How To: Get LetsEncrypt working with IIS manually)

openssl pkcs12 -export -out “certificate.pfx” -inkey “privkey.pem” -in “cert.pem” -certfile chain.pem

a6

The certificate.pfx file can then be loaded into the azure portal. When you import the certificate successfully it is displayed on the main blade automatically.

a7

 

Add the SSL binding

a71

aaaah we love the cloud….

a8

a9

IMPORTANT – Restart your instance and there we go

a10

Conclusion

In this article we have seen how to deploy an instance of node.js on Azure, applied a custom domain to it, created an SSL certificate and added to an azure instance. Once this is complete you should have an SSL secured node.js  instance running which can then be used for Office Add-in deployments.

 

Obtain an Office 365 OAuth token from within an Office Add-in without pop-ups or dialogs

In this article I will describe a simple process for generating and storing an O365 token from within an Office Add-in.

Introduction

In the previous article  I described the github project and sample code for creating and getting an Office 365 OAuth Token for use in an Office Add-in. This was an improvement on the previously accepted method for getting a token which required additional services and knowledge of C#. The biggest issue encountered was that the normal OAuth Token process when you log into Office365 takes you through multiple domains. When this happens in the Office Client Add-ins the user is thrown into a separate Internet Explorer. The generated token can then no longer be passed to the Add-in for programmatic use.

This article described how the issue has been overcome and the release of the new simplified code.

The same approach, but a new approach

As discussed in this article it is possible to access more than one domain within an Add-in by adding the additional domains to the Add-In manifest.

If we follow the OAuth process for Office 365 authorization we can see that there are two domains which are used:

We initially request access from “https://login.windows.net/common/oauth2/authorize? ” and then get redirected to “https://login.microsoftonline.com ” before getting sent back to the original.

To solve the issue at hand we add those two domains to the manifest in the following manner

  <AppDomains>
    <AppDomain>https://login.windows.net</AppDomain>
	<AppDomain>https://login.microsoftonline.com</AppDomain>
  </AppDomains>

In the github repo I have actually posted a complete sample manifest file for you to see.

The code 

d3

The code for the Authorization is relatively simple. The Home.js code is triggered when the page loads. If the location.href of the Add-In contains the access_token then we move to app.returnToken(). if not then we “getToken”.

//Home.js
(function () {
    'use strict';

    // The Office initialize function must be run each time a new page is loaded in the Add-In
    if (location.href.split("access_token").length < 2){
        Office.initialize = function (reason) {
            $(document).ready(function () {
                //check to see if there is an OAuth Token cached in the cookie
                //app.addinName will need to be different for every Add-In
                var token = app.getCookie(app.addinName)
                if (!token) {
                    var tokenParams = {};
                    tokenParams.authServer = 'https://login.windows.net/common/oauth2/authorize?';
                    tokenParams.responseType = 'token';
                    tokenParams.replyUrl = location.href.split("?")[0];

                    //THESE tokenParams need to be changed for your application
                    tokenParams.clientId = 'Your-app-clientId-goes-here';
                    tokenParams.resource = "https://yoursite.sharepoint.com";

                    app.getToken(tokenParams);
                } else {
                    //we have a token therefore carry on
                    app.tokenCallback(token)
                }
            });
        };
    } else {
        //The window has the access_token in the URL
        $(document).ready(function () {
            app.returnToken();
        });
    }
})();

The important parts of the App.js code are the getToken and returnToken. Within getToken(tokenParams) we parse out the incoming object and redirect the user to the login screen part of the process using location.href. The reason for having a Home.js separate from App.js is really for clarify.

//App.js
//...
    app.getToken = function (tokenParams) {

        var url =   tokenParams.authServer +
                    "response_type=" + encodeURI(tokenParams.responseType) + "&" +
                    "client_id=" + encodeURI(tokenParams.clientId) + "&" +
                    "resource=" + encodeURI(tokenParams.resource) + "&" +
                    "redirect_uri=" + encodeURI(tokenParams.replyUrl);

       // var winObj = window.open(url);
       // winObj.focus();
        location.href=url;
    };
//...

Putting this all together, when accessing the Add-in for the first time, the user now sees the login screens within the Add-in


o1

o2

And then once logged in the user is sent back to the original screen but with the Authorization token appended to the URL

o3

The returnToken() part of the application parses the incoming URL, extracts the Token and then inserts it into the page for display. The token is then stored in a cookie for 1 hour. This is the length of time the Authentication token is valid. The next time the user opens the Add-in within the hour the token will be stored and accessible.

//App.js
//...
app.returnToken = function(){
        var urlParameterExtraction = new (function () {
            function splitQueryString(queryStringFormattedString) {
                var split = queryStringFormattedString.split('&');

                // If there are no parameters in URL, do nothing.
                if (split == "") {
                    return {};
                }

                var results = {};

                // If there are parameters in URL, extract key/value pairs.
                for (var i = 0; i < split.length; ++i) {
                    var p = split[i].split('=', 2);
                    if (p.length == 1)
                        results[p[0]] = "";
                    else
                        results[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
                }
                return results;
            }

            // Split the query string (after removing preceding '#').
            this.queryStringParameters = splitQueryString(window.location.hash.substr(1));
        })();

        var token = urlParameterExtraction.queryStringParameters['access_token'];

        if (token){
            app.tokenCallback(token)
        } else {
            document.write("Shame")
        }
        /*if (window.opener){
            window.opener.app.tokenCallback(token);
            window.close()
        } else {
            document.write("There appears to have been an error, please close the window and check with your administrator")
        }*/

    }

	app.tokenCallback = function(token){
		//this would then continue to do what you really need in the Add-In
        document.getElementById('tokenHere').innerHTML = token
	}
//...

Sample code only

The code displayed in this example is for example only. It is there to demonstrate the process and return the token. What you then do with the token is up to you 🙂

Conclusion

In this article we have seen how we can create an Office 365 OAuth token with the minimum of impact on the user. They have to log into the Add-in within the Outlook client and the disruption on the User Experience is minimal.

 

Using more than one domain inside of an Office Add-In

In this article I am going to introduce the  <AppDomains> parameter within an Office Add-In Manifest. Using this parameter we are going to see how you can change the URL within an Add-In and consider the possibilities that brings us.

Introduction

I was casually reading through the thrilling “Office Add-ins XML Manifest” (http://dev.office.com/docs/add-ins/overview/add-in-manifests) and I came across this casual comment:

By default, if your add-in tries to go to a URL in a domain other than the domain that hosts the start page (as specified in the SourceLocation element of the manifest file), that URL will open in a new browser window outside the add-in pane of the Office host application. This default behavior protects the user against unexpected page navigation within the add-in pane from embedded iframe elements.

To override this behavior, specify each domain you want to open in the add-in window in the list of domains specified in the AppDomainselement of the manifest file. If the add-in tries to go to a URL in a domain that isn’t in the list, that URL will open in a new browser window (outside the add-in pane).”

This was the exact problem I had when I came up with the O365Token solution on how to Authenticate an Add-in to O365 and ended up using a window.open() solution. When I tried to do the OAuth redirect it failed because it opened a whole new Internet Explorer instance which did not communicate with the Add-in parent.

The published solution works but is a somewhat poor user experience due to the Internet Explorer window opening up. But hey it worked so I went with it.

The problem demonstrated
I am demonstrating this issue using firebuglite in one of my existing Add-ins. I change the location.href of the Add-in (in Outlook) and the requested website opens up in a fresh Internet Explorer window.

d1

d2

Proof of concept

I created a simple addition to my manifest file:

  <AppDomains>
    <AppDomain>https://login.windows.net</AppDomain>
	<AppDomain>https://login.microsoftonline.com</AppDomain>
  </AppDomains>

I uploaded the new file through the Exchange admin portal, refreshed it for the user and tested it again

d3

d4

and look at that – it opened within the Add-in without issue.

Conclusion

In this article I have demonstrated how using the  <AppDomains> parameter within the manifest file we are able to change the website loaded within the Add-in

Next – how do we re-write the O365Token to load nicely in this window?

How to create Dynamic Workflow functionality in Outlook Add-Ins based on unique keys

In this article I will demonstrate how to use a regular expression to provide dynamic contexual assignment of an Outlook add-in. Using that regular expression we will be able to identify the necessary information to link the Add-In to some external dynamic workflow functionality.

Introduction

During the Collab365 presentation I demonstrated a workflow application which was a simple vacation request approval. In that demonstration I showed how we are able to detect a unique key inside of an email and then use that value to open the workflow within the add in (https://youtu.be/t6kRFV09TYs?t=1950).

In previous articles I have demonstrated how to create a contextual add-in and in this article we will look at how we can take that up a notch and make the context dynamic and useful.

I am going to demonstrate the capability in the context of a napacloud add-in so that you are able to work along.

Messing with RegEx

Regular Expressions are a weird an wonderfully powerful capability, generally reserved for people way smarter than me to figure out. Fortunately there are many example sites which can be used to help you figure out how you should build your regular expression.

I used http://scriptular.com/ which allowed me to test my regular expression until I made it work.

We need to create a unique key within out email so that it can be picked up by Outlook. We cannot use an existing URL though because there is already functionality associated with that.

r2

Using regular expressions in an Office Add-in

Inside of the napacloud tooling we are able to play with adding a regular expression to the context of the Add-In.

r1

So I insert my regular expression into the box, save and run. In this case (for demonstration I make the number of characters fixed to be 6)

r3

Test Email

I created a simple test email with a few expressions which COULD match……and when the Add-In runs – only only of the links is highlighted

r4

So now what?

Well what we want to happen is when the user clock on that Workflow Id: Ac9sXP link we want to take them to the right page within our Application (surfaced through the Add-In).

Within the Office.initialize we are able to determine functionality which happens when the user selects the Add-In. I used the same regular expression to match the desired Workflow Id

Office.initialize = function (reason) {
        $(document).ready(function () {
            Office.context.mailbox.item.body.getAsync(
		  "text",
		  { asyncContext:"This is passed to the callback" },
		  function callback(result) {
		    // Do something with the result
			var str = result.value; 
			var res = str.match(/Workflow\sId:\s[0-9|a-z|A-Z]{6}/g).toString();      				
			$("#content-main").html("The RegEx matched is---> "+res)
		  });
        });
    };

When you run the sample in the browser you get this

r5

More advanced

Once you have this string in JavaScript you can do a number of things with it, the two most obvious to me are:

  • Create an iFrame within the application and add the WorkflowID to the Query String
  • If you have an angular application you can then route the user to the correct document using the WorkflowID

Conclusion

In this article I showed how to create a contextual addin using a semi-complex Regular Expression. Then using that exposed value from the email we can surface dynamic functionality for the user.

The Code

I have posted the code from this sample napacloud out on GitHub for anyone who wants to download it an play with it

You can find it here:

https://github.com/markyroden/RegExInOutlookAddIn

 

“Office 365 Add-Ins – a web developer’s playground” – presentation from Collab365 conference now live

Last week I presented at my first non-IBM conference and it was a total blast. At PSC, we see a number of customers who are doing mail migrations who still need to integrate their remaining business critical systems with Office 365. Office Add-Ins, especially in the context of mail and workflow are a great way to look at this integration problem.

The collab365 conference required me to prerecord the presentation and it was streamed at the agenda time. This allowed me to sit in the side chat and talk to the people watching the presentation. This increased interaction and with hindsight I should have worked it more.

This recording is similar to the presentation I gave at ICONUS and Engage.ug this year, but not specifically focused on XPages/Domino integration. The XPages/Domino examples are all in here though and also an example of integration with Watson Tone analysis.

All the presentation from the Collab365 conference are now available and can be accessed here – you will need to create a free registration to get at them all.

https://collab365.conferencehosts.com/confs/Summit2016

Hope you enjoy, there is a lot to learn and a lot of interesting possibilities with the new Office Add-In model.

 

Speaking at Engage: “Dev04. XPages and Office 365 development – more familiar that you think”

I am very proud to be speaking at the Engage 2016 User Group conference, in Eindhoven March 24th

Thursday, March 24 | 09:00 – 10:00 | D. Saturn

This is a very interesting session for me personally because it reflects how my job has allowed me to evolve into areas of development which are not just XPages. Don’t get me wrong, I am far from done with the XPages world, but with a lot of our customers having a mixed Domino and Office 365 environment the past year has presented some new challenges and opportunities.

I always believe that a picture is worth more than a thousand words and in this session I will show many demonstrations of what is possible and go into some details of how O365 development and modern Domino web development are really very similar.

I look forward to seeing as many people as possible bright and early on march 24th 🙂

Abstract

Many companies run a mixed IBM Notes and Microsoft Office 365 (O365) environment. SharePoint/Outlook and Domino should be viewed as a new opportunity to create rich and engaging user experiences. Using both IBM and Microsoft REST services as the core to the solution, this presentation will show how both technologies stacks can be integrated to maximize application functionality and present a seamless experience to the user. Mark will provide lots of demonstrations including Office Web Add-Ins, how to access O365 data from your Domino applications and many others. Come and see how your core Domino webdev skills are equally applicable to the Office 365 environment.