OAuth 2.0 password grant with Office365/Exchange IMAP/POP3/SMTP

November 19th, 2020

First you need to 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

Enable additional flows:

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

This image has an empty alt attribute; its file name is image-1.png

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:
https://www.nuget.org/packages/Microsoft.Identity.Client/

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

string userEmail = "Username for mailbox";
string userPassword = "Password for that user";

IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId)
    .WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
    .Build();

var scopes = new string[] 
{
    "offline_access",
    "email",
    "https://outlook.office.com/IMAP.AccessAsUser.All",
    "https://outlook.office.com/POP.AccessAsUser.All",
    "https://outlook.office.com/SMTP.Send",
};

Now acquire the access token and user email address:

var accounts = await app.GetAccountsAsync();

AuthenticationResult result;
if (accounts.Any())
{
    IAccount account = accounts.FirstOrDefault();
    result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();
}
else
{
    SecureString securePassword = new SecureString();
    foreach (char c in userPassword)
    {
        securePassword.AppendChar(c);
    }
    result = await app.AcquireTokenByUsernamePassword(
        scopes, 
        userEmail, 
        securePassword).ExecuteAsync();
}

string user = result.Account.Username;
string accessToken = result.AccessToken;

Finally you can connect to IMAP/POP3/SMTP server and authenticate:

using (Imap client = new Imap())
{
    client.ConnectSSL("outlook.office365.com");
    client.LoginOAUTH2(user, accessToken);
 
    client.SelectInbox();

    // ...

    client.Close();
} 

Aruba.it (@aruba.it, @technet.it) settings

October 27th, 2020

For @custom-domain.ext mailbox format go here:
Aruba.it custom domains IMAP, POP3, SMTP settings

POP3

Server: pop3.aruba.it
SSL: true-implicit
Port: 995 (default)
User :  email address (e.g.: name@aruba.it or name@technet.en)

using (Pop3 client = new Pop3())
{
    client.ConnectSSL("pop3.aruba.it");
    client.UseBestLogin("user@aruba.it", "password");

    // ...

    client.Close();
}
Next step: receive emails using POP3.

IMAP

Server:  imap.aruba.it
SSL: true-implicit
Port: 993 (default)
User: email address (e.g.: name@aruba.it or name@technet.en)

using (Imap client = new Imap())
{
    client.ConnectSSL("imap.aruba.it");
    client.UseBestLogin("user@aruba.it", "password");

    // ...

    client.Close();
}

Next step: receive unseen emails using IMAP.

SMTP

Server:  smtp.aruba.it
SSL: true-implicit
Port:  465 (default)
User: email address (e.g.: name@aruba.it or name@technet.en)

using (Smtp client = new Smtp())
{
    client.ConnectSSL("smtp.aruba.it");
    client.UseBestLogin("user@aruba.it", "password");

    // ...

    client.Close();
}

Aruba.it (@custom-domain.ext) settings

October 27th, 2020

For @aruba.it and @technet.it mailbox formats go here:
@aruba.it and @technet.it IMAP, POP3, SMTP settings

POP3

Server: pop3s.aruba.it
SSL: true-implicit
Port: 995 (default)
User :  email address (e.g.: name@aruba.it or name@technet.en)

using (Pop3 client = new Pop3())
{
    client.ConnectSSL("pop3s.aruba.it");
    client.UseBestLogin("user@custom-domain.ext", "password");

    // ...

    client.Close();
}

Next step: receive emails using POP3.

IMAP

Server:  imaps.aruba.it
SSL: true-implicit
Port: 993 (default)
User: email address (e.g.: name@aruba.it or name@technet.en)

using (Imap client = new Imap())
{
    client.ConnectSSL("imaps.aruba.it");
    client.UseBestLogin("user@custom-domain.ext", "password");

    // ...

    client.Close();
}


Next step: receive unseen using IMAP.

SMTP

Server:  smtps.aruba.it
SSL: true-implicit
Port:  465 (default)
User: email address (e.g.: name@aruba.it or name@technet.en)

using (Smtp client = new Smtp())
{
    client.ConnectSSL("smtps.aruba.it");
    client.UseBestLogin("user@custom-domain.ext", "password");

    // ...

    client.Close();
}


OAuth 2.0 with Office365/Exchange IMAP/POP3/SMTP

June 23rd, 2020

First you need to 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

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

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:

https://www.nuget.org/packages/Microsoft.Identity.Client/

var pcaOptions = new PublicClientApplicationOptions
{
    ClientId = "Application (client) ID",
    TenantId = "Directory (tenant) ID",
    RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
    // RedirectUri = "http://localhost" // .net core
};

var pca = PublicClientApplicationBuilder
    .CreateWithApplicationOptions(pcaOptions)
    .Build();

var scopes = new string[] 
{
    "offline_access",
    "email",
    "https://outlook.office.com/IMAP.AccessAsUser.All",
    "https://outlook.office.com/POP.AccessAsUser.All",
    "https://outlook.office.com/SMTP.Send",
};

In addition, you can request for 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:

var authResult = pca.AcquireTokenInteractive(scopes).ExecuteAsync().Result;

string user = authResult.Account.Username;
string accessToken = authResult.AccessToken;

Finally you can connect to IMAP/POP3/SMTP server and authenticate:

using (Imap client = new Imap())
{
    client.ConnectSSL("outlook.office365.com");
    client.LoginOAUTH2(user, accessToken);
 
    client.SelectInbox();

    // ...

    client.Close();
} 

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

https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth

https://stackoverflow.com/questions/29747477/imap-auth-in-office-365-using-oauth2

https://stackoverflow.com/questions/43473858/connect-to-outlook-office-365-imap-using-oauth2

https://stackoverflow.com/questions/61597263/office-365-xoauth2-for-imap-and-smtp-authentication-fails

NavigateToTest VS2019 extension

March 19th, 2020

Extension is available for other Visual Studio versions:

You can download the extension here:
NavigateToTest Visual Studio 2019 extension

Here’s the latest version that supports Visual Studio 2019.

Extension is convention based. It matches ClassName file with ClassNameTest or ClassNameTests and vice-versa, so you can easily navigate to the test file and back.

Here are some screenshots:

Here’s the toolbar name, in case it is not added automatically:

You can download the extension here:
NavigateToTest Visual Studio 2019 extension