GithubHelp home page GithubHelp logo

isabella232 / mail-api-win10-uwp Goto Github PK

View Code? Open in Web Editor NEW

This project forked from officedev/mail-api-win10-uwp

0.0 0.0 0.0 86 KB

Code sample and tutorial demostrating use of the Office 365 mail API in a Windows 10 application

License: MIT License

C# 100.00%

mail-api-win10-uwp's Introduction

#Office 365 Inbox Viewer for Windows 10#

I recently had a need to view an Office 365 email inbox for quick triage and task assignment as part of a larger project. This tutorial describes how to create a mail client for an Office 365 inbox.

Note: If you are using the sample code just to try out the application you must complete steps 5 through 9 below to create your application definition in Azure Active Directory and to ad the Azure AD ClientID into the App.xaml file.

Create the Project and add references

  1. Open Visual Studio 2015.
  2. File | New | Project...
  3. Select Visual C# | Windows | Universal | Blank App (Universal Windows)
  4. Uncheck the box for Show telemetry in the Windows Dev Center because this is a sample project only.
  5. Name the Project MailClientWin10App. Click OK
  6. In Solution Explorer right-click on References then click Add Connected Service. Select Office 365 APIs then click Configure.
  7. Enter you Office 365 developer domain (i.e. contosodev.onmicrosoft.com), click Next and enter your developer tenant credentials.
  8. Select Create new new Azure AD application to access Office 365 API services, click Next.
  9. Click Next until you arrive on Mail settings and select the Read your mail checkbox: Office 365 Mail Permissions
  10. Click Finish.

Removed the Frame Rate Counter

Let's first remove the ugly frame rate counter that shows up by default when debugging an app.

  1. Right-click on App.xaml and click View Code. Set EnableFrameRateCounter = false; (around line 46) or remove the line completely.

##Set up Office 365 Authentication##

Now that the Office 365 Service reference has been addded to the project, we can start developing code to authenticate against Azure Active Directory and retrieve email information from the Office 365 API. In order to generate the access token from Azure Active Directory we will use the WebAccountProvider class. To do this we will create an AuthUtil class our XAML page will use for authentication and creation of the Outlook client.

  1. Right-click on the project and create a new class (Add | Class) named AuthUtil.cs.

  2. Add the following using statements to the class:

    using Microsoft.Office365.OutlookServices;
    using Windows.Security.Authentication.Web.Core;
    using Windows.Security.Credentials;
  3. Add the following method which retrieves the access token using WebAccountProvider

    private static async Task<string> GetAccessToken()
    {
    	string token = null;
    
    	//first try to get the token silently
    	WebAccountProvider aadAccountProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync("https://login.windows.net");
    	WebTokenRequest webTokenRequest = new WebTokenRequest(aadAccountProvider, String.Empty, App.Current.Resources["ida:ClientID"].ToString(), WebTokenRequestPromptType.Default);
    	webTokenRequest.Properties.Add("authority", "https://login.windows.net");
    	webTokenRequest.Properties.Add("resource", "https://outlook.office.com/");
    	WebTokenRequestResult webTokenRequestResult = await WebAuthenticationCoreManager.GetTokenSilentlyAsync(webTokenRequest);
    	if (webTokenRequestResult.ResponseStatus == WebTokenRequestStatus.Success)
    	{
    		WebTokenResponse webTokenResponse = webTokenRequestResult.ResponseData[0];
    		token = webTokenResponse.Token;
    	}
    	else if (webTokenRequestResult.ResponseStatus == WebTokenRequestStatus.UserInteractionRequired)
    	{
    		//get token through prompt
    		webTokenRequest = new WebTokenRequest(aadAccountProvider, String.Empty, App.Current.Resources["ida:ClientID"].ToString(), WebTokenRequestPromptType.ForceAuthentication);
    		webTokenRequest.Properties.Add("authority", "https://login.windows.net");
    		webTokenRequest.Properties.Add("resource", "https://outlook.office.com/");
    		webTokenRequestResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest);
    		if (webTokenRequestResult.ResponseStatus == WebTokenRequestStatus.Success)
    		{
    			WebTokenResponse webTokenResponse = webTokenRequestResult.ResponseData[0];
    			token = webTokenResponse.Token;
    		}
    	}
    
    	return token;
    }
  4. Add a method to retrieve the Office 365 Outlook client

    public static async Task<OutlookServicesClient> EnsureClient()
    {
    	return new OutlookServicesClient(new Uri("https://outlook.office.com/api/v1.0"), async () => {
    		return await GetAccessToken();
    	});
    }

Converters to improve display

In order to display the email dates and attachment icon in a user-friendly manner, we will create a couple of converters which will be used by the XAML.

Create a new folder in your project named Converters.

NullableBoolVisibilityConverter

The NullableBoolVisibilityConverter class will convert from a nullable bool into a Visibility enumeration. This will allow us to determine whether the attachment icon will be visible within the email list.

Create a new class named NullableBoolVisibilityConverter within the Converters folder and insert the following code:

```csharp

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace MailClientWin10App.Converters
{
	class NullableBoolVisibilityConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, string language)
		{
			bool? b = value as bool?;
			if (b == null || !b.HasValue || !b.Value)
				return Visibility.Collapsed;
			else
				return Visibility.Visible;
			//if (b.Value) return Visibility.Visible;
			//else return Visibility.Collapsed;
		}

		public object ConvertBack(object value, Type targetType, object parameter, string language)
		{
			throw new NotImplementedException();
		}
	}
}

```

EmailDateToStringConverter

The EmailDateToStringConverter will do basic date formatting to show dates in a more friendly manner.

Create a new class named EmailDateToStringConverter within the Converter folder and insert the following code:

```csharp

using System;
using Windows.UI.Xaml.Data;

namespace MailClientWin10App.Converters 
{
	class EmailDateToStringConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, string language)
		{
			DateTimeOffset? dateVal = value as DateTimeOffset?;
			if (dateVal == null || !dateVal.HasValue)
				return value;

			var myDate = dateVal.Value.ToLocalTime();
			string retVal = string.Empty;
			if (myDate.Date == DateTime.Today)
			{
				retVal = myDate.ToString("h:mm tt");
			}
			else if (myDate.Date > DateTime.Today.AddDays(-6))
			{
				retVal = myDate.ToString("ddd h:mm tt");
			}
			else if (myDate.Year == DateTime.Today.Year)
			{
				retVal = myDate.Date.ToString("ddd M/dd");
			}
			else
			{
				retVal = myDate.Date.ToString("ddd M/dd/yy");
			}

			return retVal;
		}

		public object ConvertBack(object value, Type targetType, object parameter, string language)
		{
			throw new NotImplementedException();
		}
	}
}

```

Creating the main page

Modify the MainPage.xaml.cs file to test the connection to Office 365.

  1. Open MainPage.xaml and change the display to 13.3" Desktop (1280 x 720) 100% scale: MainPage display settings dropdown set to 1280 by 720

  2. We need to import the a few namespaces so that we can reference them within our XAML. Add the following within the <Page element:

        xmlns:outlook="using:Microsoft.Office365.OutlookServices"
        xmlns:converters="using:MailClientWin10App.Converters"
  3. Before the opening <Grid tag, we will add our converters and a template to render the list of emails. Add the following code:

    <Page.Resources>   
    	<DataTemplate x:Key="MasterListViewItemTemplate" x:DataType="outlook:IMessage">
    		<StackPanel Margin="12,11,12,13">
    			<Grid Grid.ColumnSpan="2">
    				<Grid.ColumnDefinitions>
    					<ColumnDefinition Width="*" />
    					<ColumnDefinition Width="Auto" />
    				</Grid.ColumnDefinitions>
    
    				<TextBlock Text="{x:Bind From.EmailAddress.Name}" MaxLines="1"
    					   Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}"
    					   Style="{ThemeResource SubtitleTextBlockStyle}" />
    
    				<SymbolIcon Symbol="Attach" Grid.Column="1" Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}" Visibility="{x:Bind HasAttachments,Converter={StaticResource NullableBoolConverter}}" />
    
    			</Grid>
    			<TextBlock Text="{x:Bind Subject}" Grid.Row="1" MaxLines="1"
    					   Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
    					   Style="{ThemeResource BodyTextBlockStyle}" Grid.ColumnSpan="2" />
    
    			<Grid>
    				<Grid.ColumnDefinitions>
    					<ColumnDefinition Width="*" />
    					<ColumnDefinition Width="Auto" />
    				</Grid.ColumnDefinitions>
    
    				<TextBlock Text="{x:Bind BodyPreview}" Style="{ThemeResource BodyTextBlockStyle}" 
    						Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
    						MaxLines="1" />
    				<TextBlock Text="{x:Bind DateTimeSent}" Grid.Column="1" Margin="12,2,0,0"
    					   Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
    					   Style="{ThemeResource BodyTextBlockStyle}" />
    			</Grid>
    		</StackPanel>
    	</DataTemplate>
    
    </Page.Resources>
    
  4. Between the grid tags, we need to add our layout which will be a simple 2 row, 2 column grid:

    <Grid.RowDefinitions>
    	<RowDefinition Height="Auto" />
    	<RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    	<ColumnDefinition x:Name="MasterColumn" Width="320" />
    	<ColumnDefinition x:Name="DetailColumn" Width="*" />
    </Grid.ColumnDefinitions>
    
  5. Add an inbox header and refresh button as another grid inside of the first grid and a progress indicator to display while the messages are being retrieved. Add the following just after the </Grid.ColumnDefinitions> tag:

    <Grid Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}">
    	<Grid.ColumnDefinitions>
    		<ColumnDefinition Width="*" />
    		<ColumnDefinition Width="Auto"/>
    	</Grid.ColumnDefinitions>
    	<TextBlock Text="Inbox" Margin="24,8,8,8"
    			   Style="{ThemeResource TitleTextBlockStyle}" />
    	<AppBarButton Icon="Refresh" Grid.Column="1" x:Name="RefreshButton" Click="RefreshButton_Click" />
    </Grid>
    
    <ProgressRing x:Name="progressRing" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="8,24,8,0" Grid.Row="1"/>
    
  6. Add a list to display the inbox. We'll use a ListView along with the template we created earlier. Add the following after the <ProgressRing /> element:

    <ListView x:Name="MasterListView" Grid.Row="1" ItemContainerTransitions="{x:Null}"
    		  ItemTemplate="{StaticResource MasterListViewItemTemplate}"
    		  IsItemClickEnabled="True"
    		  ItemClick="MasterListView_ItemClick">
    	<ListView.ItemContainerStyle>
    		<Style TargetType="ListViewItem">
    			<Setter Property="HorizontalContentAlignment" Value="Stretch" />
    			<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseLowBrush}" />
    			<Setter Property="BorderThickness" Value="0,0,0,1" />
    		</Style>
    	</ListView.ItemContainerStyle>
    </ListView>
    
  7. Wire up code to retrieve emails. In Solution Explorer, Right-click MainPage.xaml and select View Code. Add a new method to load emails:

    private async void LoadEmailMessagesFromOffice365()
    {
    	MasterListView.ItemsSource = null;
    	progressRing.IsActive = true;
    	
    	var outlookClient = await AuthUtil.EnsureClient();
    
    	var messages = await outlookClient.Me.Folders["Inbox"].Messages.OrderByDescending(m => m.DateTimeReceived).Take(50).ExecuteAsync();
    
    	progressRing.IsActive = false;
    
    	MasterListView.ItemsSource = messages.CurrentPage;
    }
  8. Create a method for the refresh button click event, call the load method when the page loads and a blank click handler for the list:

    
    private void RefreshButton_Click(object sender, RoutedEventArgs e)
    {
    	LoadEmailMessagesFromOffice365();
    }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    	base.OnNavigatedTo(e);
    	LoadEmailMessagesFromOffice365();
    }
    
    private void MasterListView_ItemClick(object sender, ItemClickEventArgs e)
    {
    
    }
    
    
  9. Run your project using Local Machine:

Local Machine Debugging

The first time the project runs you will be prompted for your Office 365 username and password.

Auth Dialog

Once authenticated you will be then prompted for consent to read your email.

Consent Dialog

The dialog will provide additional information to the user about what is going on. Then, if everything is successful, your email will be displayed:

Inbox Start

Click the refresh button and check to make sure the inbox re-loads.

Showing the email details

Now that we have the inbox displaying properly, let's create XAML and code to display the full subject and body of the email, including any HTML formatting.

We will add another DataTemplate that contains a simple grid containing a stack panel for the header and a WebView for displaying the HTML. However, before we can use binding with the web view, we first need to add a control extension.

  1. Right-click on the Converters folder and add a new class named ControlExtensions. Add the following code:

    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace MailClientWin10App.Converters
    {
    	class ControlExtensions
    	{
    
    		public static string GetHTML(DependencyObject obj)
    		{
    			return (string)obj.GetValue(HTMLProperty);
    		}
    
    		public static void SetHTML(DependencyObject obj, string value)
    		{
    			obj.SetValue(HTMLProperty, value);
    		}
    
    		// Using a DependencyProperty as the backing store for HTML.  This enables animation, styling, binding, etc...  
    		public static readonly DependencyProperty HTMLProperty =
    			DependencyProperty.RegisterAttached("HTML", typeof(string), typeof(ControlExtensions), new PropertyMetadata(0, new PropertyChangedCallback(OnHTMLChanged)));
    
    		private static void OnHTMLChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    		{
    			WebView wv = d as WebView;
    			if (wv != null)
    			{
    				wv.NavigateToString((string)e.NewValue);
    			}
    		}
    
    
    	}
    }
    
  2. Open MainPage.xaml again and insert the following template just after the <Page.Resources> tag.

        <converters:EmailDateToStringConverter x:Key="EmailDateToStringConverter" />
        <converters:NullableBoolVisibilityConverter x:Key="NullableBoolConverter" />
  3. Open MainPage.xaml again and insert the following template just before the </Page.Resources> tag.

    <DataTemplate x:Key="DetailContentTemplate" x:DataType="outlook:IMessage">
    	<Grid>
    		<Grid.RowDefinitions>
    			<RowDefinition Height="Auto" />
    			<RowDefinition Height="*" />
    		</Grid.RowDefinitions>
    
    		<StackPanel HorizontalAlignment="Stretch">
    			<TextBlock Text="{x:Bind From.EmailAddress.Name}" Grid.Row="1" MaxLines="1"
    				   Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
    				   Style="{ThemeResource SubtitleTextBlockStyle}" />
    			<TextBlock Text="{x:Bind DateTimeSent,Converter={StaticResource EmailDateToStringConverter}}" Grid.Row="2" Grid.Column="1" Margin="12,2,0,0"
    				   Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
    				   Style="{ThemeResource BodyTextBlockStyle}" />
    			<TextBlock Margin="0,8" Style="{ThemeResource TitleTextBlockStyle}"
    				   HorizontalAlignment="Left" Text="{x:Bind Subject}"/>
    		</StackPanel>
    
    		
    		<WebView x:Name="DetailContentWebView" converters:ControlExtensions.HTML="{x:Bind Body.Content}" 
    					Width="{Binding VisibleWidth, ElementName=DetailColumn,Mode=OneWay}" VerticalAlignment="Stretch"
    					ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollMode="Auto" Grid.Row="1"
    				  />
    		
    	</Grid>
    </DataTemplate>
    
  4. Add a content presenter control just before the final </Grid> tag on the page:

    <ContentPresenter
    	x:Name="DetailContentPresenter"
    	Grid.Column="1"
    	Grid.RowSpan="2"
    	BorderThickness="1,0,0,0"
    	Padding="24,0"
    	BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"
    	Content="{x:Bind MasterListView.SelectedItem, Mode=OneWay}"
    	ContentTemplate="{StaticResource DetailContentTemplate}">
    </ContentPresenter>
    
    

Congratulations!

You just built a working Office 365 inbox viewer in Windows 10.

Press F5 to run your project and test your application.

Working Inbox Viewer

This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

mail-api-win10-uwp's People

Contributors

davidchesnut avatar dougperkes avatar jthake-msft avatar paulstubbs avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.