This tutorial demonstrates using OAuth 2.0 with IMAP/POP3/SMTP for Office 365 (Client Credentials flow where the end user is not required to give consent to your app's accessing their email).
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.
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 and, lately, Authenticate an IMAP, POP or SMTP connection using OAuth article. However, should you encounter any issues with it, we recommend contacting Office 365 techsupport directly as we cannot assist there.
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.
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; using MailBee.SmtpMail; ... // 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(); // SMTP e-mail send Smtp mailer = new Smtp(); SmtpServer smtpServ = new SmtpServer("smtp.office365.com", 587, 0); smtpServ.AccountName = null; smtpServ.Password = xOAuthKey; smtpServ.AuthMethods = AuthenticationMethods.SaslOAuth2; mailer.SmtpServers.Add(smtpServ); mailer.From.Email = userEmail; mailer.To.Add(userEmail); mailer.Subject = "Email to myself"; await mailer.SendAsync();
' Add to the top of your code file (if not already present) Imports Microsoft.Identity.Client Imports MailBee Imports MailBee.Pop3Mail Imports MailBee.ImapMail Imports MailBee.SmtpMail ... ' 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() ' SMTP e-mail send Dim mailer As Smtp = New Smtp() Dim smtpServ As SmtpServer = New SmtpServer("smtp.office365.com", 587, 0) smtpServ.AccountName = Nothing smtpServ.Password = xOAuthKey smtpServ.AuthMethods = AuthenticationMethods.SaslOAuth2 mailer.SmtpServers.Add(smtpServ) mailer.From.Email = userEmail mailer.To.Add(userEmail) mailer.Subject = "Email to myself" Await mailer.SendAsync()
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.
Copyright © 2006-2023 AfterLogic Corporation. All rights reserved.