OAuth 2.0 web flow with Office365/Exchange IMAP/POP3/SMTP

This article shows how to implement OAuth 2.0 web 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:


Add an authentication redirect uri to your application:

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.

Create an app secret and remember its value:

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";
string clientSecret = "Client secret value";

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

var app = ConfidentialClientApplicationBuilder
// 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 try finding account by identifier (it will be null on first access) in MSAL cache:

string userName;
string accessToken;

string identifier = null;

var account = await app.GetAccountAsync(identifier);

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

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

catch (MsalUiRequiredException e)
    // no token cache entry - perform authentication:

    Uri uri = await app

    // Add redirect code to the above 
    // Microsoft authentication uri and end this request.

After successful authentication Microsoft will redirect user’s browser back to your application – to the app’s RedirectUri (in our case http://localhost/MyApp/):


Controller responsible for handling this request should retrieve code parameter

string code = "get from url after redirect";

AuthenticationResult result = await app
    .AcquireTokenByAuthorizationCode(scopes, code)

string identifier = result.Account.HomeAccountId.Identifier;
string userName = result.Account.Username;
string 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;


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.