- Registering Your Application with Microsoft
- Configuring the Correct API Permissions for Your Application
- Desktop and Mobile Applications
- Web Services
- Additional Resources
Whether you are writing a Desktop, Mobile or Web Service application, the first thing you'll need to do is register your application with Microsoft's Identity Platform. To do this, go to Microsoft's Quickstart guide and follow the instructions.
There are several different API permissions that you may want to configure depending on which protocols your application intends to use.
Follow the instructions for adding the POP, IMAP, and/or SMTP permissions to your Entra AD application.
Now that you have the Client ID and Tenant ID strings, you'll need to plug those values into your application.
The following sample code uses the Microsoft.Identity.Client nuget package for obtaining the access token which will be needed by MailKit to pass on to the Exchange server.
static async Task<AuthenticationResult> GetPublicClientOAuth2CredentialsAsync (string protocol, string emailAddress, CancellationToken cancellationToken = default)
{
var options = new PublicClientApplicationOptions {
ClientId = "Application (client) ID",
TenantId = "Directory (tenant) ID",
// Use "https://login.microsoftonline.com/common/oauth2/nativeclient" for apps using
// embedded browsers or "http://localhost" for apps that use system browsers.
RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
};
var publicClientApplication = PublicClientApplicationBuilder
.CreateWithApplicationOptions (options)
.Build ();
string[] scopes;
if (protocol.Equals ("IMAP", StringComparison.OrdinalIgnoreCase)) {
scopes = new string[] {
"email",
"offline_access",
"https://outlook.office.com/IMAP.AccessAsUser.All"
};
} else if (protocol.Equals ("POP", StringComparison.OrdinalIgnoreCase)) {
scopes = new string[] {
"email",
"offline_access",
"https://outlook.office.com/POP.AccessAsUser.All"
};
} else {
scopes = new string[] {
"email",
"offline_access",
"https://outlook.office.com/SMTP.Send"
};
}
try {
// First, check the cache for an auth token.
return await publicClientApplication.AcquireTokenSilent (scopes, emailAddress).ExecuteAsync (cancellationToken);
} catch (MsalUiRequiredException) {
// If that fails, then try getting an auth token interactively.
return await publicClientApplication.AcquireTokenInteractive (scopes).WithLoginHint (emailAddress).ExecuteAsync (cancellationToken);
}
}
var result = await GetPublicClientOAuth2CredentialsAsync ("IMAP", "[email protected]");
// Note: We always use result.Account.Username instead of `Username` because the user may have selected an alternative account.
var oauth2 = new SaslMechanismOAuth2 (result.Account.Username, result.AccessToken);
using (var client = new ImapClient ()) {
await client.ConnectAsync ("outlook.office365.com", 993, SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}
var result = await GetPublicClientOAuth2CredentialsAsync ("SMTP", "[email protected]");
// Note: We always use result.Account.Username instead of `Username` because the user may have selected an alternative account.
var oauth2 = new SaslMechanismOAuth2 (result.Account.Username, result.AccessToken);
using (var client = new SmtpClient ()) {
await client.ConnectAsync ("smtp.office365.com", 587, SecureSocketOptions.StartTls);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}
Note: Once you've acquired an auth token using the interactive method above, you can avoid prompting the user
if you cache the result.Account
information and then silently reacquire auth tokens in the future using
the following code:
var result = await publicClientApplication.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken);
Note: for information on caching tokens, see Microsoft's documentation about how to implement a cross-platform token cache.
Once your web service has been registered, the tenant admin will need to register your service principal.
To use the New-ServicePrincipal cmdlet, open an Azure Powershell terminal and install ExchangeOnlineManagement and connect to your tenant as shown below:
Install-Module -Name ExchangeOnlineManagement -allowprerelease
Import-module ExchangeOnlineManagement
Connect-ExchangeOnline -Organization <tenantId>
Next, register the Service Principal for your web service:
New-ServicePrincipal -AppId <APPLICATION_ID> -ObjectId <OBJECT_ID> [-Organization <ORGANIZATION_ID>]
In order to grant permissions for your web service to access an Office365 and/or Exchange account, you'll need to first get the Service Principal ID registered in the previous step using the following command:
Get-ServicePrincipal | fl
Once you have the Service Principal ID for your web service, use the following command to add full mailbox permissions for the email account that your web service will be accessing:
Add-MailboxPermission -Identity "[email protected]" -User
<SERVICE_PRINCIPAL_ID> -AccessRights FullAccess
Now that you have the Client ID and Tenant ID strings, you'll need to plug those values into your application.
The following sample code uses the Microsoft.Identity.Client nuget package for obtaining the access token which will be needed by MailKit to pass on to the Exchange server.
static async Task<AuthenticationResult> GetConfidentialClientOAuth2CredentialsAsync (string protocol, CancellationToken cancellationToken = default)
{
var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create (clientId)
.WithAuthority ($"https://login.microsoftonline.com/{tenantId}/v2.0")
.WithCertificate (certificate) // or .WithClientSecret (clientSecret)
.Build ();
string[] scopes;
if (protocol.Equals ("SMTP", StringComparison.OrdinalIgnoreCase)) {
scopes = new string[] {
// For SMTP, use the following scope
"https://outlook.office365.com/.default"
};
} else {
scopes = new string[] {
// For IMAP and POP3, use the following scope
"https://ps.outlook.com/.default"
};
}
return await confidentialClientApplication.AcquireTokenForClient (scopes).ExecuteAsync (cancellationToken);
}
var result = await GetConfidentialClientOAuth2CredentialsAsync ("IMAP");
var oauth2 = new SaslMechanismOAuth2 ("[email protected]", result.AccessToken);
using (var client = new ImapClient ()) {
await client.ConnectAsync ("outlook.office365.com", 993, SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}
var result = await GetConfidentialClientOAuth2CredentialsAsync ("SMTP");
var oauth2 = new SaslMechanismOAuth2 ("[email protected]", result.AccessToken);
using (var client = new SmtpClient ()) {
await client.ConnectAsync ("smtp.office365.com", 587, SecureSocketOptions.StartTls);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}
For more information, check out the Microsoft.Identity.Client documentation.