Chapter 6

Exchange Online Development

What’s in This Chapter?

  • Understanding Exchange Online in Office 365
  • Developing solutions for Exchange Online using the Exchange Web Services Managed API

In this chapter, you learn how to build solutions that integrate with Microsoft Exchange Online data and services. Using the Exchange Web Services Managed API, you can create and manage mailbox items such as email messages, contacts, tasks, and appointments. You can also leverage Exchange services, such as the Free Busy service, to replicate the functionality in Microsoft Outlook that finds the best meeting times for a set of attendees. Finally, you learn how to build notification solutions in which your application subscribes to streaming notifications in a mailbox, enabling you to listen for and handle specific events in the mailbox.

Introducing Exchange Online in Office 365

Exchange Online provides a cloud-hosted mail and calendar solution based on Microsoft Exchange Server. Users access their mailbox using Microsoft Outlook 2010 or in their browser using Outlook Web Access. The fact that their mailbox is in the cloud is invisible to the user.

In this section, you learn about the tools for developing solutions for Exchange Online—specifically the Exchange Web Services Managed API. You learn how to use Remote PowerShell to administer Exchange Online, and also how your applications use Autodiscover to connect to Exchange Online.

Exchange On-Premises Versus Exchange Online

From a development perspective, there isn’t much difference between Exchange Online and Exchange on-premises. With only minor tweaks, applications written to run against Exchange Service on-premises can work against Exchange Online.

However, compared to other products that are part of Office 365, Exchange Online is relatively mature, having been previously available as a hosted version in Business Productivity Online Services (BPOS). Microsoft’s experience in providing a hosted Exchange offering gives a tremendous benefit to Exchange developers and administrators; Microsoft has worked through the challenges to enable the product to run in a multitenant, cloud-hosted environment without limiting its functionality. As a developer, you are not limited in the type of solutions you can build for Exchange Online.

So be sure to thumb your nose at SharePoint developers who are limited to building Sandboxed Solutions and can’t yet use PowerShell to remotely administer SharePoint Online.

Introducing the Exchange Web Services Managed API

Exchange Server exposes a set of web services that applications can use to access Exchange services and mailbox data; these web services are known as Exchange Web Services (EWS). Application such as Microsoft Outlook use EWS to configure a user’s mailbox and access services, such as the Exchange Free Busy service.

The Exchange Web Services Managed API (EWS Managed API) is a managed API built on top of EWS; it abstracts the complexity of working directly with EWS by wrapping the functionality in an easy-to-use, managed API.

When to Use the Exchange Web Services Managed API

The EWS Managed API greatly simplifies the development experience of working with EWS. Before the release of the EWS Managed API, the only way for developers to work with EWS from managed code was to add a service reference from their Visual Studio project and code against the generated proxy classes.

The EWS Managed API abstracts the complexity of working with EWS; for example, by eliminating the need to manually construct and send the EWS web request and handle the asynchronous response. However, you need to give up the convenience of working with the EWS Managed API in some development scenarios:

  • The current version of the EWS Managed API is not compiled for Silverlight; you cannot reference and use it from a Silverlight application. You can work around this limitation by creating a service that wraps the necessary functionality from the EWS Managed API and calling it from Silverlight.
  • HTML5/JavaScript development is quickly becoming more prevalent; in this development model you need to interact directly with EWS through JavaScript.
  • You must work with EWS directly if you need to access it from a non-.NET platform.
  • Some of the less frequently used, more obscure features of EWS have not been exposed in the EWS Managed API.
  • Updates to the EWS Managed API tend to lag behind updates to Exchange Server. If you need to leverage the latest and greatest EWS features before an updated version of the EWS Managed API is released, you need to work directly with EWS.

The EWS Managed API makes EWS development easy using a discoverable and easy-to-use, managed API. However, you must work with EWS directly in some development scenarios.

Setting Up Your Development Environment

The EWS Managed API installer is available as a 32- or 64-bit download. Download and install the appropriate version for your development and environment that you’ll deploy your application into.

The API is installed by default to C:Program FilesMicrosoftExchangeWeb Services1.1 (or Program Files (x86) for the 32-bit version). In the above install path, 1.1 indicates the version of the EWS Managed API that is installed. You can reference Microsoft.Exchange.WebServices.dll from this location, or you can copy it to a folder in your source code and reference it from there.

You can download the EWS Managed API (and other Exchange Server developer downloads) from the Exchange Server Developer Center at http://msdn.microsoft.com/en-us/exchange/aa731546.aspx.

Administering Exchange Online Using PowerShell

When administering an on-premises Exchange Server deployment using PowerShell, the Exchange Server Management Shell connects using the identity of the logged-in user. To administer Exchange Online using PowerShell, you need to establish a Remote PowerShell connection to the Exchange Online environment. However, you first must set the credentials to authenticate with Exchange Online. You can capture the credentials by running the Get-Credential PowerShell cmdlet; this pops up a window into which you can enter Live ID credentials.

Next, use the New-PSSession cmdlet to establish a connection with the generic Remote PowerShell endpoint at http://ps.outlook.com/powershell. Office 365 is a multitenant environment, so you must connect to a Remote PowerShell endpoint specific to your Office 365 tenancy. You don’t need to know the address of the endpoint for your Office 365 tenancy; after you authenticate with the Remote PowerShell endpoint at http://ps.outlook.com/powershell, it uses the provided credentials to find and connect to an appropriate endpoint.

download.eps
$LiveCred = Get-Credential
 
$Session = New-PSSession 
        -ConfigurationName Microsoft.Exchange 
        -ConnectionUri https://ps.outlook.com/powershell/ 
        -Credential $LiveCred 
        -Authentication Basic 
        -AllowRedirection
Import-PSSession $Session -ea SilentlyContinue

code snippet ConnectToExchangeOnline.ps1

As you can see in Figure 6-1, the connection is redirected until it connects to the Remote PowerShell endpoint specific to your Office 365 tenancy.

Now that you are connected to Exchange Online via Remote PowerShell, you can execute other PowerShell management cmdlets as you would on-premises using the Exchange Server Management Shell.

Building Applications for Exchange Online

Before your EWS Managed API-based application can leverage Exchange Online data and services, it must connect to Exchange Online. In this section, you learn how to connect to Exchange Online using the ExchangeService class and how to use the Autodiscover service to configure the instance of ExchangeService to connect to EWS at the most efficient URL for a certain user’s mailbox.

You then learn how to work with Exchange data such as emails, conversations, tasks, and appointments. You see how the EWS Managed API can enable your application to impersonate another user or perform mailbox operations using their credentials. You also learn how to use the new streaming notification functionality to subscribe to notifications on a user’s mailbox.

The ExchangeService Object

The ExchangeService class is the primary class through which your application connects to Exchange Online to interact with a user’s mailbox or access an Exchange service such as the Autodiscover service or Free Busy service.

To use the ExchangeService class in your code, make sure you add the appropriate using directive:

using Microsoft.Exchange.WebServices.Data;

Create an instance of the ExchangeService class, using an overload of the constructor to specify the version of the Exchange Server that you target:

var exchangeService 
    = new ExchangeService(ExchangeVersion.Exchange2010_SP1);

The ExchangeVersion enum includes the following values:

  • Exchange2007_SP1
  • Exchange2010
  • Exchange2010_SP1

You can use the EWS Managed API to connect to different types of Exchange Server deployments, not just Exchange Online. The ExchangeService class enables you to target a specific version of Exchange Server to take full advantage of the features in that version. If you don’t specify an ExchangeVersion, you can access only the least common denominator of features available across all the versions.

note.eps
At the time of this writing, Exchange Online is based on Exchange Server 2010 Service Pack 2; however, the EWS Managed API is still at version 1.1. Specify ExchangeVersion.Exchange2010_SP1 when creating an instance of the ExchangeService class to take advantage of the latest Exchange Server features available to the EWS Managed API.

The ExchangeService class also requires a set of credentials that it uses to connect to Exchange Online; set these using an instance of System.Net.NetworkCredential:

var credentials = new NetworkCredential()
{
    UserName = userName,
    Password = password
};

Now that you have created an instance of the ExchangeService class and specified the credentials to use to connect to Exchange Online, you must use the Autodiscover service to find the EWS URL that the application needs to connect to for the specific user.

Working with the Autodiscover Service

In a typical Exchange Server deployment, EWS is available at a URL such as https://exchange.mycompany.com/EWS/Exchange.asmx.

note.eps
EWS is only available at an https endpoint.

However, in a large deployment that may be geographically dispersed, EWS is available at multiple URLs hosted on servers around the globe—the application must connect to the URL most convenient to the signed-in user. For example, if a user’s mailbox is on a server in Japan, connecting to an EWS URL hosted on a server in the United States can cause performance issues due to network latency.

An application should always connect to the EWS URL most convenient to the user’s mailbox, but how do you find the EWS URL to connect to? Enter the Autodiscover service, which uses a set of credentials to find the most efficient EWS URL with which to connect.

warning.eps
You should never hardcode the EWS URL in your application. The most efficient EWS URL for a given user’s mailbox may vary in a large and globally distributed environment. Always use the Autodiscover service to locate the most efficient EWS URL for the user’s mailbox.

Autodiscover isn’t intended just for use by custom applications using the EWS Managed API. Microsoft Outlook also uses Autodiscover to configure users’ mailboxes and their connection to the Exchange environment.

The simplest way to use the Autodiscover service is to call the AutodiscoverUrl method on the instance of ExchangeService and specify the SMTP address of the user:

exchangeService.AutodiscoverUrl("[email protected]");

You can then access the EWS URL using the Url property of the ExchangeService class:

var ewsUrl = exchangeService.Url;

The Autodiscover process is optimized for an Exchange Server on-premises deployment. However, you can tweak the process slightly to make it go faster when executing your code against Exchange Online. To better understand these optimizations, it is beneficial to first explore how the Autodiscover works against Exchange Server on-premises.

Autodiscover in an Exchange On-Premises Deployment

Before exploring how to use Autodiscover in Exchange Online, it is helpful to understand how Autodiscover works in an Exchange on-premises deployment.

An Exchange Server on-premises deployment includes one or more servers running the Client Access role. The Client Access servers expose an Autodiscover virtual directory responsible for handling Autodiscover requests from EWS Managed API applications, or applications such as Microsoft Outlook.

The Client Access servers also contain an Active Directory object called the Service Connection Point (SCP). The SCP contains a list of all the URLs for the Autodiscover service in the Exchange Service deployment.

When your application calls ExchangeService.AutodiscoverUrl, the EWS Managed API queries the SCP for the Autodiscover service URL to use. The Autodiscover URL then returns the EWS URL to use for the particular users’ credentials/mailboxes.

Autodiscover in Exchange Online

Now that you have a basic understanding of how the Autodiscover process works in an Exchange Server on-premises deployment, you can learn how to optimize the process for Exchange Online.

In Exchange Online, there is no SCP that contains a list of all the Autodiscover service URLs in the environment. However, when you call ExchangeService.AutodiscoverUrl against Exchange Online, the EWS Managed API still tries to find the SCP to query it for that list. Several seconds are wasted until the operation times out and throws an exception, and the EWS Managed API tries another way to locate the Autodiscover service URL—this can be a frustrating experience for the user because it appears that the application is hanging.

If you set the TraceEnabled property of the ExchangeService class to true and call ExchangeService.AutodiscoverUrl, you see the exception that is thrown when the EWS Managed API can’t find the SCP, as shown in Figure 6-2.

Instead of relying on the shortcut to simply call ExchangeService.AutodiscoverUrl, you can work with the Autodiscover service directly and control the steps that it goes through to find the EWS URL with which to connect.

To work with the Autodiscover service directly, make sure you add the appropriate using directive to your code:

using Microsoft.Exchange.WebServices.Autodiscover;

The following code snippet goes through the following steps to get the EWS URL:

1. Specify the credentials to use by creating an instance of NetworkCredentials.

2. Create an instance of the ExchangeService class.
3. Set the credentials to use for the ExchangeService.
4. Create an instance of the AutodiscoverService class.
5. Set the credentials to use for the AutodiscoverService.
6. Set the EnableScpLookup property of the AutodiscoverService instance to false to bypass querying the Active Directory SCP.
7. Define a RedirectionUrlValidationCallback delegate on the AutodiscoverService instance. The Autodiscover service may redirect the request several times until it finds the URL. The delegate returns true, indicating that it is OK for the EWS Managed API to redirect the request.
8. Call GetUserSettings on the AutodiscoverService instance to extract specific user settings into an instance of GetUserSettingsResponse.
9. Extract the ExternalEwsUrl property from the GetUserSettingsResponse instance. This property is the EWS URL for the specified user.
10. Set the Url property of the ExchangeService instance to the value of ExternalEwsUrl.

That’s a lot of work for what you could previously achieve with one line of code, but it greatly improves the performance of the Autodiscover process.

The code snippet also enables tracing on both the ExchangeService and AutodiscoverService class instances, so you can see the requests and responses directly in the console application.

download.eps
// Set the credentials to user to connect to Exchange Online
var credentials = new NetworkCredential()
{
    UserName = userName,
    Password = password
};
 
Console.WriteLine("Autodiscovering Exchange Web Services URL for {0}{1}", 
    _userName, 
    Environment.NewLine);
 
// Create an instance of ExchangeService 
_exchangeService = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
 
// Enable tracing
_exchangeService.TraceEnabled = true;
 
// Set the credentials
_exchangeService.Credentials = credentials;
 
// Create an instance of the AutodiscoverService
_autodiscoverService 
    = new Microsoft.Exchange.WebServices.Autodiscover.AutodiscoverService();
 
// Enable Autodiscover tracing
_autodiscoverService.TraceEnabled = true;
 
// Set the credentials
_autodiscoverService.Credentials = credentials;
 
// Prevent the AutodiscoverService from querying the Active Directory SCP
_autodiscoverService.EnableScpLookup = false;
 
// Specify a redirection Url validation callback that returns true
_autodiscoverService.RedirectionUrlValidationCallback 
    = delegate { return true; };
 
// Use the AutodiscoverService to get the EWS Url for the user's mailbox
GetUserSettingsResponse response =
    _autodiscoverService.GetUserSettings(
        _userName,
        UserSettingName.ExternalEwsUrl);
 
// Extract the Exchange Web Services Url for the user's mailbox
var externalEwsUrl = 
    new Uri(response.Settings[UserSettingName.ExternalEwsUrl].ToString());
 
// Set the Url of the ExchangeService object
_exchangeService.Url = externalEwsUrl;

code snippet EXODevelopmentProgram.cs

Take a look at the trace generated by the Autodiscover process.

As you recall, there is no Active Directory SCP in Exchange Online that lists all the available Autodiscover endpoints. In this case, the Autodiscover process relies instead on convention to locate an Autodiscover endpoint. Autodiscover endpoints are typically located at URLs such as the following:

You can see in the trace that the Autodiscover process tries to locate an Autodiscover endpoint at several URLs before being finally redirected to https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml.

<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:22Z">
  Determining which endpoints are enabled for host 
  mydomain.com
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
          Tid="10" Time="2011-10-01 20:27:44Z">
  No Autodiscover endpoints are available for host 
  mydomain.com
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  Determining which endpoints are enabled for host 
  autodiscover.mydomain.com
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  No Autodiscover endpoints are available for host 
  autodiscover.mydomain.com
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  Trying to get Autodiscover redirection URL from 
  http://autodiscover.mydomain.com/autodiscover/autodiscover.xml.
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  Redirection URL found: 
  'https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml'
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  Determining which endpoints are enabled for host 
  autodiscover-s.outlook.com
</Trace>
 
<Trace Tag="AutodiscoverConfiguration" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  Host returned enabled endpoint flags: Legacy, Soap, WsSecurity
</Trace>

Next, you see the HTTP POST made to the Autodiscover endpoint as a result of calling AutodiscoverService.GetUserSettings to get the value of ExternalEwsUrl.

<Trace Tag="AutodiscoverRequestHttpHeaders" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  POST /autodiscover/autodiscover.svc HTTP/1.1
  Content-Type: text/xml; charset=utf-8
  Accept: text/xml
  User-Agent: ExchangeServicesClient/14.02.0051.000
</Trace>
 
<Trace Tag="AutodiscoverRequest" 
       Tid="10" Time="2011-10-01 20:27:44Z" 
       Version="14.02.0051.000">
  <?xml version="1.0" encoding="utf-8"?>
  <soap:Envelope 
        xmlns:a="http://schemas.microsoft.com/exchange/2010/Autodiscover" 
        xmlns:wsa="http://www.w3.org/2005/08/addressing" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
      <a:RequestedServerVersion>Exchange2010</a:RequestedServerVersion>
      <wsa:Action>
        http://schemas.microsoft.com/exchange/2010/Autodiscover                  
              /Autodiscover/GetUserSettings
      </wsa:Action>
      <wsa:To>
        https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc
      </wsa:To>
      </soap:Header>
    <soap:Body>
      <a:GetUserSettingsRequestMessage 
        xmlns:a="http://schemas.microsoft.com/exchange/2010/Autodiscover">
        <a:Request>
          <a:Users>
            <a:User>
              <a:Mailbox>[email protected]</a:Mailbox>
            </a:User>
          </a:Users>
          <a:RequestedSettings>
            <a:Setting>ExternalEwsUrl</a:Setting>
          </a:RequestedSettings>
        </a:Request>
      </a:GetUserSettingsRequestMessage>
    </soap:Body>
  </soap:Envelope>
</Trace>

And finally, the response containing the value of ExternalEwsUrl, the EWS URL for the specified user.

<Trace Tag="AutodiscoverResponseHttpHeaders" 
       Tid="10" Time="2011-10-01 20:27:44Z">
  200 OK
  Transfer-Encoding: chunked
  RequestId: 205e5b8f-21f4-47d5-868c-560ae408a3d8
  X-DiagInfo: CH1PRD0302CA003
  Cache-Control: private
  Content-Type: text/xml; charset=utf-8
  Date: Sat, 01 Oct 2011 20:26:29 GMT
  Server: Microsoft-IIS/7.5
  X-AspNet-Version: 2.0.50727
  X-Powered-By: ASP.NET
</Trace>
 
<Trace Tag="AutodiscoverResponse" 
       Tid="10" Time="2011-10-01 20:27:44Z" Version="14.02.0051.000">
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" 
              xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
      <a:Action s:mustUnderstand="1">
        http://schemas.microsoft.com/exchange/2010/Autodiscover
              /Autodiscover/GetUserSettingsResponse
      </a:Action>
      <h:ServerVersionInfo 
          xmlns:h="http://schemas.microsoft.com/exchange/2010/Autodiscover" 
          xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <h:MajorVersion>14</h:MajorVersion>
        <h:MinorVersion>1</h:MinorVersion>
        <h:MajorBuildNumber>225</h:MajorBuildNumber>
        <h:MinorBuildNumber>71</h:MinorBuildNumber>
        <h:Version>Exchange2010_SP2</h:Version>
      </h:ServerVersionInfo>
    </s:Header>
    <s:Body>
      <GetUserSettingsResponseMessage 
        xmlns="http://schemas.microsoft.com/exchange/2010/Autodiscover">
        <Response xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
          <ErrorCode>NoError</ErrorCode>
          <ErrorMessage />
          <UserResponses>
            <UserResponse>
              <ErrorCode>NoError</ErrorCode>
              <ErrorMessage>No error.</ErrorMessage>
              <RedirectTarget i:nil="true" />
              <UserSettingErrors />
              <UserSettings>
                <UserSetting i:type="StringSetting">
                  <Name>ExternalEwsUrl</Name>
                  <Value>
                  https://sn2prd0302.outlook.com/EWS/Exchange.asmx
                  </Value>
                </UserSetting>
              </UserSettings>
            </UserResponse>
          </UserResponses>
        </Response>
      </GetUserSettingsResponseMessage>
    </s:Body>
  </s:Envelope>
</Trace>

Working with Mailbox Items

The EWS Managed API makes it easy to work with mailbox items such as email messages, tasks, and appointments. In this section, you learn how to create and send an email message, how to create and update a task, and how to create a contact.

Working with Email

The ability to send email messages is a common feature of line-of-business applications; for example, to send a confirmation email after submitting a form or completing a workflow.

Fortunately, it is easy to send an email using the EWS Managed API:

1. Create a new email message by creating an instance of the EmailMessage class and specifying the instance of ExchangeService to use.
2. Set properties of the email message such as Subject.
3. Set the email message recipients using the ToRecipients, CcRecipients, and BccRecipients properties—these are all collections of strings that you can simply add recipients to.
4. Set the body of the message using an instance of the MessageBody class, which allows you to either specify that the body text is either BodyType.HTML or BodyType.Text.
5. Send the email message by calling EmailMessage.Send or EmailMessage.SendAndSaveCopy (which saves a copy of the email message in the user’s Sent Items folder).
download.eps
// Create an EmailMessage
var emailMessage = new EmailMessage(_exchangeService);
 
// Set message properties
emailMessage.Subject = "Hello from the cloud!";
emailMessage.ToRecipients.Add(recipient);
 
// Set message body
emailMessage.Body = new MessageBody() 
    {
        BodyType = BodyType.HTML,
        Text = "<p>I sent this using Exchange Web Services.</p>"
    };
 
// Send the message and save a copy in Sent Items
emailMessage.SendAndSaveCopy();

code snippet EXODevelopmentEXOMailboxItems.cs

note.eps
The constructor for most mailbox item classes in the EWS Managed API requires an instance of the ExchangeService class. Recall that the ExchangeService class has a Url property, which is the EWS URL that the ExchangeService instance is connected to. This is how the EWS Managed API knows to connect to the user’s mailbox to send email, create a task, and so on.

You can also add file attachments to an email message by specifying the path to the file or loading it from a byte array or stream.

emailMessage.Attachments.AddFileAttachment("C:\Invoice.docx");

You can even add other mailbox items as attachments to an email message. For example, you can attach a task or contact item to the message—handy if you like to include your contact card with every email. You can use the ItemAttachment<T> class, where T indicates the type of attachment; for example, ItemAttachment<Task>.

ItemAttachment<Task> taskAttachment = 
    emailMessage.Attachments.AddItemAttachment<Task>();

You should of course set the minimum required properties of the mailbox item you are attaching to the email message, such as the task subject.

Working with Tasks

The ability to create and assign a task in code can come in handy. For example, a CRM application can use the EWS Managed API to create a task to remind a sales representative to call a client.

To create a simple task, create an instance of the Task class, set its Subject, StartDate, and DueDate properties, and save it.

download.eps
 // Create a Task
var task = new Task(_exchangeService);
 
// Set the Task subject
task.Subject = "Finish writing Chapter 6";
 
// Set the Start and Due dates
task.StartDate = DateTime.Now;
task.DueDate = DateTime.Now.AddMonths(1);
 
// Create the Task
task.Save();

code snippet EXODevelopmentEXOMailboxItems.cs

You can also define a recurrence pattern for a task to repeat daily, weekly, monthly, or yearly; recurrence patterns are defined by the Recurrence enum. The following code snippet defines a simple weekly recurrence pattern to repeat the task every 1 week on a specific day of the week.

// Create a recurrence pattern for the Task
var dayOfTheWeek = (DayOfTheWeek)Enum.Parse(
    typeof(DayOfWeek), 
    task.StartDate.Value.DayOfWeek.ToString());
 
// Repeat every 1 week
task.Recurrence = new Recurrence.WeeklyPattern(
    startDate: task.StartDate.Value,
    interval: 1,
    daysOfTheWeek: dayOfTheWeek);

Working with Contacts

The EWS Managed API enables you to easily create contacts just as you would in Microsoft Outlook. To create a contact, create an instance of the Contact class, and set some of its basic properties such as Give Name, Surname, and CompanyName. You can also set the FileAs property to control how the contact name displays; for example as First Name Last Name (Company Name).

download.eps
 // Create a Contact
var contact = new Contact(_exchangeService);
 
// Set Contact properties
contact.GivenName = "Rebecca";
contact.Surname = "Laszlo";
contact.CompanyName = "Big Company, Inc.";
contact.FileAs = String.Format("{0}, {1}, ({2})", 
    contact.Surname, 
    contact.GivenName, 
    contact.CompanyName);
 
// Set the Contact's email address
contact.EmailAddresses[EmailAddressKey.EmailAddress1] 
    = "[email protected]";
 
// Set the Contact's physical address
var workAddress = new PhysicalAddressEntry() 
{
    Street = "2525 N. Long St.",
    City = "Megalopolis",
    State = "CA",
    CountryOrRegion = "United States of America",
    PostalCode = "90055"
};
contact.PhysicalAddresses[PhysicalAddressKey.Business] 
    = workAddress;
 
// Create the Contact
contact.Save();

code snippet EXODevelopmentEXOMailboxItems.cs

Email addresses and physical addresses work differently in contacts because a contact record can have several of each. The EmailAddresses and PhysicalAddresses properties of the Contact class are dictionaries, not collections, so you set them differently. For example, you can set contact.EmailAddresses[EmailAddressKey.EmailAddress1] to a string representing an email address, or contact.PhysicalAddresses[PhysicalAddressKey.Business] to an instance of PhysicalAddressEntry. This allows a contact record to have multiple email addresses and multiple physical addresses, such as a home or business address.

Working with Calendar Items

The EWS Managed API includes functionality that makes it easy to work with meeting appointments. In this section, you learn how to create a recurring meeting appointment, how to get a user’s upcoming appointments, and how to use the Free Busy service to find a suitable meeting time for a set of attendees.

Working with Meeting Appointments

To create a meeting appointment, create an instance of the Appointment class and set properties such as the Subject of the appointment, add required and optional attendees, optionally set a recurrence pattern, and send the meeting invite to the invitees.

download.eps
// Create an Appointment
var appointment = new Appointment(_exchangeService);
 
// Set properties of the Appointment
appointment.Subject = "Weekly Status Meeting";
appointment.RequiredAttendees.Add("[email protected]");
appointment.Start = new DateTime(
    DateTime.Now.Year, 
    DateTime.Now.Month, 
    DateTime.Now.Day, 
    DateTime.Now.AddHours(1).Hour, 
    0, 
    0);
appointment.End = appointment.Start.AddHours(1);
                
// Create a recurrence pattern for the Appointment
var dayOfTheWeek = (DayOfTheWeek) Enum.Parse(
    typeof(DayOfWeek), appointment.Start.DayOfWeek.ToString());
 
// Repeat every 1 week
appointment.Recurrence = new Recurrence.WeeklyPattern(
    appointment.Start.Date,
    1, 
    dayOfTheWeek);
 
// Save the appointment and send an invitation to the attendees
appointment.Save(SendInvitationsMode.SendToAllAndSaveCopy);

code snippet EXODevelopmentEXOCalendarItems.cs

You can use the RequiredAttendees and OptionalAttendees properties of the Appointment to invite people, resources, and rooms to an appointment. These are simple collections that you can add attendees to; you can define an attendee using a string representing an SMTP address or with an instance of the AttendeeInfo class. The AttendeeInfo class is useful because it allows you to add different types of attendees such as meeting organizers, optional attendees, resources (such as a projector), and conference rooms.

// Specify the meeting organizer
appointment.RequiredAttendees.Add(new AttendeeInfo()
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Organizer
});
 
// Invite someone else
appointment.RequiredAttendees.Add(new AttendeeInfo()
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Required
});
 
// Add a resource
appointment.RequiredAttendees.Add(new AttendeeInfo()
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Resource
});
 
// Set a room
appointment.RequiredAttendees.Add(new AttendeeInfo() 
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Room
});

Getting Upcoming Appointments

You can use the EWS Managed API to get a list of upcoming meeting appointments from your calendar and integrate the data into your application; for example, a CRM application can use the EWS Managed API to retrieve and display an account manager’s upcoming client meetings.

To retrieve a user’s meeting appointments from their calendar, start by defining a CalendarView; this class allows you to define a date range view of appointments in the user’s Calendar folder. To retrieve the list of meeting appointments, call ExchangeService.FindAppointments and specify the folder to search in, and the instance of CalendarView that you created. You need to define the folder to search in because meeting appointment items can technically exist in any mailbox folder.

download.eps
// Create a CalendarView 
var calendarView = new CalendarView(
    DateTime.Now,
    DateTime.Now.AddDays(numberOfDays));
 
// Search for Appointments in the Calendar folder 
//   during the time range specified by the CalendarView
FindItemsResults<Appointment> appointments =
    _exchangeService.FindAppointments(
        WellKnownFolderName.Calendar,
        calendarView);
            
// Display Appointments
foreach (var appointment in appointments)
{
    Console.WriteLine("Subject:	" 
        + appointment.Subject);
    Console.WriteLine("Date:		" 
        + appointment.Start.ToString("dd MMMM yyyy"));
    Console.WriteLine("Start Time:	" 
        + appointment.Start.ToString("hh:mm tt"));
    Console.WriteLine("End Time:	" 
        + appointment.End.ToString("hh:mm tt"));
    Console.WriteLine();
}

code snippet EXODevelopmentEXOCalendarItems.cs

Working with the Free Busy Service

The calendar in Microsoft Outlook provides functionality that helps you find suitable meeting times for a set of attendees, resources, and rooms, as shown in Figure 6-3.

After you choose the people to invite to the meeting, and optionally choose a room to have the meeting in, Microsoft Outlook displays a list of meeting times that work for all the attendees and the rooms that are available during those times. Each meeting suggested is also rated as Good, Fair, or Poor. Any conflicts are also highlighted. To enable this functionality, Microsoft Outlook uses the Exchange Free Busy service. You can use the EWS Managed API to interact with the Free Busy service directly from your application.

Here’s how to use the EWS Managed API to interact with the Free Busy service to find a set of suitable meeting times:

1. Define a list of attendees. This could include a meeting organizer, required attendees, optional attendees, resources, and rooms.
2. Create an instance of the AvailabilityOptions class to define the criteria that the Free Busy service can use to recommend meeting times.
3. Call ExchangeService.GetUserAvailability to make a request to the Free Busy service for suggestions for the defined list of attendees, during a specified time window, using the specified options.
4. Iterate through the provided suggestions and choose one.
5. Schedule the appointment.
download.eps
// Specify the meeting organizer
appointment.RequiredAttendees.Add(new AttendeeInfo()
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Organizer
});
 
// Invite someone else
appointment.RequiredAttendees.Add(new AttendeeInfo()
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Required
});
 
// Set a room
appointment.RequiredAttendees.Add(new AttendeeInfo() 
{
    SmtpAddress = "[email protected]",
    AttendeeType = MeetingAttendeeType.Room
});
 
// Set the AvailabilityOptions of the meeting
var options = new AvailabilityOptions();
options.MeetingDuration = 60;
options.MaximumNonWorkHoursSuggestionsPerDay = 4;
options.MinimumSuggestionQuality = SuggestionQuality.Good;
options.RequestedFreeBusyView = FreeBusyViewType.FreeBusy;
 
// Call the service to get a collection of meeting suggestions
GetUserAvailabilityResults results =
    _exchangeService.GetUserAvailability(
        attendees,
        new TimeWindow(DateTime.Now, DateTime.Now.AddDays(1)),
        AvailabilityData.FreeBusyAndSuggestions,
        options);
 
var availableTimes = new List<DateTime>();
int option = 1;
 
foreach (var suggestion in results.Suggestions)
{
    Console.WriteLine("Please select an available appointment time for "
        + suggestion.Date.ToString("dddd, dd MMMM yyyy") + ":");
    Console.WriteLine();
 
    Console.WriteLine("#	Suggestion	Quality");
    Console.WriteLine();
 
    foreach (var timeSuggestion in suggestion.TimeSuggestions)
    {
        availableTimes.Add(timeSuggestion.MeetingTime);
        Console.WriteLine(option.ToString() +
            "	" + timeSuggestion.MeetingTime.ToString("hh:mm tt") +
            "	" + timeSuggestion.Quality);
        option++;
    }
}

code snippet EXODevelopmentEXOCalendarItems.cs

The AvailabilityOptions class controls the types of meeting suggestions and data returned by the Free Busy service. For example, the MeetingDuration property denotes the duration in minutes of the meeting suggestions. The MinimumSuggestionQuality defines the quality of the suggestions. The RequestedFreeBusyView indicates the level of detail in the returned meeting suggestions; for example FreeBusyViewType.Details includes all the detail about appointments in the users’ calendar that the requesting user has permissions to view, whereas FreeBusyViewType.FreeBusy includes only start and end times of appointments in the users’ calendar.

The results returned by the Free Busy service are in the form of Suggestion objects. You can access properties of each suggestion, such as its quality, start, and end time.

Impersonating Other Users

Applications often need to perform mailbox operations that appear to have been created by another user. For example, if a CRM application creates a meeting appointment for a user, it shouldn’t appear to have been created by a service account. Email messages must also come from the actual sender, not the service account.

The EWS Managed API allows an account with the appropriate permissions to impersonate another account. In this section, you learn how to configure application impersonation, and see how to impersonate other users to create a meeting appointment using their rights.

Configuring Application Impersonation

To grant a service account permission to impersonate other users, you need to grant it the ApplicationImpersonation role over a set of users. The set of users can be an Active Directory Organizational Unit (OU), a security group, or a Microsoft Exchange management scope role filter that defines a set of users using some search criteria.

Use the New-ManagementRoleAssignment PowerShell cmdlet to configure impersonation. The following example grants the ApplicationImpersonation role to the [email protected] account over all the users in the organization—obviously not something you’d want to do, but a good, simple example to start with.

New-ManagementRoleAssignment 
    –Name "Impersonation-MyApp" 
    –Role "ApplicationImpersonation" 
    –User [email protected]

You can also grant the permission to impersonate users to a group of accounts; the following example grants the ApplicationImpersonation role to all the accounts in the Service Accounts group.

New-ManagementRoleAssignment 
    –Name "Impersonation-MyApp-Group" 
    –Role "ApplicationImpersonation" 
    –SecurityGroup "Service Accounts"

The previous examples granted a service account—or group of service accounts—permission to impersonate all the users in the organization. A more realistic scenario is to grant this permission only for a smaller set of users. You can create a management scope filter that defines the set of users, for example, based on their membership in a specific department.

Create the management scope filter using the New-ManagementScope PowerShell cmdlet, and set the RecipientRestrictionFilter to define the condition for membership in this management scope filter.

New-ManagementScope 
    -Name "Sales Users" 
    -RecipientRestrictionFilter { Department -Eq "Sales" }

You can then create the management role assignment and specify the management scope filter to apply it to. In the following example, [email protected] has permission to impersonate members of the Sales department.

New-ManagementRoleAssignment 
    –Name "Impersonation-MyApp-Scope" 
    –Role "ApplicationImpersonation" 
    –User [email protected] 
    -CustomRecipientWriteScope "Sales Users"

Impersonating a User Account

Now that you have configured impersonation using PowerShell, you can use the EWS Managed API to impersonate other users and perform mailbox operations using their rights.

To impersonate an account, set the ImpersonatedUserId property of the ExchangeService instance to an instance of the ImpersonatedUserId class. Any mailbox operations that you perform after setting the ImpersonatedUserId are executed using that account’s rights.

download.eps
// Set the user to impersonate 
_exchangeService.ImpersonatedUserId =
    new ImpersonatedUserId(
        ConnectingIdType.SmtpAddress,
        "[email protected]");
 
// Create the Appointment
var appointment = new Appointment(_exchangeService);
appointment.Subject = "Review Proposal";
appointment.Start = DateTime.Now;
appointment.End = appointment.Start.AddHours(1);
appointment.RequiredAttendees.Add("[email protected]");
 
// Handle the ServiceResponseException 
try
{
    appointment.Save(
        SendInvitationsMode.SendToAllAndSaveCopy);
}
catch (Microsoft.Exchange.WebServices.Data.ServiceResponseException ex)
{
    throw ex;
}
 
// Set ImpersonatedUserId to null
_exchangeService.ImpersonatedUserId = null;

code snippet EXODevelopmentEXOCalendarItems.cs

If the service account doesn’t have the permission to impersonate the specified account, calls to perform any impersonated mailbox operations can throw a Microsoft.Exchange.WebServices.Data.ServiceResponseException exception.

note.eps
When performing mailbox operations using impersonation, it’s as if you connect to EWS using the impersonated account’s credentials. Therefore, when running Autodiscover to get the EWS URL to connect to, you should specify the impersonated account’s SMTP address instead of that of the service account.

Recall that any operations that you perform after setting ExchangeService.ImpersonatedUserId will be created using the impersonated user’s rights—and will appear to have been created by them. You should set ExchangeService.ImpersonatedUserId back to null when you finish impersonating the account.

Working with Conversations

Microsoft Outlook—and other email clients—include the ability to organize email messages into conversations. You can then perform actions on all the messages in a conversation; such as moving them to a different folder or categorizing them.

In this section, you learn how to use the EWS Managed API to work with conversations, including how to retrieve conversations from a user’s mailbox, move the messages in the conversation and categorize the messages in the conversation.

Retrieving Conversations from a Mailbox

Email messages in a conversation are typically spread out across multiple folders in a user’s mailbox; for example, the latest messages would be in the inbox folder, and the user might have already moved other messages in the conversation to a different folder.

The EWS Managed API provides functionality to retrieve conversations from the user’s mailbox and examine their contents. The first step is to define a ConversationIndexedItemView and specify how many conversations the operation should retrieve. You can then call ExchangeService.FindConversation to find conversations in the user’s mailbox; the FindConversation method accepts an instance of ConversationIndexedItemView and the folder to search in.

download.eps
var conversationView = new ConversationIndexedItemView(
    pageSize: Int32.MaxValue, 
    offset: 0, 
    offsetBasePoint: OffsetBasePoint.Beginning);
 
var conversations = _exchangeService.FindConversation(
    view: conversationView, 
    folderId: WellKnownFolderName.Inbox);
 
foreach (var conversation in conversations)
{
    Console.WriteLine("Conversation Id: {0}", conversation.Id);
    Console.WriteLine("Conversation Topic: {0}", conversation.Topic);
    Console.WriteLine("Number of Messages in Conversation: {0}", 
        conversation.GlobalMessageCount);
 
    Console.WriteLine("Messages:");
    var messageIdsInConversation = conversation.GlobalItemIds;
 
    foreach (var itemId in messageIdsInConversation)
    {
        var item = Item.Bind(_exchangeService, itemId);
        Console.WriteLine("Received: {0}", item.DateTimeReceived);
        Console.WriteLine("Contained in Folder: {0}", item.ParentFolderId);
    }
}

code snippet EXODevelopmentEXOConversations.cs

You can then iterate through all the conversations in the search results and the messages contained in them.

This example specifically looks for conversations in the Inbox folder, however, as you know, the email messages in a conversation can be spread out across multiple folders in a user’s mailbox. The Conversation class exposes properties such as MessageCount and ItemIds that apply only to messages in the folder specified in the instance of ConversationIndexedItemView. For example, the conversation.MessageCount property indicates the number of email messages in the conversation in the Inbox folder.

These properties have “global” counterparts; for example the GlobalMessageCount and GlobalItemIds apply to all the messages in a conversation regardless of the folder they are in. The conversation.GlobalMessageCount property indicates the number of email messages in the conversation across the user’s entire mailbox.

Table 6-1 shows a list of conversation properties and their global equivalents.

Table 6-1: Conversation Properties

Property Global Property Purpose
Categories GlobalCategories The categories that have been applied to the conversation
FlagStatus GlobalFlagStatus Whether the conversation is flagged as important
HasAttachments GlobalHasAttachments Indicates if any of the messages in the conversation have attachments
Importance GlobalImportance The importance of the conversation
ItemClasses GlobalItemClasses The different types of mailbox items contained in the conversation
ItemIds GlobalItemIds The unique IDs of the messages in the conversation
LastDeliveryTime GlobalLastDeliveryTime The delivery time of the last message received in the conversation
MessageCount GlobalMessageCount The number of messages in the conversation
Size GlobalSize The total size of all the messages
UniqueRecipients GlobalUniqueRecipients All the recipients of the messages in the conversation
UniqueSenders GlobalUniqueSenders All the senders of the messages in the conversation
UniqueUnreadSenders GlobalUniqueUnreadSenders List of people who have sent messages that are still unread
UnreadCount GlobalUnreadCount Number of unread messages in the conversation

Source: EWS Managed API 1.1 Documentation

Performing Actions on Messages in a Conversation

After getting a handle to a particular conversation, you can perform actions that apply to all the email messages in the conversation. You can delete the conversation and all the email messages in it; move or copy the conversation to another folder; or mark the conversation as read or unread.

To delete a conversation, call Conversation.DeleteItems, and specify the folder to delete items from and the delete mode. The following example deletes the conversation from the Inbox folder; the messages are hard-deleted—they are permanently deleted and not copied to the Deleted Items folder.

conversation.DeleteItems(
    WellKnownFolderName.Inbox, 
    DeleteMode.HardDelete);

The DeleteMode enum contains the following values:

  • HardDelete: Permanently delete the email messages in the conversation.
  • MoveToDeletedItems: Move the email messages in the conversation to the Deleted Items folder.
  • SoftDelete: Move the email messages in the conversation to the dumpster; you can later retrieve them from the dumpster using the Recover Deleted Items feature accessible in the Ribbon in Microsoft Outlook.

If you don’t specify a folder to delete from, the email messages in the conversation are deleted from all the folders in the user’s mailbox.

You can also move the email messages in a conversation to another folder by using Conversation.MoveItemsInConversation, or copy them to another folder by using Conversation.CopyItemsInConversation.

Categorizing Conversations

Microsoft Outlook allows you to apply categories to email messages in a conversation to make them easier to manage. Categories are also used in the Quick Steps feature of Microsoft Outlook, which allows you to perform multiple actions on a conversation using a keyboard shortcut; for example, apply a category and move the email messages in the conversation to a specific folder.

The following example applies multiple categories to the email messages in a conversation. You can define the categories in a List<string> and call Conversation.EnableAlwaysCategorizeItems to apply them to the conversation.

download.eps
var conversationView = new ConversationIndexedItemView(
    pageSize: Int32.MaxValue, 
    offset: 0, 
    offsetBasePoint: OffsetBasePoint.Beginning);
 
var conversations = _exchangeSevice.FindConversation(
    view: conversationView, 
    folderId: WellKnownFolderName.Inbox);
 
foreach (var conversation in conversations)
{
    var categories = new List<string>() 
        {
            "2011",
            "Projects"
        };
    conversation.EnableAlwaysCategorizeItems(categories, false);
}

code snippet EXODevelopmentEXOConversations.cs

Conversation.EnableAlwaysCategorizeItems indicates that all future email messages in the conversation should be automatically tagged with those categories. You can disable that by calling Conversation.DisableAlwaysCategorizeItems.

Alternatively, you can access the Conversation.Categories collection directly to add and remove items from it.

Working with Streaming Notifications

Notifications allow you handle certain events on a user’s mailbox and run custom actions when those events occur. For example, you can monitor a customer service mailbox for new emails, and when a new message arrives, parse its contents and create a record in a customer service ticketing system. In this section, you learn how to work with the new Streaming Notification functionality in the EWS Managed API 1.1.

Version 1.0 of the EWS Managed API provided functionality to create subscriptions for both pull and push notifications. When subscribing to pull notifications, you specify the mailbox events to subscribe to and then manually check for any notifications; for example, using a timer to check for new notifications every 30 seconds. Push notifications work as you would expect; they automatically push notifications about events that your application is subscribed to. Using the EWS Managed API to develop pull subscription functionality is easy to do; however, it requires you to continuously poll Exchange for new notifications. Push subscriptions get around this issue, but they are complex to develop by comparison—you have to implement your own push notification listener for Exchange or Exchange Online to send notifications to.

The EWS Managed API 1.1 introduces Streaming Notifications, which replicate the functionality in push notifications but remove the need to build your own notification listener—making it a lot easier to implement in your application.

Creating a Streaming Notification Subscription

To subscribe to Streaming Notifications and handle notification events, your application should:

1. Call ExchangeService.SubscribeToStreamingNotifications and specify the folders and events to subscribe to.
2. Create a new StreamingSubscriptionConnection that specifies the lifetime of the subscription.
3. Add the Streaming Notification subscription to the subscription connection.
4. Define handlers for the different events raised by the subscription connection.
5. Implement the events handlers to handle the specific events.

When calling ExchangeService.SubscribeToStreamingNotifications to create a subscription for Streaming Notifications, provide an array of mailbox folder IDs to subscribe to events in, and an array of the types of events to subscribe to. The EventType enum defines the types of mailbox that can occur; its values include the following:

  • Status
  • NewMail
  • Deleted
  • Modified
  • Moved
  • Copied
  • Created
  • FreeBusyChanged

After creating a StreamingSubscriptionConnection, you can add multiple subscriptions to it. This gives you the flexibility to create subscriptions for different events in different mailbox folders and add them all to the same subscription connection.

The SubscriptionConnection class exposes three events:

  • OnNotificationEvent: Indicates that a mailbox event has occurred
  • OnSubscriptionError: Indicates that an error has happened in the subscription
  • OnDisconnect: Indicates that the subscription has expired or been disconnected
download.eps
// Subscribe to events on the user's Inbox
var subscription = 
    _exchangeService.SubscribeToStreamingNotifications(
        folderIds: new FolderId[] {WellKnownFolderName.Inbox}, 
        eventTypes: new EventType[] 
        {
            EventType.NewMail,
            EventType.Created,
            EventType.Deleted
        });
 
// Define a connection for the subscription
var subscriptionConnection = new StreamingSubscriptionConnection(
    service: _exchangeService,
    lifetime: 30);
 
// Add the subscription
subscriptionConnection.AddSubscription(subscription);
 
// Define handlers for notification events
subscriptionConnection.OnNotificationEvent += 
    new StreamingSubscriptionConnection.NotificationEventDelegate(
        subscriptionConnection_OnNotificationEvent);
 
// Define handler for subscription errors
subscriptionConnection.OnSubscriptionError += 
    new StreamingSubscriptionConnection.SubscriptionErrorDelegate(
        subscriptionConnection_OnSubscriptionError);
 
// Define handler for when the subscription disconnects or expires
subscriptionConnection.OnDisconnect += 
    new StreamingSubscriptionConnection.SubscriptionErrorDelegate(
        subscriptionConnection_OnDisconnect);
 
// Open the subscription connection
subscriptionConnection.Open();
 
Console.WriteLine("Created streaming notification subscription.");
Console.WriteLine("Waiting for notifications...");
Console.ReadLine();

code snippet EXODevelopmentEXONotifications.cs

note.eps
You can use SubscribeToStreamingNotificationsOnAllFolders to subscribe to Streaming Notifications on all the folders in a user’s mailbox instead of having to list them all.

Handling Notification Events

In this section, you learn how to implement the handlers for the different events raised by the SubscriptionConnection class:

  • OnNotificationEvent
  • OnSubscriptionError
  • OnDisconnect

The SubscriptionConnection.OnNotificationEvent event is raised when an event defined in the Streaming Notification subscriptions occurs. The NotificationEventArgs exposes an Events collection; you can iterate through each event, examine it, and take appropriate action.

Notification events can occur on either mailbox items or folders; you can examine the type of notification event by checking if it is an ItemEvent or FolderEvent. This gives you the flexibility to take different action based on the type of notification event.

download.eps
void subscriptionConnection_OnNotificationEvent
    (object sender, NotificationEventArgs args)
{
    // Get a handle to the subscription
    var subscription = args.Subscription;
 
    // Iterate through the events
    foreach (var notificationEvent in args.Events)
    {
        if (notificationEvent is ItemEvent)
        {
            switch (notificationEvent.EventType)
            {
                case EventType.Created:
                    Console.WriteLine("Notification: message created.");
                    break;
                case EventType.Deleted:
                    Console.WriteLine("Notification: message deleted.");
                    break;
                case EventType.NewMail:
                    Console.WriteLine("Notification: new email message.");
                    break;
                default:
                    break;
            }
 
            var itemEvent = notificationEvent as ItemEvent;
            Console.WriteLine("ItemId: {0}", itemEvent.ItemId.UniqueId);
            Console.WriteLine("Subject: {0}", 
                Item.Bind(_exchangeService, itemEvent.ItemId.UniqueId).Subject);
        }
    }
}

code snippet EXODevelopmentEXONotifications.cs

The SubscriptionConnection.OnSubscriptionError event is raised when an error occurs in the subscription connection. The underlying Exception object is accessible through the instance of SubscriptionErrorEventArgs.

download.eps
void subscriptionConnection_OnSubscriptionError
    (object sender, SubscriptionErrorEventArgs args)
{
    Console.WriteLine(
        "An error has occurred: {0}", 
        args.Exception.Message);
}

code snippet EXODevelopmentEXONotifications.cs

The SubscriptionConnection.OnDisconnect event is raised when the subscription expires or is disconnected. You can choose to automatically reconnect to the subscription or present a choice to the user. You can access the subscription connection by casting the sender parameter as an instance of StreamingSubscriptionConnection and then call the Open method to reopen it.

download.eps
void subscriptionConnection_OnDisconnect(
    object sender, SubscriptionErrorEventArgs args)
{
    var subscriptionConnection = 
        sender as StreamingSubscriptionConnection;
 
    ConsoleKeyInfo cki;
    Console.WriteLine("The connection has expired or been disconnected.");
    Console.WriteLine("Do you want to reconnect? Y/N");
    while (true)
    {
        cki = Console.ReadKey(true);
        {
            if (cki.Key == ConsoleKey.Y)
            {
                subscriptionConnection.Open();
                Console.WriteLine("Reopened subscription connection.");
                break;
            }
        }
    } 
}

code snippet EXODevelopmentEXONotifications.cs

Streaming Notifications in the EWS Managed API 1.1 provide a much easier way to work with notifications; they leverage the best features of push notifications but are easier to implement.

Summary

The EWS Managed API is an easy-to-use, managed API that makes it easier to work with EWS to connect to Exchange Online, work with mailbox items, and interact with Exchange services such as the Free Busy service.

In the next chapter, you learn about working with the Lync API to build communications solutions for Lync Online.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset