OAuth 2.0 with Office365/Exchange IMAP/POP3/SMTP

This article shows how to implement OAuth 2.0 desktop flow to access Office365 via IMAP, POP3 or SMTP using Mail.dll .net email client.

Make sure IMAP/POP3/SMTP 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:

Remember to add authentication entries (localhost is needed for .net core):


.NET desktop: https://login.microsoftonline.com/common/oauth2/nativeclient
.NET core/.NET 5,6,7+: http://localhost
ASP.NET: your application custom url

Then you need to apply correct API permissions and grant the admin consent for your domain.

In the API permissions / Add a permission wizard, select Microsoft Graph and then Delegated permissions to find the following permission scopes listed:

  • offline_access
  • email
  • IMAP.AccessAsUser.All
  • POP.AccessAsUser.All
  • SMTP.Send

Remember to Grant admin consent..

Use Microsoft Authentication Library for .NET (MSAL.NET) nuget package to obtain an access token:

string clientId = "Application (client) ID";
string tenantId = "Directory (tenant) ID";

// for @outlook.com/@hotmail accounts instead of setting .WithTenantId use:
// .WithAuthority(AadAuthorityAudience.PersonalMicrosoftAccount)

var app = PublicClientApplicationBuilder
// This allows saving access/refresh tokens to some storage

var scopes = new string[] 

In addition, you should request offline_access scope. When a user approves the offline_access scope, your app can receive refresh tokens from the Microsoft identity platform token endpoint. Refresh tokens are long-lived. Your app can get new access tokens as older ones expire.

Now acquire the access token and user email address:

string userName;
string accessToken;

var account = (await app.GetAccountsAsync()).FirstOrDefault();

    AuthenticationResult refresh = await app
        .AcquireTokenSilent(scopes, account)

    userName = refresh.Account.Username;
    accessToken = refresh.AccessToken;
catch (MsalUiRequiredException e)
    var result = await app.AcquireTokenInteractive(scopes)

    userName = result.Account.Username;
    accessToken = result.AccessToken;

Finally you can connect using IMAP/POP3/SMTP, authenticate and download user’s emails:

using (Imap client = new Imap())
    client.LoginOAUTH2(userName, accessToken);

    List<long> uids = imap.Search(Flag.Unseen);
    foreach (long uid in uids)
        IMail email = new MailBuilder()
        string subject = email.Subject;


As this is fairly new feature for Exchange/Office365, here are some useful links:





Token serialization

Below is a simple implementation that saves MSAL token cache to file:

static class TokenCacheHelper
    public static void EnableSerialization(ITokenCache tokenCache)

    private static readonly string _fileName = "msalcache.bin3";

    private static readonly object _fileLock = new object();

    private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
        lock (_fileLock)
            byte[] data = null;
            if (File.Exists(_fileName))
                data = File.ReadAllBytes(_fileName);

    private static void AfterAccessNotification(TokenCacheNotificationArgs args)
        if (args.HasStateChanged)
            lock (_fileLock)
                byte[] data = args.TokenCache.SerializeMsalV3();
                File.WriteAllBytes(_fileName, data);

Please note that most likely you should store this cache in an encrypted form in some kind of a database.
Consider using MSAL token serialization implementations available here:




Consider using our Q&A forum for asking any questions.