OAuth 2.0 for Office 365 Accounts (non-interactive mode)

This tutorial demonstrates using OAuth 2.0 with IMAP/POP3 for Office 365 (Client Credentials flow where the end user is not required to give consent to your app's accessing their email).

Note that at the time of writing (October 2022) Office 365 still does not support Client Credentials flow for SMTP, so the classic login/password authentication (Basic Auth) is still the recommended option for SMTP. This may change in the future.

See Microsoft accounts - Installed apps or Microsoft accounts - Installed apps running HttpListener versions of this tutorial if you're looking for OAuth 2.0 for Outlook.com or Hotmail.com accounts (not Office 365).

See desktop or ASP.NET Core guide if you're looking for interactive flows where the end user grants consent to your app to access their email.

Introduction

Basically, Client Credentials flow is very simple on the application side but in case of Office 365 requires a lot of efforts to configure a number of things in your Office 365 tenant and app registration. The below is an unofficial guide which seems to work for us. It was adapted from the kind contribution of our customers and our personal experience. However, should you encounter any issues with it, we recommend contacting Office 365 techsupport directly as we cannot assist there.

Register Azure project

Configure Exchange Online

It's now required to set permissions to impersonate user mailboxes in Exchange Online. For that, you to create a Service Principal and assign it to all mailboxes which you want to access. The mailboxes must belong to your tenant/domain.

Get access token - Sample code

Now you can use Microsoft APIs to get the access token and pass it to MailBee.NET to log in the desired mailbox in your Office 365 tenant.

The code will be the same for desktop, console and web applications.

// Add to the top of your code file (if not already present)
using System;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using MailBee;
using MailBee.Pop3Mail;
using MailBee.ImapMail;

...

// Add to an async method
string clientId = "Application (client) ID";
string tenantId = "Directory (tenant) ID";
string clientSecret = "Saved Client Secret";
string userEmail = "mailbox, e.g. mailbox@yourdomain.com";
string[] scopes = { "https://outlook.office365.com/.default" };
IConfidentialClientApplication confidentalApp = ConfidentialClientApplicationBuilder.Create(clientId).WithTenantId(tenantId).WithClientSecret(clientSecret).Build();
AuthenticationResult result = await confidentalApp.AcquireTokenForClient(scopes).ExecuteAsync();
string userName = result.Account?.Username;
string accessToken = result.AccessToken;
string xOAuthKey = OAuth2.GetXOAuthKeyStatic(userEmail, accessToken);

// IMAP login
Imap imap = new Imap();
await imap.ConnectAsync("outlook.office365.com", 993);
await imap.LoginAsync(null, xOAuthKey, AuthenticationMethods.SaslOAuth2, AuthenticationOptions.None, null);
await imap.DisconnectAsync();

// POP3 login
Pop3 pop = new Pop3();
await pop.ConnectAsync("outlook.office365.com", 995);
await pop.LoginAsync(null, xOAuthKey, AuthenticationMethods.SaslOAuth2, AuthenticationOptions.None, null);
await pop.DisconnectAsync();
' Add to the top of your code file (if not already present)
Imports Microsoft.Identity.Client
Imports MailBee
Imports MailBee.Pop3Mail
Imports MailBee.ImapMail

...

' Add to an async method
Dim clientId As String = "Application (client) ID"
Dim tenantId As String = "Directory (tenant) ID"
Dim clientSecret As String = "Saved Client Secret"
Dim userEmail As String = "mailbox, e.g. mailbox@yourdomain.com"
Dim scopes As String() = {"https://outlook.office365.com/.default"}
Dim confidentalApp As IConfidentialClientApplication = ConfidentialClientApplicationBuilder.Create(clientId).WithTenantId(tenantId).WithClientSecret(clientSecret).Build()
Dim result As AuthenticationResult = Await confidentalApp.AcquireTokenForClient(scopes).ExecuteAsync()
Dim userName As String = result.Account?.Username
Dim accessToken As String = result.AccessToken
Dim xOAuthKey As String = OAuth2.GetXOAuthKeyStatic(userEmail, accessToken)

' IMAP login
Dim imap As Imap = New Imap()
Await imap.ConnectAsync("outlook.office365.com", 993)
Await imap.LoginAsync(Nothing, xOAuthKey, AuthenticationMethods.SaslOAuth2, AuthenticationOptions.None, Nothing)
Await imap.DisconnectAsync()

' POP3 login
Dim pop As Pop3 = New Pop3()
Await pop.ConnectAsync("outlook.office365.com", 995)
Await pop.LoginAsync(Nothing, xOAuthKey, AuthenticationMethods.SaslOAuth2, AuthenticationOptions.None, Nothing)
Await pop.DisconnectAsync()

If you're on .NET 4.5 and experiencing TLS 1.0 related error when obtaining the token, upgrade your solution to a newer .NET version. Alternatively, add this at the top of your method which gets the access token:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12

The login procedure should now complete successfully.

You can find the complete sample projects based on this code (.NET 4.5+ compatible, C# and VB.NET) at these locations:

As mentioned above, the code in these console projects can be applied to desktop and ASP.NET Core apps with no changes.


Send feedback to AfterLogic

Copyright © 2006-2022 AfterLogic Corporation. All rights reserved.