Delay Loading Outlook Add-ins

A customer I work with encountered an issue where a specific add-in was causing Outlook to lose its network connection. Essentially, we were unable to get the “Click here to view more on Microsoft Exchange” (in cached mode) to light up. Here is what we saw:

connect error

Here is what we wanted to see:

connected

It was always grayed out and no mater what we did in Outlook with the connection state, it never same back.

After a lot of troubleshooting we found one particular in-house add-in was causing the problem. Oddly, everything worked great with the same add-in in previous versions of Outlook, but in Outlook 2016, we started seeing this problem. Therefore, we knew it had to be a change made in Outlook 2016. What we found is that Outlook 2016 had been greatly reconfigured in the startup code to optimize network connections as it now connects to the cloud (Office 365). So we started working with the product team on identifying the root cause and in the end we were unable to find a solution (in time). My customers deployment was delayed.

As such, I had to come up with a workaround. We found that if the add-in was not loaded when Outlook started, but was manually enabled after Outlook  launched, the problem would NOT occur. This got me thinking: What if I created an add-in that loaded add-ins AFTER Outlook was done loading all other add-ins?

The Outlook Delayed Loading of Add-ins for the Enterprise was born. By the way, that name is credited to my customer. The catchy acronym stuck: D-LAME Add-in. wlEmoticon-disappointedsmile.png

I have posted the project for it here on GitHub here:

https://github.com/davecra/DLAME

You will need to load it into Visual Studio and compile it and then sign it with a certificate on your own. The code is provided AS IS. The README.md on the page explains the installation, configuration and usage of the a add-in once you have it ready for deployment. Some key points:

  • You will want to make sure it is not disabled by setting the Resilience policy key for the add-in.
  • You will want to move the add-in(s) you wish to delay from HKLM to HKCU registry locations.
  • You can load DLAME as either HKCU or HKLM. The suggestion is HKLM.

So, what can you use this for? Well, it turns out this add-in has a lot of uses and as I have started discussing it with other support folks at Microsoft, several use cases came out:

  1. You have a lot of add-ins that you need to have loaded with Outlook. They keep getting disabled by Outlooks resiliency feature, so you add policy settings to prevent them from being disabled, but now Outlook takes forever to launch. You can now set only DLAME to be resiliency policy blocked and then delay load all your other add-ins.
  2. Because it is a .NET/VSTO add-in, added to the above scenario, you can have all your VSTO add-ins load after Outlook has completed loading all other add-ins.
  3. Because the loading occurs on a background thread, the user will see Outlook fully load and then will start to see the other add-ins load (Ribbons and buttons appearing) after they are able to see their inbox and start reading/selecting items.

Bottom line, this add-in is useful for helping an enterprise manage their add-in without impacting the loading of Outlook or user productivity.

However, there is ONE major caveat. You will need to thoroughly test your add-ins because some add-ins might not like being loaded AFTER the fact. Technically, I have not found any that behave this way, but there could be some that register to certain events (like Application_Load and NewExplorer) that will not get fired if loaded after Outlook is already fully loaded.

Using NPM to Publish and Update Packages

This blog post is more for me than you. I come from an era when command line was the only way to get things done. The folks that were able to do that in the 1980’s and early 1990’s, were called…

nerd

Well, for some reason, after advancements in GUI (Graphical User Interfaces) we are back to command-line interfaces. I have heard an argument that this makes it easier to build in voice command interfaces, but I do not see myself saying: “npm install”. I believe it came about because it is easier to create a command line interface quickly for free than it is to create a graphical one. Just sayin’. wlEmoticon-winkingsmile.png

With that said, lets get down the business. I published OfficeJs.dialogs to NPM and found a few last minutes bugs and needed to update it. Well, this seemed easy enough, but I was getting some error about my git working directory:

git working directory dialogs not clean

This turns out to happen because I needed to do both a push and a pull. Not sure why, but I did a push and sync and that did not resolve the issue. I had to do a pull from git too:

menu

Next, I had to then do a version update. To do this you type this in the Terminal window in VS Code once it is pointed to the repository folder:

npm version patch

This will add a single point to the version, so for me that was from 1.0.1 to 1.0.2. Next, you issue a single command:

npm publish

This will publish version 1.0.2 (in my case) to the node module in the sky (npmjs.com). Next, I then went to my project where I am using it and then issue this command:

npm update officejs.dialogs

And just like that, I had the latest version. Seems simple enough, but it took a while for me to research this and get it working. And since these are all command lines without a graphical ability to “hunt and peck” for the right menu item, I am writing it down for posterity. I will likely be referring to this post for myself again in the future.

Did you miss the Message… box?

Several customers have asked me if OfficeJS has something similar to a Visual Basic or C# MessageBox.Show() function. The answer is no. And for a long time there was not even a dialog option. With the latest releases of the OfficeJS libraries comes a new dialog feature. Yet to get a standard MessageBox, you will still need to create it from scratch. Or, at least until this blog post you did. I have created a helper library the consists of two files:

  • dialogs.js
  • dialogs.html

To reference this library you can do any of the following:

If you used NPM, you can reference then with a script tag like this:

<script type="language/javascript" src="./node_modules/officejs.dialogs/dialogs.js">

NOTE: This assumes your page is in the root of your project. The key point is that it is added to your node_modules when you use NPM and this is how you will reference it.

Once referenced you can then call a MessageBox like this:

MessageBox.Reset();
MessageBox.Show("This is a test with a lot of text that simply has not point but to show you what " +
                "happens when you place a lot of text in a MessageBox for any point other than to " +
                "place a whole lot of text in the MessageBox.",
                "This is the Caption",
                MessageBoxButtons.AbortRetryCancel,
                MessageBoxIcons.Stop,
                true, "Check this if you want me to stop nagging you.",
                function(buttonPressed, checked) {
                  console.log("The button pressed was: " + buttonPressed);
                  console.log("The checkbox was checked? " + checked);
                });

Here is what this will look like:

msg

You can call up an InputBox like this:

InputBox.Reset();
InputBox.Show("What value do you want to enter?",
              "InputBox caption",
              "Default value", function(result) {
                var msg = "";
                if(result.length == 0) {
                  msg = "The user pressed cancel.";
                } else {
                  msg = "The user entered: " + result;
                }
                console.log(msg);
              });

Here is what the above code looks like:

input

You can show a custom form of your own design like this:

  Form.Reset();
  Form.Show("/test.html",10,20,false,function(result){
    var yourJSON = JSON.parse(result).Result;
    // if you placed false in the 4th param you must
    // handle the close of the form
    Form.DialogClose();
  });

Here is an example of what the above code looks like:

form-ex

It is important to note that like everything else in the OfficeJS world this is an async dialog. This also means it is non-blocking. This means any code you do not have in your callback method will continue to run. And if you are wanting to display multiple message boxes at the same time – you cannot. The last one you try to display wins, the others will be gone. Most everything in this dialog is just like you will remember from the good ol’ Visual Basic/C# MessageBox and InputBox. Even the constants for MessageBoxButtons and MessageBoxIcons are the same. But, I added a little flare and it probably helps with the best practices in OfficeJS to not nag the user with dialogs, and that is the ability to add a check box to the form so you can ask the user if they do not want to be bothered by your code anymore.

For the MessageBox, the withcheckbox and checkboxtext are there to give you that ability. Additionally, you see the callback method (asyncResult) that will return once the use dismissed the dialog. It will return with two pieces of information:

  • The button the user clicked in string format. So “Yes” or “Cancel” will be what you see here.
  • A Boolean representing whether the check box was checked or not.

For the InputBox, the callback method (asyncResult), will return one piece of information. If will return the text the user entered, or it will return nothing (an empty string), if the user pressed cancel.

The Form method will return a JSON object:

Error: { },                  // Error object
Result: { },                 // JSON from form
Cancelled: false       // boolean if formed cancelled with X

The Result object will be the JSON from your own form. In your code you will need to call back to the parent like this:

Office.initialize = function(reason) {
    $(document).ready(function () {
        $("#okButton").click(function() {
            // notify the parent
            Office.context.ui.messageParent("My custom message.");
        });
    });
};

You will also see in the examples above, I call .Reset() before I issue a new dialog request. This is because the objects are global and this is a way to be certain to clean up anything in memory that might be associated with a previous dialog. In my testing, I never really had problems like this, but I added it as an extra precaution.

Also, note, I have only tested this in Outlook OWA, I have not had a chance to test it in Excel, Word, PowerPoint or even in the full Outlook client. So, if you encounter issues in those other clients, please let me know.

Finally, I want to call out the OfficeJS Helpers. This library provides a lot of help with authorization dialogs, but also has a simple method for displaying messages using OfficeHelpers.ui.notify(). You can install it into your project using NPM:

npm install –save @microsoft/office-js-helpers

Node Package Manager

As I delve ever deeper into the world of Node, I have found the ability to install packages with NPM quite handy. I do this from VS Code using the Terminal window. I just type:

npm install <packagename>

As I have been developing different packages for my customers, I have found the need to install code that I have been reusing over and over again. Most importantly, easyEws. So, I created a npmjs account (davecra) and I published easyEws. But what is even better and what I was after, is I can now install the latest version of easyEws by going into the Terminal window in VS Code and typing this:

npm install easyEws

 

Debugging JavaScript 101

I am “newish” to web development in the modern era. By modern era I mean, that I was writing webpages before “getting on the web” was cool. Before the movie “You Got Mail” came out, when AOL, dialup and Netscape were all still “the thing.” So, I know web development back then, probably up through 2007’ish. And I have done very little serious web development until 2 years ago when I really started delving into OfficeJS. So here are some things I have learned and would like to admit I did not know… I mean, pass along to you:

  1. Node. This heralds back to my previous post on Yo Office. In this post, I call out that NodeJS/BrowserSync is a powerful feature. I can safely say, as I have been working with it more and more, it has changed my life for the better. wlEmoticon-openmouthedsmile.png I have also been using Node and VS Code in an effort to understand this newer way of development. I have had a number of colleagues convince me to keep on keeping on with it – it will grow on me, they swear. Ok… So, what I like is when I hit save in VS Code and go back to the browser and click my add-in button (for a function-file), or open my taskpane again – it is current. I DO NOT have to refresh the browser. Browser-Sync takes care of all this for me.
  2. Chrome. If you are debugging outside of Visual Studio, I have found Chrome to be the best browser with which to debug. Here is why:
    • It’s Incognito mode is the best option for making sure you always have the most recent files and things are not cached. Edge and IE have private modes, but there is the next issue…
    • Edge and IE are tied into Windows and when you try to log into your developer tenant from them, it automatically grabs your credentials from Windows and takes you to your company email. Ugh!
    • Incognito still lets you (with warnings) load certain extensions and you also get form fill, so it makes getting into your tenant mailbox super quick and easy.
    • F12, developer tools. Edge and IE also have, but look at Chrome’s: Enough said there.
  3. console.log(). This is a bit of a no brainer, but I have found that sprinkling my code with this helps me get a good idea of my code flow, especially with Async() hell that you can get into with OfficeJS.
  4. debugger; – this has saved my life. I know, I am a “noob,” but I had no idea how to set a breakpoint in my code and get the browser to stop there, right there… no not there, RIGHT THERE!!! There is a window in my office with easy access to the pavement 4 stories below. One day, the day when I found this (after much frustration with my inability to write coherent JavaScript – a common problem I have), I was about to see if I could bounce. So, what you do is place this one word in your code, and if you have the developer tools open… viola! OMG:

    debugger;

  5. try/catch – In C#, especially with the debugger attached, I sometimes worried about error handling after the fact. Partially because I was not sure all the exception types I would want to catch or just use a general exception handler. But to say unexpected things happen in JavaScript and OfficeJS all the time is an understatement. Especially if you pretend to be a JavaScript developer like me. wlEmoticon-winkingsmile.png
    • I use the console to always output errors.
    • And, I know this is coming, TypeScript makes things so much easier in this area. As a matter of fact, I know one colleague that will be telling me “of course you do not bounce,” and my problems would be so much less had I used TypeScript in the first place. For the record, TypeScript makes a horribly disastrous JavaScript developer like me into an only moderately bad one. wlEmoticon-hotsmile.png But, unfortunately, all my clients are writing code in JavaScript, so here I must suffer.
  6. And shrimp sandwich… that’s… uh… that’s about itwlEmoticon-surprisedsmile.png

As I learn new things, I will come add them to this list. But if you have some great tips on debugging, please comment below.

Dialogs in OfficeJS

I have been working on a number of projects for my customers and recently, dialogs have taken front and center stage. The Office.context.ui Dialogs are powerful, albeit a tad confusing and the documentation suffers from a few easily missed points.  Here is the documentation:

But in this post, I hope to explain everything I have learned. To start off with here is the code to issue the dialog:

  Office.context.ui.displayDialogAsync('https://localhost:3000/function-file/dialog.html',
      { height: 20, width: 30, displayInIframe: true },
      function (asyncResult) {
          dialog = asyncResult.value;
          // callbacks from the parent
          dialog.addEventHandler(Office.EventType.DialogEventReceived, processMessage);
          dialog.addEventHandler(Office.EventType.DialogMessageReceived, processMessage);
      });

What this dialog does is opens as a modal form in a frame over the application (in Office Web Apps). It looks like this:

screen.PNG

As you can see the dialog is modal. But what is really important are the two event handlers you need to register to be able to get back to your code:

          dialog.addEventHandler(Office.EventType.DialogEventReceived, processMessage);
          dialog.addEventHandler(Office.EventType.DialogMessageReceived, processMessage);
The first one is an event receiver and really this is the event handler for errors, such as being unable to open the dialog or, most importantly, the user closed the dialog by clicking the (X) in the upper right of the dialog. There are a series errors you can catch, but specifically, the dialog cancel is this:
12006 The dialog box was closed, usually because the user chooses the X button.
The second one is a handler for messages coming from the dialog. These messages can be anything, but is usually a string or a JSON string. You can send a message from the dialog like this:
Office.context.ui.messageParent('{message}');
When the dialog issues a message using the code above, the function defined in the event handler is called. For example, if the user clicks an OK button or Submit button, you can pass the stringified values from the form back to the callback function. From there the dialog actually remains open until the caller issues a close, like this:
    // close the dialog
    dialog.close();
In the example above where I make the displayDialogAsync call, you will see I defined the SAME callback function for both dialog events. I did this because the results can be parsed by the same function. Here is what my function look like:
function processMessage(arg) {
    // close the dialog
    dialog.close();
    // procress the result
    if(arg.error == 12006) {
      // user clicked the (X) on the dialog
      sendEvent.completed({ allowEvent: false });
    } else {
      if(arg.message=="Yes") {
        // user clicked yes
        sendEvent.completed({ allowEvent: true });
      } else {
        // user clicked no
        sendEvent.completed({ allowEvent: false });
      }
    }
}
My previous blog post references all the code for the dialog:

Outlook OnSend and Dialog Sample

As promised, I have created a GitHub repository for the sample I blogged about earlier. Here is the repository:

https://github.com/davecra/outlook-sample-1

This includes three items of interest:

  1. The OnSend event, implemented in the simplest of ways to demonstrate bare bones how to get it to work.
  2. The displayDialogAsync with the inline frame (displayInFrame) option. I will blog about this in the future as well.
  3. A project build by Yo Office and published per my blog post here.

What this sample add-in does is pops up a dialog box anytime you press Send on an email with a question: “Are you sure?” If you click Yes, it sends, if you click “no” is blocks the send. Here is what that dialog looks like:

dialog

If you have followed the steps from my Yo Office post, you will be able to open the project in VS Code, and from the terminal, launch it with:

npm start

Next, you will need to follow the steps to enable the OnSend policy in your account and then you will need to install/sideload the manifest. From there you will not see any appearance of the add-in at all, until you press the Send button.

NOTE: At the point I first tested it on June, 13th, 2017, there is a KNOWN ISSUE with the certificates created fro a “yo office” build. If you have not resolved the certificates issue you will be able to start the project in Node.js, but the add-in will fail to run. You need to perform the steps outlined here to correct it:

https://github.com/OfficeDev/generator-office/issues/244