Picture 1

Exchange Online

1.Exchange Online

Exchange Online is the hosted version for the messaging platform in Microsoft Office 365 that provides organizations with access to the full-featured version of the traditional Onprem Exchange Server.

Microsoft Exchange Online is among the most mature of Microsoft’s cloud offerings, being part of the Office cloud offering from the beginning, when Office 365 was called Business Productivity Online Suite (BPOS). That also means that Exchange is almost fully developed and there has not been any new main functionality added for years.

The same can be said about the development possibilities of Exchange: The current API, the Exchange Web Services (EWS), hasn't changed in many years, although it is becoming replaced by the Microsoft Graph API, which is progressively introducing a new REST interface for the server.

1.1.Introduction to developing for Exchange

Exchange Online offers three main possibilities to be accessed programmatically: Exchange Web Services API (EWS), a dedicated set of PowerShell cmdlets (called Exchange Online PowerShell), and, since the introduction of Microsoft Graph, the possibility to approach Exchange Online using REST APIs has been open. Because Graph is an ongoing project by Microsoft, the functionality it offers is not (yet) as complete as the possibilities given by EWS, but Graph is officially replacing EWS. The Exchange Online PowerShell is mainly used for configuration, monitoring, maintenance, and to manage Exchange from the command line.

A close up of a logo

Description automatically generated

EWS is becoming deprecated: Microsoft has announced (https://developer.microsoft.com/en-us/graph/blogs/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/) that starting on July 19th, 2018 "...Exchange Web Services (EWS) will no longer receive feature updates. While the service will continue to receive security updates and certain non-security updates, product design and features will remain unchanged. This change also applies to the EWS SDKs for Java and .NET as well."

EWS can be used in precisely the same way for Exchange Online and Exchange Onprem, the only difference is given by the disparities in functionality in the two systems (they are very similar in any way), and the login method. EWS can be used in different ways: As a managed API by any development language (making SOAP, Simple Object Access Protocol, calls under the hood), as a set of SOAP Web Services, and from PowerShell. Because SOAP has been replaced by REST in the enterprise and is, in fact, not used anymore, its programmatic use will be not discussed in this book.

A close up of a logo

Description automatically generated

Regarding PowerShell, there is a set of cmdlets dedicated to Exchange Online Protection (EOP), but they are only used in standalone EOP organizations (for example, to protect an OnPremises Exchange environment). If you are working with an Office 365 subscription that includes EOP (E3, E5, etc.), you don't use Exchange Online Protection PowerShell; the same features are available in the standard Exchange Online PowerShell modules.

1.2.Login in Exchange

As it happens with other servers from Office 365, it is necessary to log in to the system to be authenticated, before any program can start interacting with the data.

1.2.1.Login from a managed language (CSharp)

For the CSharp examples in this chapter, the values to log in to Exchange (email address, password, application ID, and tenant ID, depending on the authorization method) are saved in an external file called exCs.values.config that is used by the appSettings section in the App.Config Visual Studio Solution file. The App.Config file for the Visual Studio Solution contains the following section inside the <configuration> tag:

<appSettings file="c:\Temporary\exCs.values.config">

<add key="exUserName" value="" />

<add key="exUserPw" value="" />

<add key="exAppId" value="" />

<add key="exTenantId" value="" />

</appSettings>

The first line points to an external file that contains the values to be used by the App.Config file; it has the following form:

<appSettings >

<add key="exUserName" value="user@domain.onmicrosoft.com" />

<add key="exUserPw" value="VerySecurePw" />

<add key="exAppId" value="SomeGuid" />

<add key="exTenantId" value="SomeGuid" />

</appSettings>

Note: The exAppId and exTenantId values are only needed if using oAuth (se section about oAuth later in this chapter).

The values can be called by their name in the appSettings file, as follows:

string myExUser = ConfigurationManager.AppSettings["exUserName"];

1.2.2.Login from PowerShell

EWS can be used by PowerShell to reach programmatically the Exchange information. The Microsoft.Exchange.WebServices.dll needed to work with EWS must be installed locally.

A close up of a logo

Description automatically generated

The EWS DLLs can be downloaded from https://www.microsoft.com/en-us/download/details.aspx?id=42951. Download the EwsManagedApi.msi file from that site and install it locally. The DLLs will be installed in the local directory C:\Program Files\Microsoft\Exchange\Web Services\2.2\.

To make the EWS DLLs available for PowerShell, they must be loaded at the beginning of the script with the following statement (which must be in one continuous line):

Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"

The values to log in to Exchange (email address, password, application ID, and tenant ID, depending on the authorization method) are saved in an external file called exPs.values.config (in XML format) that is loaded by PowerShell at runtime. The external config file is called at the beginning of the script, as follows:

[xml]$configFile = get-content "C:\Projects\exPs.values.config"

And the file exPs.values.config contains the values to be used in the script; it has the following form:

<appSettings>

<exUserName>user@domain.onmicrosoft.com</exUserName>

<exUserPw>VerySecurePw</exUserPw>

<exAppId>SomeGuid</exAppId>

<exTenantId>SomeGuid</exTenantId>

</appSettings>

Note: The exAppId and exTenantId values are only needed if using oAuth (se section about oAuth later in this chapter).

The values can be called by their name in the appSettings file, as follows:

$myUser = $configFile.appsettings.exUserPw

If PowerShell is not allowing to run scripts, change the execution policy using the command:

Set-ExecutionPolicy -ExecutionPolicy [Unrestricted]/[RemoteSigned]/[Default]

1.2.3.Login with user credentials for EWS (Basic Authentication) and CSharp

Microsoft recommends not to use basic authentication (using username/password) anymore, although Exchange Online still accepts this type of authentication. Nevertheless, basic authentication can be a good option, to avoid extensive setup tasks and repetitive logins, for simple test or demonstration applications.

A close up of a logo

Description automatically generated

EWS Basic Authentication is becoming fully decommissioned: Microsoft has announced (https://developer.microsoft.com/en-us/graph/blogs/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/) that on October 13th, 2020, it "...will stop supporting and fully decommission the Basic Authentication for EWS to access Exchange Online". This means that new or existing apps will not be able to use Basic Authentication when connecting to Exchange using EWS.

The function (ConnectBA) in the following recipe uses the email address and password of one user to get authorized in Exchange. The AutodiscoverUrl method determines the best endpoint for a given user (the endpoint that is closest to the user's Mailbox server); this method can be called using only the username parameter, but Exchange Online rejects the request as unsafe. Therefore, the RedirectionUrlValidationCallback routine, which is considered valid if it uses HTTPS, must be used in conjunction with the authentication call. Instantiating the ExchangeService with an empty constructor will create an instance that is bound to the latest known version of Exchange. The TraceEnabled and TraceFlag properties can be activated to get information from Exchange about the login process (for debugging purposes), and the Url method of the service instance gives back the address used by Exchange Online.

01.001

ID

File

Routines

NuGets

Microsoft.Exchange.WebServices, Microsoft.Identity.Client

Ref. DLLs

Microsoft.Exchange.WebServices, Microsoft.Exchange.WebServices.Auth, Microsoft.Identity.Client

Using

Microsoft.Exchange.WebServices.Data, Microsoft.Identity.Client

        static ExchangeService ConnectBA(string userEmail, string userPW)
        {
            ExchangeService exService = new ExchangeService
            {
                Credentials = new WebCredentials(userEmail, userPW)
            };

            //exService.TraceEnabled = true;
            //exService.TraceFlags = TraceFlags.All;

            exService.AutodiscoverUrl(userEmail, RedirectionUrlValidationCallback);
            //Console.WriteLine(exService.Url);

            return exService;
        }

        static bool RedirectionUrlValidationCallback(string redirectionUrl)
        {
            bool validationResult = false;

            Uri redirectionUri = new Uri(redirectionUrl);
            if (redirectionUri.Scheme == "https")
            {
                validationResult = true;
            }

            return validationResult;
        }

The authorization method can be called from any other routine as follows:

01.002

ID

File

Routines

NuGets

Microsoft.Exchange.WebServices, Microsoft.Identity.Client

Ref. DLLs

Microsoft.Exchange.WebServices, Microsoft.Exchange.WebServices.Auth, Microsoft.Identity.Client

Using

Microsoft.Exchange.WebServices.Data, Microsoft.Identity.Client

        static void Main(string[] args)
        {
            ExchangeService myExService = ConnectBA(
                                ConfigurationManager.AppSettings["exUserName"],
                                ConfigurationManager.AppSettings["exUserPw"]);

            CallEWSTest(myExService);
        }

1.2.4.Login with oAuth for EWS and CSharp

Although the fact that oAuth relies on a third-party authentication provider, that the standard is more difficult to implement than basic authentication, and that oAuth requires another layer of integration (the application will need both, the authentication provider and the Exchange server), Microsoft recommends using oAuth instead of basic authentication because of the advantage in security.

Since Office 365 uses Azure Active Directory (AAD) as authentication provider, any application that wants to use Office Exchange EWS oAuth authentication must have an application ID issued by AAD. The following steps indicate how to register one application as a public client with Azure Active Directory.

1 - Using a browser, navigate to the main administration page of Office 365 (https://admin.microsoft.com or through https://portal.office.com), log in with an administrator account, and open the Azure Active Directory Admin Center.

2 - Click on Azure Active Directory in the menu on the left side, and then on App registrations (Manage section). Use the New registration button.

3 - Assign a name to the registration, select Accounts in this organizational directory only in the Supported account types section, and select the Public client/native (mobile & desktop) option in the Redirect Uri section. Write the value urn:ietf:wg:oauth:2.0:oob on the textbox at the side of the Redirect Uri section. Use the Register button to save the registration.

4 - The registration is complete. Copy the values given in Application (client) ID and Directory (tenant) ID to use it in the source code of the application to be developed.

Note: If you are using the App.config file described in the initial section of this chapter, copy the Application (client) ID value to the exAppId parameter, and the Directory (tenant) ID value to the exTenantId parameter.

The Visual Studio solution to use the authentication from oAuth (a console applications in this chapter) requires a using directive to Microsoft.Identity.Client.

A close up of a logo

Description automatically generated

The DLLs to work with the Microsoft.Identity.Client can be installed by the NuGet Microsoft.Identity.Client by Microsoft (https://www.nuget.org/packages/Microsoft. Identity.Client/) directly from Visual Studio.

The function ConnectOA in the following recipe uses the Azure AD registration client and tenant ID to get authorized in Exchange.

01.003

ID

File

Routines

NuGets

Microsoft.Exchange.WebServices, Microsoft.Identity.Client

Ref. DLLs

Microsoft.Exchange.WebServices, Microsoft.Exchange.WebServices.Auth, Microsoft.Identity.Client

Using

Microsoft.Exchange.WebServices.Data, Microsoft.Identity.Client

        static async System.Threading.Tasks.Task<ExchangeService> ConnectOA(
                                                            string AppId, string TenId)
        {
            ExchangeService exService = new ExchangeService();

            PublicClientApplicationOptions pcaOptions = new PublicClientApplicationOptions
            {
                ClientId = AppId,
                TenantId = TenId
            };

            IPublicClientApplication pcaBuilder = PublicClientApplicationBuilder
                .CreateWithApplicationOptions(pcaOptions).Build();

            string[] exScope = new string[] {
                            "https://outlook.office.com/EWS.AccessAsUser.All" };

            AuthenticationResult authToken = await
                              pcaBuilder.AcquireTokenInteractive(exScope).ExecuteAsync();

            exService.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
            exService.Credentials = new OAuthCredentials(authToken.AccessToken);

            return await System.Threading.Tasks.Task.FromResult(exService);
        }

The first time that the application runs, a standard login window will appear requiring the account data of the user that made the registration. After login, the window will ask for permissions (Access your mailboxes, Maintain access to data you have given it access to and View your basic profile). Subsequently, the application will ask only for the user login, not for the permissions.

Because the connection routine is asynchronous, use the following code to call it.

01.004

ID

File

Routines

NuGets

Microsoft.Exchange.WebServices, Microsoft.Identity.Client

Ref. DLLs

Microsoft.Exchange.WebServices, Microsoft.Exchange.WebServices.Auth, Microsoft.Identity.Client

Using

Microsoft.Exchange.WebServices.Data, Microsoft.Identity.Client

        static void Main(string[] args)
        {
            ExchangeService myExService = ConnectOA(
                                ConfigurationManager.AppSettings["exAppId"],
                                ConfigurationManager.AppSettings["exTenantId"]).
                                                            GetAwaiter().GetResult();

            CallEWSTest(myExService);
        }

A close up of a logo

Description automatically generated

The use of oAuth to get access to Exchange is faster than the use of base authentication, especially because it is not necessary to use the auto-discovery method.

1.2.5.Login for EWS with PowerShell and Basic Authentication

The ConnectPsEwsBA routine in the next recipe takes care of login in Exchange using Basic Authentication with PowerShell.

01.005

ID

File

Routines

PS Modules

GenericOauthEWS.ps1

Other Modules

Microsoft.Exchange.WebServices.dll

Function ConnectPsEwsBA()
{
	$ExService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
	$ExService.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials(`
		$configFile.appsettings.exUserName, $configFile.appsettings.exUserPw)
	$ExService.Url = new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx");
	#$ExService.TraceEnabled = $true
	#$ExService.TraceFlags = [Microsoft.Exchange.WebServices.Data.TraceFlags]::All
	$ExService.AutodiscoverUrl($configFile.appsettings.exUserName, {$true})

	return $ExService
}

See section 1.2.2. to get details about login with PowerShell. The TraceEnabled and TraceFlag properties can be activated at any moment to get information regarding the internal working of Exchange when logging in.

To call the function, use code similar to the next example.

01.006

ID

File

Routines

PS Modules

GenericOauthEWS.ps1

Other Modules

Microsoft.Exchange.WebServices.dll

##==> EWS Basic Authorization
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
$ExService = ConnectPsEwsBA

CallEWSTest $ExService  #Calling any function

1.2.6.Login for EWS with PowerShell and oAuth

Using oAuth from PowerShell is not a trivial or easy endeavor. But because Basic Authentication is being closed for Exchange, it will be obligatory to use in some years.

For this book, we use the GenericOauthEWS.ps1 login routine developed by Glen Scales (glenscales@yahoo.com, https://gsexdev.blogspot.com/), that can be downloaded from his GitHub repository https://github.com/gscales/Powershell-Scripts/blob/master/GenericOauthEWS.ps1. The module is fully described in the article https://gsexdev.blogspot.com/2018/08/dependency-free-generic-ews-oauth.html.

A close up of a logo

Description automatically generated

The EWS DLLs required to work with oAuth and Exchange can be downloaded from https://www.microsoft.com/en-us/download/details.aspx?id=42951. Download the EwsManagedApi.msi file from that site and install it locally. The DLLs will be installed in the local directory C:\Program Files\Microsoft\Exchange\Web Services\2.2\.

To use the module, first, load it in the script and then call the Connect-Exchange method. Use the return value to get any access to the required information.

01.007

ID

File

Routines

PS Modules

GenericOauthEWS.ps1

Other Modules

Microsoft.Exchange.WebServices.dll

##==> EWS oAuth Authorization
Import-Module .\GenericOauthEWS.ps1 -Force
#Test-EWSConnection -MailboxName $configFile.appsettings.exUserName
$ExService = Connect-Exchange `
				$configFile.appsettings.exUserName "" $configFile.appsettings.exAppId

CallEWSTest $ExService  #Calling any function

The module has a Test-EWSConnection method that can be used to check the connection with Exchange and get some information about the account.

1.2.7.Login using the Exchange Online PowerShell

To work with Exchange Online PowerShell, use Windows PowerShell on the local computer to create a remote PowerShell session with Exchange Online, providing the Office 365 credentials, the required connection settings, and then import the Exchange Online cmdlets into the local Windows PowerShell session.

The following function automates the complete process.

01.008

ID

File

Routines

PS Modules

GenericOauthEWS.ps1

Other Modules

Microsoft.Exchange.WebServices.dll

Function ConnectPsOnlBA() 
{
	[SecureString]$securePW = ConvertTo-SecureString -String `
				$configFile.appsettings.exUserPw -AsPlainText -Force
	$myCredentials = New-Object System.Management.Automation.PSCredential -ArgumentList `
				$configFile.appsettings.exUserName, $securePW
	$mySession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri `
				https://outlook.office365.com/powershell-liveid/ -Authentication Basic `
				-AllowRedirection -Credential $myCredentials
	Import-PSSession $mySession -AllowClobber
}

To use the remote session, utilize the function as follows.

01.009

ID

File

Routines

PS Modules

GenericOauthEWS.ps1

Other Modules

Microsoft.Exchange.WebServices.dll

##==> Exchange Online PowerShell Basic Authorization
ConnectPsOnlBA

Get-Mailbox  #Calling any cmdlet

$currentSession = Get-PSSession
Remove-PSSession -Session $currentSession

The remote session is killed at the end of the code for security concerns.

A close up of a logo

Description automatically generated

Microsoft has announced that Remote PowerShell for Exchange will be closed on October 13th, 2020 (https://techcommunity.microsoft.com/t5/blogs/ blogarticleprintpage/blog-id/Exchange/article-id/27095). Microsoft recommends using the multi-factor authentication PowerShell module or the PowerShell within Azure Cloud Shell to use PowerShell with Exchange, as the article mentions.

1.3.Programming Exchange with EWS and CSharp

To work with EWS in Visual Studio, the development computer must have the Microsoft.Exchange.WebServices and Microsoft.Exchange.WebServices.Auth DLLs installed.

A close up of a logo

Description automatically generated

The EWS DLLs can be installed by the NuGet Microsoft.Exchange.WebServices by Microsoft (https://www.nuget.org/packages/Microsoft. Exchange.WebServices/) directly from Visual Studio.

toc