OAuth 2.0 client credential flow with Office365/Exchange IMAP/POP3/SMTP
- OAuth 2.0 with Office365/Exchange IMAP/POP3/SMTP
- OAuth 2.0 web flow with Office365/Exchange IMAP/POP3/SMTP
- OAuth 2.0 password grant with Office365/Exchange IMAP/POP3/SMTP
- OAuth 2.0 device flow with Office365/Exchange IMAP/POP3/SMTP
- OAuth 2.0 client credential flow with Office365/Exchange IMAP/POP3/SMTP
This article shows how to implement OAuth 2.0 client credential flow to access Office365 via IMAP, POP3 using Mail.dll .net email client. This flow is particularly useful for daemon/service apps that need to monitor certain mailboxes, without any user interaction.
Make sure IMAP/POP3 is enabled for your organization and mailbox:
Enable IMAP/POP3/SMTP in Office 365
Register your application in Azure Portal, here’s a detailed guide how to do that:
https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
Add permissions to your application in the API permissions / Add a permission wizard:
Select APIs my organization uses and search for “Office 365 Exchange Online“:
…then click Application permissions:
For POP access, choose the POP.AccessAsApp permission.
For IMAP access, choose the IMAP.AccessAsApp permission.
For SMTP access, choose the SMTP.SendAsApp permission.
Remember to Grant admin consent:
Create an application secret in Certificates & secrets panel by clicking ‘New client secret’ button:
Note the secret value as it is shown only during creation.
Use Windows PowerShell on your machine to Register service principals in Exchange.
Set execution policy first:
Set-ExecutionPolicy RemoteSigned
Install ExchangeOnlineManagement module:
Install-Module -Name ExchangeOnlineManagement
Import-Module ExchangeOnlineManagement
Connect and log-in as an administrator (you’ll be prompted for password):
Connect-ExchangeOnline
-UserPrincipalName your-admin-account@your-domain.onmicrosoft.com
For Exchange running in hybrid mode log-in using following code:
$lc = Get-Credential
Connect-ExchangeOnline -Credential $lc
Create service principal
New-ServicePrincipal
-AppId <APPLICATION_ID>
-ServiceId <OBJECT_ID>
[-Organization <ORGANIZATION_ID>]
You can find ApplicationId and ObjectId in Enterprise applications in your application’s Overview panel:
Make sure you use the Object ID from the Enterprise Application.
Do not use the value from the App Registration screen.
In our case:
New-ServicePrincipal
-AppId 061851f7-08c0-40bf-99c1-ebd489c11f16
-ServiceId 4352fc11-5c2f-4b0b-af40-447ff10664e8
Note: If you still get an error running the New-ServicePrincipal cmdlet after you perform these steps, it is likely due to the fact that the user doesn’t have enough permissions in Exchange online to perform the operation. By default this cmdlet is available to users assigned the Role Management role
Add permissions to a specific mailbox:
Add-MailboxPermission
-Identity "<USER@your-domain.onmicrosoft.com>"
-User <OBJECT_ID>
-AccessRights FullAccess
In our case:
Add-MailboxPermission
-Identity "AdeleV@your-domain.onmicrosoft.com"
-User 4352fc11-5c2f-4b0b-af40-447ff10664e8
-AccessRights FullAccess
Shared mailboxes
You need to use Add-MailboxPermission for every shared mailbox you need access to:
Add-MailboxPermission
-Identity "shared@your-domain.onmicrosoft.com"
-User <OBJECT_ID>
-AccessRights FullAccess
Let’s code
Use Microsoft Authentication Library for .NET (MSAL.NET) nuget package to obtain an access token:
https://www.nuget.org/packages/Microsoft.Identity.Client/
// C#
string clientId = "Application (client) ID"; // 061851f7-...
string tenantId = "Directory (tenant) ID";
string clientSecret = "Client secret value";
string userName = "Username/email for mailbox"; // AdeleV@...
var app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret)
.Build();
string[] scopes = new string[] {
"https://outlook.office365.com/.default"
};
' VB.NET
Dim clientId As String = "Application (client) ID" ' 061851f7-...
Dim tenantId As String = "Directory (tenant) ID"
Dim clientSecret As String = "Client secret value"
Dim userName As String = "Username/email for mailbox" 'AdeleV@...
Dim app = ConfidentialClientApplicationBuilder.Create(clientId) _
.WithTenantId(tenantId) _
.WithClientSecret(clientSecret) _
.Build()
Dim scopes As String() = New String() { _
"https://outlook.office365.com/.default" _
}
Now acquire an access token:
// C#
var result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
string accessToken = result.AccessToken;
' VB.NET
Dim result = Await app.AcquireTokenForClient(scopes).ExecuteAsync()
Dim accessToken As String = result.AccessToken
Finally you can connect using IMAP/POP3, authenticate and download user’s emails:
// C#
using (Imap client = new Imap())
{
client.ConnectSSL("outlook.office365.com");
client.LoginOAUTH2(userName, accessToken);
client.SelectInbox();
List<long> uids = imap.Search(Flag.Unseen);
foreach (long uid in uids)
{
IMail email = new MailBuilder()
.CreateFromEml(imap.GetMessageByUID(uid));
string subject = email.Subject;
}
client.Close();
}
' VB.NET
Using client As Imap = New Imap()
client.ConnectSSL("outlook.office365.com")
client.LoginOAUTH2(userName, accessToken)
client.SelectInbox()
Dim uids As List(Of Long) = imap.Search(Flag.Unseen)
For Each uid As Long In uids
Dim email As IMail = New MailBuilder() _
.CreateFromEml(imap.GetMessageByUID(uid))
Dim subject As String = email.Subject
Next
client.Close()
End Using
SMTP
Microsoft started supporting client credential flow and SMTP recently.
SMTP requires SMTP.SendAsApp permission added to your AD application.
All other OAuth flows (web, desktop, password grant, device) support SMTP client access as well.
For SMTP non-OAuth2 access:
“SMTP AUTH will still be available when Basic authentication is permanently disabled on October 1, 2022.” (https://docs.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online)
However Microsoft disables SMTP AUTH in all tenants in which it’s not being used.
Here’s how to enable SMTP AUTH:
https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/authenticated-client-smtp-submission
Troubleshooting
1. Start with PowerShell commands:
Get-ServicePrincipal
Get-MailboxPermission -Identity "AdeleV@your-domain.onmicrosoft.com"
You should see following results:
Make sure the ServiceId is the same as the Object ID on the Enterprise Application screen (do not use the value from the App Registration screen)
Make sure the AppId is the same as the Application ID on the Enterprise Application screen
2. Check if you can connect to this account using IMAP and regular interactive flow:
https://www.limilabs.com/blog/office-365-oauth-2-0-imap-pop3-email-client-connectivity-tools
This proves you have IMAP access properly configured.
3. Check if you added correct permissions and have granted Admin consent for your domain.
4. Usually people use incorrect client/tenant ids/secrets – double check every single value you enter (also for additional spaces).
5. You may need to wait 20-30 minutes for some changes to take effect (it really may take this long!).
Additional links
https://docs.microsoft.com/en-us/powershell/exchange/exchange-online-powershell-v2?view=exchange-ps#install-and-maintain-the-exo-v2-module
https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#use-client-credentials-grant-flow-to-authenticate-imap-and-pop-connections
Get Mail.dll