0

I have followed this guide on how to use client credentials grant flow to authenticate IMAP.

https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#use-client-credentials-grant-flow-to-authenticate-imap-and-pop-connections

The app registration has the following permissions:

enter image description here

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

enter image description here

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

https://learn.microsoft.com/en-us/exchange/recipients/mailbox-permissions?view=exchserver-2019&viewFallbackFrom=exchonline-ww

enter image description here

The obtained access token looks good with roles matching what I want to do:

enter image description here

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:

Azure AD Service Principal client credentials grant AUTHENTICATE failed accessing outlook.office365.com mailbox via IMAP

IMAP and SMTP settings from:

https://support.microsoft.com/en-us/office/pop-imap-and-smtp-settings-8361e398-8af4-4e97-b147-6c6c4ac95353

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.

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

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.

enter image description here

enter image description here

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.

Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • If I understand correctly you are trying to send e-mail from an application directly using an oauth-client, without using an actual user/mailbox-account? I was trying to do the same. From my understanding this is not possible. You are always required to start an interactive login and use the token subsequently generated for the user and not the client. [....non-interactive sign in is not supported.](https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#smtp-protocol-exchange) – Philippe Oct 21 '22 at 13:45
  • The background service approach seems to be supported by [grap-api](https://learn.microsoft.com/en-us/graph/outlook-send-mime-message), for which the client permission are used. As far as I understand. SMTP does not seem to be an option, see also https://github.com/jstedfast/MailKit/issues/1383#issuecomment-1141319806 and https://github.com/jstedfast/MailKit/issues/1126 – Philippe Oct 21 '22 at 13:51

0 Answers0