Pieter van der Westhuizen

UX guidelines to create Outlook 2013 mail apps

So we’ve had the Office 2013 Preview for nearly two months now and I hope you’ve been sinking your teeth into it. I have been toying with it for a bit and it does take a considerable mind-set shift. We have to leave our “Office COM based developer-hat” on one side and put our “web developer-hat” on.

In my last article we’ve taken a hands-on approach on some UX guidelines for Office 2013 Content and Task Pane Apps, in today’s article we’ll take the same approach but focus on Mail apps for Outlook 2013.

Creating the mail app project

You can create the mail app for Office using Visual Studio, but for this example we’ll create the project using the Napa development tools and Visual Studio 2012.

Sign into your Office 365 developer account and click on the “Add New Project” link.

Adding a new project

When prompted on which kind of app you want to build, select “Mail app for Office” from the list, enter a project name and click on the Create button.

Creating a new mail app project

The Napa development tools will open the project in a web based IDE. You can use this to build your project, but we’ll be using Visual Studio 2012.

Setting the activation rules for the mail app

When creating a new mail app for Office, the app will by default be visible or activate when the user opens an e-mail in Outlook. For this example we need the app to activate when the user opens an appointment in Outlook. To change this, click on the “Properties” button.

Accessing the mail app project's properties

In the properties window, click on Activation Rules and change the Rule node to the following:

<Rule xsi:type=”ItemIs” ItemType=”Appointment” />

Setting the activation rules for the mail app

Opening the mail app solution in Visual Studio

Click on the “Open in Visual Studio” button.

Opening the project in Visual Studio 2012

You can either choose to save or run the download, and it will open the project in Visual Studio 2012. The solution will have two projects: one will contain the CSS, HTML and JavaScript files needed for the app and the other will contain an XML file used to configure your mail app for Office.

Outlook mail app solution layout

When you first open the solution in Visual Studio 2010, your Solution Explorer should look like this:

The structure of the mail app solution

The project structure looks similar to the content and task panes app projects; The Pages folder contains the html pages that provides the UI for the app and the Scripts folder contains all the JavaScript files needed to add interactions. The Content folder is where you should store any CSS style sheets.

Our mail app will display a list of cities and landmarks based on the location of an appointment in Outlook. We’ll use the GeoNames WebServices and its jeoQuery jQuery wrapper again to return the information we need.

In order to use jeoQuery we first need to add it as well as the jQuery library to our project’s Scripts folder.

Adding the jeoQuery library to the Scripts folder

Next, we need to add the required HTML mark-up to display the UI of our mail app to the user. We’ll use the Default.html file for this.

Default.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <title>Outlook Locations App</title>
 
    <link rel="stylesheet" type="text/css" href="../Content/Office.css" />
    <link rel="stylesheet" type="text/css" href="../Content/App.css" />
 
    <script src="../Scripts/jquery.min.js"></script>
    <script src="https://az88874.vo.msecnd.net/api/1.0/office.js"></script>
    <script src="../Scripts/jeoquery.js"></script>
    <script src="../Scripts/App.js"></script>
</head>
<body>
    <div id="Header">
        <h2 id="titleText" style="margin-top: 0px;"></h2>
    </div>
    <div id="Content" class="ui-grid-b">
    </div>
    <div id="MoreInfo">
        <a id="backLink" href="#"><h2 id="backText" style="margin-top: 0px;"></h2></a>
        <iframe id="wiki" frameborder="0"  height="200px" width="100%"
			style="visibility:hidden;"></iframe>
    </div>
    <div id="error" >
    </div>
</body>
</html>

App.js

The App.js file contains the logic to retrieve the data from the GeoNames web service.

// This function is run when the app is ready to start interacting with the 
// host application. It ensures the DOM is ready before updating the span
// elements with values from the current message
Office.initialize = function () {
    $(document).ready(function () {
        var item = Office.context.mailbox.item;
        jeoquery.userName = 'demo';
        jeoquery.wikipediaSearch(geoCallback, item.location, item.location, 'EN', 6);
 
        $("#backLink").click(function () {
            $('#Header').show();
            $('#Content').show();
            $('#MoreInfo').hide();
        });
 
    });
};
 
function geoCallback(data) {
    var counter = 1;
    $('#titleText').text(data.geonames.length + ' possible locations found');
    $.each(data.geonames, function (index, data) {
        if (counter == 1) {
            $('#Content').append(
				'<div class="ui-block-a"><div><img onclick=showWikiPage("' + 
				data.wikipediaUrl + '") height="75" width="100" src="' + 
				data.thumbnailImg + '"/><a href="http://' + 
				data.wikipediaUrl + '"><p class="title">' + 
				data.title + '</p></a><p><strong>Lat:</strong> ' + 
				Math.round(data.lat * 1000) / 1000 + '</p><p><strong>Lon:</strong> ' + 
				Math.round(data.lng * 1000) / 1000 + '</p></div></div>');
        }
        if (counter == 2) {
            $('#Content').append(
				'<div class="ui-block-b"><div><img onclick=showWikiPage("' + 
				data.wikipediaUrl + '") height="75" width="100" src="' + 
				data.thumbnailImg + '"/><a href="http://' + 
				data.wikipediaUrl + '"><p class="title">' + 
				data.title + '</p></a><p><strong>Lat:</strong> ' + 
				Math.round(data.lat * 1000) / 1000 + '</p><p><strong>Lon:</strong> ' + 
				Math.round(data.lng * 1000) / 1000 + '</p></div></div>');
        }
        if (counter == 3) {
            $('#Content').append(
				'<div class="ui-block-c"><div><img onclick=showWikiPage("' + 
				data.wikipediaUrl + '") height="75" width="100" src="' + 
				data.thumbnailImg + '"/><a href="http://' + 
				data.wikipediaUrl + '"><p class="title">' + 
				data.title + '</p></a><p><strong>Lat:</strong> ' + 
				Math.round(data.lat * 1000) / 1000 + '</p><p><strong>Lon:</strong> ' + 
				Math.round(data.lng * 1000) / 1000 + '</p></div></div>');
        }
        if (counter == 4) {
            $('#Content').append(
				'<div class="ui-block-a"><div><img onclick=showWikiPage("' + 
				data.wikipediaUrl + '") height="75" width="100" src="' + 
				data.thumbnailImg + '"/><a href="http://' + 
				data.wikipediaUrl + '"><p class="title">' + 
				data.title + '</p></a><p><strong>Lat:</strong> ' + 
				Math.round(data.lat * 1000) / 1000 + '</p><p><strong>Lon:</strong> ' + 
				Math.round(data.lng * 1000) / 1000 + '</p></div></div>');
        }
        if (counter == 5) {
            $('#Content').append(
				'<div class="ui-block-b"><div><img onclick=showWikiPage("' + 
				data.wikipediaUrl + '") height="75" width="100" src="' + 
				data.thumbnailImg + '"/><a href="http://' + 
				data.wikipediaUrl + '"><p class="title">' + 
				data.title + '</p></a><p><strong>Lat:</strong> ' + 
				Math.round(data.lat * 1000) / 1000 + '</p><p><strong>Lon:</strong> ' + 
				Math.round(data.lng * 1000) / 1000 + '</p></div></div>');
        }
        if (counter == 6) {
            $('#Content').append(
				'<div class="ui-block-c"><div><img onclick=showWikiPage("' + 
				data.wikipediaUrl + '") height="75" width="100" src="' + 
				data.thumbnailImg + '"/><a href="http://' + 
				data.wikipediaUrl + '"><p class="title">' + 
				data.title + '</p></a><p><strong>Lat:</strong> ' + 
				Math.round(data.lat * 1000) / 1000 + '</p><p><strong>Lon:</strong> ' + 
				Math.round(data.lng * 1000) / 1000 + '</p></div></div>');
        }
        counter++;
    });
}
 
function showWikiPage(url) {
    var wikiUrl = 'http://' + url;
    $('#Header').hide();
    $('#Content').hide();
    $('#wiki').attr('src', wikiUrl);
    $('#wiki').css('visibility', 'visible');
    $('#backText').text('< back');
}

The code first waits for the DOM to be ready and Office 2013 to be fully loaded. We then get a reference to the current open item in Outlook using the following line:

var item = Office.context.mailbox.item;

We pass the location property of the item, which in this case is an Outlook appointment, into the jeoQuery wikipediaSearch method which in turn returns the data to a call-back function called geoCallback.

The geoCallback function, loops through the list of returned locations and appends the data to the Content div element in our Default.html file.

The resulting Outlook 2013 mail app should look like this for the user when he opens an appointment:

Main page of the Mail app in Outlook 2013 Appointment

When the user clicks on an image, the code of our mail app hides the contents of the Content div element and shows the MoreInfo div element after setting the iFrame called wiki‘s src attribute to the Wikipedia url returned by the GeoNames web service. The user will then see the Wikipedia entry for the location he clicked on.

Details page of the Mail app in Outlook 2013

And there you have it; a small mail app to show the user more information about the location their appointment is scheduled at.

Thank you for reading. Until next time, keep coding!

Available downloads:

Sample Outlook 2013 mail app

Post a comment

Have any questions? Ask us right now!