How to access Outlook from HTML and JavaScript based add-ins
When Microsoft announced their new Office development platform, which would allow developers to create MS Office Apps using HTML and JavaScript, I was very excited about the idea. Unfortunately, I quickly learned that I simply could not accomplish the same things I can with the standard Office Object Model than with the new Office JavaScript object model.
Another thing that kept me from fully embracing the JS/HTML object model was die complexities in deploying the Office Apps. It was not particularly hard to deploy, nor was it quick and easy.
So when Eugene asked me to write a blog post about an idea one of our in-house gurus, Sergey, came up with, I was delighted by the idea.
- Accessing the Outlook Object Model from JavaScript
- Creating the Outlook add-in
- Adding the Outlook Inspector Browser Advanced Region
- Creating the HTML file
- Adding the JavaScript
Accessing the Outlook Object Model from JavaScript
The premise of Sergey’s idea was relatively simple – a .NET web browser control embedded inside either a standard Office Task bar or on an Add-in Express Advanced Taskbar. The web browser control could host any browser based content and you would be able to access the Outlook Object model using JavaScript. For example, in the following image, we’re showing a standard HTML page that shows information about the current open e-mail when the user clicks a button:
Creating the Add-in Express based Outlook add-in
In order to enable this functionality, we first need to create an Outlook Add-in using Add-in Express for Office and .net. Start by creating a new ADX COM Add-in project in Visual Studio.
Select your programming language (VB.NET, C# or Visual C++) and the minimum supported Office version.
Complete the wizard by selecting Microsoft Outlook as the supported application.
Adding the Outlook Inspector Browser Advanced Region
Next, we’ll need to add either a standard task pane or advanced region to embed the web browser on. We’ll use the Add-in Express Advanced Region, since it gives us much more customization options than the standard Office task pane.
Add a new ADX Outlook Form to your Outlook add-in project.
Open the newly added Outlook Form designer and add a standard Web Browser control to it, as illustrated in the following image:
Select the Web Browser control and generate a new event handler for its DocumentCompleted event by double-clicking next to the event name in the control’s event list:
Add the following code to the DocumentCompleted event handler:
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { var d = webBrowser.Document.DomDocument as mshtml.HTMLDocument; try { dynamic window = d.parentWindow; var windowEx = (IExpando)window; PropertyInfo p = windowEx.AddProperty("bhoModule"); p.SetValue(windowEx, AddinExpress.MSO.ADXAddinModule.CurrentInstance, null); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("error adding ie script: " + ex.Message); } }
The code above holds the biggest reason we will be able to access the Outlook Object Model via JavaScript. A property called bhoModule is added to the DOM’s parent window. This property’s value is then set to the AddinExpress.MSO.ADXAddinModule.CurrentInstance.
Next, add a new method called Init and add the following code to it:
public void Init() { Uri url = new Uri(this.GetType().Assembly.CodeBase); string dir = Path.GetDirectoryName(url.LocalPath); string htmlFilePath = "file:///" + Path.Combine(dir, "MailInspector.html"); this.webBrowser.Navigate(htmlFilePath); }
The Init method will navigate the web browser control to an HTML file located in the project.
Creating the HTML file
The necessary code is already in place to make our HTML and JavaScript access the Outlook Object model. Add a new HTML Page to your project.
Select the HTML page and set its Copy to Output Directory property to Copy Always.
Next, add the following folders to your project:
- css
- js
We’ll use the Twitter Bootstrap framework to style our HTML. So, add the bootstrap.css file to the css folder and the boostrap.js file to the js folder. Make sure, you also set these files’ Copy to Output Directory property to Copy Always.
Open the MailInspector.html file, we’ve added earlier and add the following mark up to it:
<!DOCTYPE html> <!-- saved from url=(0016)https://localhost --> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Outlook Addin</title> <link href="css/bootstrap.css" rel="stylesheet" /> <link href="css/style.css" rel="stylesheet" /> </head> <body> <div class="container"> <div class="page-header"> <h1> Mail Inspector <a id="showInfo-button" href="#" class="btn btn-xs btn-primary">Show Mail Info</a> <a id="setInfo-button" href="#" class="btn btn-xs btn-primary">Set Mail Info</a> </h1> </div> <form class="form-horizontal" role="form"> <div class="form-group"> <label for="from" class="col-sm-2 control-label">From:</label> <div class="col-sm-3"> <input type="text" class="form-control" id="from" placeholder="From"> </div> </div> <div class="form-group"> <label for="email" class="col-sm-2 control-label">E-mail:</label> <div class="col-sm-3"> <input type="text" class="form-control" id="email" placeholder="E-mail"> </div> </div> <div class="form-group"> <label for="subject" class="col-sm-2 control-label">Subject:</label> <div class="col-sm-3"> <input type="text" class="form-control" id="subject" placeholder="Subject"> </div> </div> <div class="form-group"> <label for="received" class="col-sm-2 control-label">Received:</label> <div class="col-sm-3"> <input type="text" class="form-control" id="received" placeholder="Received"> </div> </div> </form> </div> <script src="js/jquery.min.js"></script> <script src="js/bootstrap.js"></script> </body> </html>
Mark of the Web
You’ll notice the second line in the file states:
<!-- saved from url=(0016)https://localhost -->
This is used to force Internet Explorer (The .Net Web Browser control uses Internet Explorer) to run in the Local Internet Zone. This is useful to enable dynamic content like JavaScript inside the web browser control. You can read more about this feature on MSDN.
Adding the JavaScript
The final step is to add the required JavaScript in order to add the interaction to our Outlook add-in. We’ll have two buttons on our HTML add-in: One will show the information about the currently open e-mail message and the other will check whether the Inspector window is in compose mode and set the recipient and subject values based on what the user entered.
Add the following to the HTML page we’ve added earlier:
<script type="text/javascript"> $('#showInfo-button').click(function () { if (window.bhoModule != null) { var objOutlook = window.bhoModule.OutlookApp; var inspector = objOutlook.ActiveInspector(); var currItem = inspector.CurrentItem; var sender = currItem.Sender; $('#from').val(sender.Name); $('#email').val(sender.Address); $('#subject').val(currItem.Subject); $('#received').val(currItem.ReceivedTime); } }); $('#setInfo-button').click(function () { if (window.bhoModule != null) { var objOutlook = window.bhoModule.OutlookApp; var inspector = objOutlook.ActiveInspector(); var currItem = inspector.CurrentItem; if (!currItem.Sent) { currItem.Subject = $('#subject').val(); currItem.To = $('#email').val(); } } }); </script>
You will notice that in the above JavaScript, we accessed the bhoModule property and obtained a reference to the Active Inspector. From there, we can get a reference to CurrentItem property and access any properties on the Outlook Mail item.
The beauty about this approach is that you can host the bulk of your add-in code on a public server and when you need to make changes, it will automatically reflect on your user’s end. It offers you a lot of flexibility and you can use the rich variety of online libraries and tools to develop your Office Outlook add-in.
Hands up, who would like to see this as a full featured ability of Add-in Express in the next version?
Available downloads:
This sample Outlook add-in was developed using Add-in Express for Office and .net:
Thank you for reading. Until next time, keep coding!
23 Comments
You say the beauty of this approach is that you can host the code on a public website, but your example runs only local code. Are there no restrictions on the source of the html and related files?
Hi Steve,
There is no such restrictions as far as I’m aware of. I’ve deployed the same HTML add-in on a public website and it runs fine. You can try it on https://htmladdin.coalitionsoft.net/Inspector/Mail
Just keep in mind that the web browser control runs in the same zone as the user’s Internet Explorer.
I see graphical glitches with this approach when Outlook is resized. See these screenshots:
Before resizing: https://i.imgur.com/EI5Iyfx.png
After resizing: https://i.imgur.com/w5MDp9p.png
I’ve tried the following:
– Outlook 2010 (64-bit) and Outlook 2013 (32-bit)
– Enabling / disabling Graphics acceleration
– Enabling / disabling WebBrowser double buffering
– Attempted to trigger a redraw on resize (WebBrowser.Refresh refreshes the page, but that’s not what I want…)
– Invalidated the WebBrowser and/or Form
– Changed the WebBrowser’s Location / size
– Triggered Javascript to cause a redraw (Document.Body.Style = “display:none;”; Document.Body.Style = “display:block;”;
And lots more but those were the obvious ones. Has anybody else seen this behavior?
My system is:
Windows 7 Ultimate 64-bit w/ SP1
Intel i7-4960HQ 2.6 GHz
NVIDIA GeForce GT 750M
16 gb ram
Let me know if I can provide any more information.
Jimmie,
Sorry, your message has been in the pending category for quite a long time. We’ve seem to solve this problem at https://www.add-in-express.com/forum/read.php?FID=5&TID=12879. If you have any other problem please let me know.
Thank you so much for this helpful example, but can you send me the code or proyect.
Hello Elvin,
See the Available Downloads section above.
Hi,
is there any way to get a binary arrray of a message file with javascript and access the outlook object model? I mean, I can save the selected message with the “SaveAs()” method, but then I’m not able anymore, to get a byte array.. because for example a local XMLHTTPRequests are not allowed to the saved ms file. Any Ideas?
Thanks, David
Hello David,
Create a public method in your add-in module. The method should create a byte array and fill it with data it retrieve from the selected item(s). Your javascript code should call that method and use the byte array as required. Is this what you are looking for?
Hi Andrei,
thanks for the answer. But where can I create a public Method? And when I create a public method in the InspectorBrowser.cs file for example, how can I call this from the javascript outlook object model?
And another problem: When I’m not opening an Outlook item in a new window, I have always “null” objects of activeinspector and explorer, even when I have selected a message. Just a really simple sample code:
var objOutlook = window.bhoModule.OutlookApp; // this object is ok
var inspector = objOutlook.ActiveInspector(); // is always null
var myExplorer = objOutlook.ActiveExplorer(); // is always null
–> only works when item is open in new window.
Hi Dave,
>> But where can I create a public Method? And when I create a public method in the InspectorBrowser.cs file for example, how can I call this from the javascript outlook object model?
You need to add a new public method in the AddinModule.cs source file. To call such a method you can use the following code:
if (window.bhoModule != null) {
var myData = window.bhoModule.MyMethod();
//…
>> And another problem: When I’m not opening an Outlook item in a new window, I have always “null” objects of activeinspector and explorer, even when I have selected a message.
I don’t know the exact reason of this behavior. Could you please send your project (or some demo project with the same behavior) to me for testing?
Thanks, this was exactly the code example I was looking for. It works now perfect!
I will check the demo project again and take a look on my project, why it’s not working, when Item not in new window.
You can simulate the error in your DemoProject by yourself: Just set the InspectorBrowser Item also in Explorer Mode (which I finally want) like in the PrintScreen here:
https://drive.google.com/file/d/0ByxH1KPOPS80OC1Nd3JhdTQzSHc/view?usp=sharing
And then you are not able anymore, to get the currentItem or the selection. Look here, when you click “Show Mail Info” button:
https://drive.google.com/file/d/0ByxH1KPOPS80ei1CYVlaYVdZcEk/view?usp=sharing
So, how access the selected Item in Explorer Mode?
Hi Dave,
I have just added a new button especially for Explorer:
<a id=”showInfoExpl-button” href=”#” class=”btn btn-xs btn-primary” rel=”nofollow”>Show Mail Info from Explorer</a>
And the following code:
$(‘#showInfoExpl-button’).click(function () {
if (window.bhoModule != null) {
var objOutlook = window.bhoModule.OutlookApp;
var explorer = objOutlook.ActiveExplorer();
var selection = explorer.Selection;
var currItem = selection.Item(1);
var sender = currItem.Sender;
$(‘#from’).val(sender.Name);
$(‘#email’).val(sender.Address);
$(‘#subject’).val(currItem.Subject);
$(‘#received’).val(currItem.ReceivedTime);
}
});
I don’t see any errors.
Thanks Dimitry, I see the problem: I just forgot to remove the inspector line, which was throwing always the null error, because there was no inspector active in my test-mode ;-)
Hi Dave,
Thank you for letting me know!
I think, I have only a last problem:
– I can only see my Add-In, when I start Outlook directly from Visual Studio in Debug Mode.
– When I register my Add-In and start Outlook normal, It’s not shown, but it’s listed and activated correct in the Add-Ins under options in Outlook.
– BUT: Your Demo Project works correct and shows the Add-In also without start Visual Studio. So there must be a minimal config error anywhere in my Project, but I don’t see where currently…
I attached my solution under this link:
https://drive.google.com/file/d/0ByxH1KPOPS80VEE1RFQyY2VzZkU/view?usp=sharing
Or maybe, you already know the problem ;-)
Dave,
Don’t do “custom” things in constructors. For instance, the add-in module is created when you register the add-in: creating a subfolder in the folder which is current in that moment may fail and this won’t let your add-in register. Also file operations are long and this is what prevents your form from being shown. Still, calling Init in the constructor of the form, makes from creation even slower. I suggest that you move that call to e.g. ADXBeforeFormShow event of the form.
Many thanks, it works now!
Is it possible to call a C# procedure of the Addin from JavaScript code?
Hello Felipe,
The idea is described in a code sample at https://www.add-in-express.com/docs/internet-explorer-html-events.php; search the “Module-script two-way interaction” string on that page.
Regarding HTML,javascript and CSS. Can I load all those file without copying all files to executable directory ??
Hello Shyam,
I’m afraid your question doesn’t make sense in the context of COM add-ins.