I have followed this guide on how to use client credentials grant flow to authenticate IMAP.
The app registration has the following permissions:
I have successfully given my application's service principal access to the mailbox I wish to read:
Add-MailboxPermission -Identity "john.smith@contoso.com" -User <SERVICE_PRINCIPAL_ID> -AccessRights FullAccess
And the application's service principal has SendAs rights to the mailbox used.
Add-RecipientPermission -Identity "john.smith@contoso.com" -Trustee <SERVICE_PRINCIPAL_ID> -AccessRights SendAs
https://serverfault.com/a/1110785
The obtained access token looks good with roles matching what I want to do:
I have used both Microsoft.Identity.Client and System.Net.Http.HttpClient to get a token successfully and I have used MailKit.Net.Smtp.SmtpClient to send emails. I can get access to the mailbox via IMAP using MailKit.Net.Imap.ImapClient. See this question:
IMAP and SMTP settings from:
The guide does say:
Note As per the current test with SMTP Oauth 2.0 client credential flow with non-interactive sign in is not supported.
What I can't understand is why they then have a Office 365 Exchange Online Application permission called Mail.Send that Allows the app to send mail as any user without a signed-in user. Application permissions states that they should be used when Your application runs as a background service or daemon without a signed-in user.
Similar question:
Office 365 XOAUTH2 for SMTP on native clients 535 5.7.3 Authentication unsuccessful
Using Mail.Send with Delegated permissions I can send an email using SMTP with the mailbox I wish to send as. Code example for that:
https://stackoverflow.com/a/73728638/3850405
Code:
    var clientId = "";
    var tenantId = "";
    var clientSecret = "";
    //I have also tried with var outlookDomain = "smtp.office365.com";
    var outlookDomain = "outlook.office365.com";
    var email = "info@example.com";
    var app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithClientSecret(clientSecret)
    .Build();
    string[] scopes = new string[] {
    "https://outlook.office365.com/.default"
    };
    var result = await app.AcquireTokenForClient(scopes)
    .ExecuteAsync();
    string accessToken = result.AccessToken;
    var oauth2Test = new SaslMechanismOAuth2(email, accessToken);
    var client = new ImapClient();
    await client.ConnectAsync(outlookDomain, 993, SecureSocketOptions.Auto, cancellationToken);
    await client.AuthenticateAsync(oauth2Test);
    await client.DisconnectAsync(true);
    var message = new MimeMessage();
    message.From.Add(MailboxAddress.Parse(_settings.UserName));
    message.To.Add(MailboxAddress.Parse("info2@example.com"));
    message.Subject = "Test";
    message.Body = new TextPart("plain") { Text = @"Oscar Testar" };
    using (var smtpClient = new SmtpClient())
    {
        await smtpClient.ConnectAsync("smtp.office365.com", 587, SecureSocketOptions.StartTls, cancellationToken);
        if (smtpClient.AuthenticationMechanisms.Contains("OAUTHBEARER") || smtpClient.AuthenticationMechanisms.Contains("XOAUTH2"))
        {
            //Exception here:
            await smtpClient.AuthenticateAsync(oauth2Test);
        }
        await smtpClient.SendAsync(message, cancellationToken);
        await smtpClient.DisconnectAsync(true, cancellationToken);
    }
MailKit.Security.AuthenticationException: '535: 5.7.3 Authentication unsuccessful [AB1C230CA0059.SWEP280.PROD.OUTLOOK.COM]'
If I try with outlookDomain set to smtp.office365.com and scopes set to https://smtp.office365.com/.default I get the following exception:
Microsoft.Identity.Client.MsalServiceException: 'AADSTS500011: The resource principal named https://smtp.office365.com was not found in the tenant named <NAME>. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.





