email sending over office365 (smtp-mail.outlook.com) with oauth client_credentials_flow not working

Giuseppe Clinaz 0 Reputation points
2024-12-13T07:59:03.0766667+00:00

Hello,

I have set up an Azure App Registration to send emails using Microsoft services via the client_credentials flow. I am utilizing the email-oauth-proxy (https://github.com/simonrob/email-oauth2-proxy) application for this purpose.

Working Workflow with Microsoft Graph API:

I request a token using the following command

curl -X POST "https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$SECRET&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default"

With the obtained token, I can successfully send an email using the Microsoft Graph API:

curl -v -X POST "https://graph.microsoft.com/v1.0/users/$SENDER_EMAIL/sendMail" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": {
"subject": "Subject of the email",
"body": {
"contentType": "Text",
"content": "This is the content of the email."
},
"toRecipients": [
{
"emailAddress": {
"address": "$RCPT_EMAIL"
}
}
]
}
}'

This approach works perfectly.


Problem with SMTP and Scope https://outlook.office365.com/.default:

However, when I use the scope https://outlook.office365.com/.default to send emails via SMTP (smtp-mail.outlook.com), authentication fails. The server and configuration used are as follows:

  • Server Address: smtp-mail.outlook.com
  • Authentication: OAuth 2.0 with the token obtained via client_credentials
  • Port: 587 (STARTTLS)

Despite correct credentials and using the same Azure App Registration, I receive the following error when attempting to send emails:

535 5.7.139 Authentication unsuccessful, the request did not meet the criteria to be authenticated successfully.

I have also followed these steps using PowerShell:

  1. Created a new service principal:
       
       New-ServicePrincipal -AppId "APP_ID" -ServiceId "OBJECT_ID"
    
  2. Updated the service principal with a display name:
       
       Set-ServicePrincipal -Identity "OBJECT_ID" -DisplayName "email-oauth-proxy"
    
  3. Granted the service principal full access to the mailbox:
       
       Add-MailboxPermission -Identity "SENDER_EMAIL" -User "OBJECT_ID" -AccessRights FullAccess
    

Despite these steps, the issue with SMTP authentication persists.

Questions:

  1. Is sending emails via SMTP using a token from the client_credentials flow and the scope https://outlook.office365.com/.default supported at all?
  2. If yes, are there specific configurations or permissions that need to be enabled in the Azure App Registration or the user account (SENDER_EMAIL)?
  3. What steps should I take to resolve this issue?
  4. The default security policy (recommended) is activated. Can this be an issue?

Thank you for your assistance! I look forward to your response.

Microsoft Exchange Online
Outlook
Outlook
A family of Microsoft email and calendar products.
4,218 questions
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
22,644 questions
{count} votes

1 answer

Sort by: Most helpful
  1. FrankEscarosBuechsel-MSFT 575 Reputation points Microsoft Employee
    2024-12-13T22:19:16.3466667+00:00

    Hi @Giuseppe Clinaz • Thank you for reaching out.

    It looks like you are trying to use OAUTH2 with a client credentials flow to utilize SMTP to send emails. I have replicated your described setup in my environment and it looks like you are indeed following the correct guide.

    As to your questions:

    1. Yes, the document you are referencing actually states at the very bottom that this is required when requesting the access token.
    2. The necessary configuration for the most part is described in the guide you are following, I will give you some additional pointers below as well, that are a bit more hidden across other documents or portals.
    3. The general troubleshooting steps are outlined in the following Learn Article: Error: Authentication unsuccessful, in your particular case I will walk you through some more steps to validate as well below, as it looks like a configuration issue indeed.
    4. As per 3, yes this can cause problems. I had it disabled throughout my testing, enabled it right now and revoked the refresh tokens for the user, it's still working for now, however I would stick on the side of caution here and follow the guidance, for your use case some enforced parameters for the users like mandatory Multifactor Authentication after 14 days of enablement will not be compatible with the use case you are trying to achieve. If you are in a position to utilize Conditional Access policies from a licensing perspective of your tenant then that would be my recommendation. The following Learn Article also has more background Authenticate your device or application directly with a Microsoft 365 or Office 365 mailbox, and send mail using SMTP AUTH client submission

    With IMAP working you are really mostly interested in the marked output, as that is your pre-formatted combined username and bearer token string which is required to authenticate for SMTP as well.

    User's image

    You may have your own method of creating that, however, even a wrong escape character can render the token invalid for a successful login.

    In Office365 Admin Center or via PowerShell you have to ensure that the mailbox does allow SMTP authentication (this is not enabled by default). This should read false when using PowerShell.

    Get-CASMailbox -Identity <EmailAddress> | Format-List SmtpClientAuthenticationDisabled
    

    In the UI the Manage Email apps link will allow you to set the checkbox.

    User's image

    Your API permissions look alright to me, you can probably restrict them actually, below you can find the setup which I tested with, your screenshot is not showing it but I am assuming that you did indeed give the necessary admin consent for the Office365 permission set.

    User's image

    Next is registering the Service Principal in Exchange Online, you followed the steps, there is however one pitfall possible.

    Set-ServicePrincipal -Identity "OBJECT_ID" -DisplayName "email-oauth-proxy"
    

    There is 2 possible object IDs, however only one will work.

    The OBJECT_ID is the Object ID from the Overview page of the Enterprise Application node (Azure Portal) for the application registration. It is not the Object ID from the Overview page of the App Registrations node. Using the incorrect Object ID will cause an authentication failure.

    I recommend using the PowerShell snippet from the guide to make sure the correct IDs are being used.

    
    $AADServicePrincipalDetails = Get-AzureADServicePrincipal -SearchString YourAppName
    
    New-ServicePrincipal -AppId $AADServicePrincipalDetails.AppId -ObjectId $AADServicePrincipalDetails.ObjectId -DisplayName "EXO Serviceprincipal for EntraAD App $($AADServicePrincipalDetails.Displayname)"
    
    $EXOServicePrincipal = Get-ServicePrincipal -Identity "EXO Serviceprincipal for EntraAD App YourAppName"
    
    Add-MailboxPermission -Identity "<EmailAddress>" -User $EXOServicePrincipal.Identity -AccessRights FullAccess
    

    The last step is to confirm everything works with the token created from the PowerShell script I outlined earlier ideally.

    Once you are connected via telnet you will have to follow a 2 step process as per SMTP protocol. Send a helo with your own IP to the server.
    Send the auth xoauth2 generatedtokenstring.

    You can see this in the picture below.

    User's image

    There unfortunately is a lot of steps to follow for this to be successful, and I tripped up a couple of times myself during the reproduction here, so I am sure that either the Security Defaults disabling or going over the OBJECTID in the Service Principal will resolve your issue, the other steps which you performed look correct to me.


    Please "Accept the answer" if the information helped you. This will help us and others in the community as well.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.