node.jsazureazure-active-directorynodemailer

I cannot send mail using Azure OAuth with Nodemailer


I am trying to change the authentication in my project to OAuth2 because Microsoft has stopped support for Basic authentication. Everything seems normal on the Azure side.

const createEmailTransporter = async () => {

  const accessToken = await getAccessToken();

  return nodemailer.createTransport({
    host: config.EMAIL_HOST,
    port: config.EMAIL_PORT,
    secure: false,
    auth: {
      type: 'OAuth2',
      user: config.EMAIL_ADDRESS,
      clientId: config.EMAIL_CLIENT_ID,
      clientSecret: config.EMAIL_CLIENT_SECRET,
      accessToken: accessToken,

    },
  });
};

Get Token Method:

const getAccessToken = async () => {
  let data = qs.stringify({
    'client_id': config.EMAIL_CLIENT_ID,
    'scope': config.EMAIL_SCOPE,
    'client_secret': config.EMAIL_CLIENT_SECRET,
    'grant_type': config.EMAIL_GRANT_TYPE,
    'password': config.EMAIL_PASSWORD,
  });

  let axiosConfig = {
    method: 'post',
    maxBodyLength: Infinity,
    url: `https://login.microsoftonline.com/${config.EMAIL_TENANT_ID}/oauth2/v2.0/token`,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    data: data
  };

  try {
    const response = await axios.request(axiosConfig);
    return response.data.access_token;

  } catch (error) {
    console.error("❌ Error getting access token:", error.response?.data || error.message);
    throw new Error(`Error getting access token: ${error}`);
  }
};

I can get tokens. There is no problem here.

But, When I request mail sending with this token, I get this error.


  "error": { 
   "code": "500",  
  "message": "EAUTH",  
  "target": "An error has occurred: Invalid login: 535 5.7.3 Authentication unsuccessful [VI1PR04CA0115.eurprd04.prod.outlook.com 2025-02-20T17:01:08.809Z 08DD4FC050A77D92]",    "@Common.numericSeverity": 4  
}}

We work with the company's IT team and things like the scope when buying tokens all seem to be correct.

Where could there be a mistake. I can't get Auth with OAuth.


Solution

  • To send Mail using Microsoft Graph API using client_credentials flow you need to grant Mail.Send application type API permission to the Microsoft Entra ID application.

    Grant Admin consent to Mail.Send application type API permission:

    enter image description here

    For sample I generated access token passing below parameters:

    https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
    
    client_id: ClientID
    client_secret: Secret
    scope: https://graph.microsoft.com/.default
    grant_type: client_credentials
    

    enter image description here

    You can also decode the token in jwt.ms and check Mail.Send permission:

    enter image description here

    You can make use of the access token to send mail using Microsoft Graph query:

    POST https://graph.microsoft.com/v1.0/users/userID/sendMail
    Content-type: application/json
    
    {
      "message": {
        "subject": "Meet for lunch?",
        "body": {
          "contentType": "Text",
          "content": "The new cafeteria is open."
        },
        "toRecipients": [
          {
            "emailAddress": {
              "address": "xxx"
            }
          }
        ],
        "ccRecipients": [
          {
            "emailAddress": {
              "address": "xxxx"
            }
          }
        ]
      },
      "saveToSentItems": "false"
    }
    

    You will get a 202 Accepted response if the request is successful:

    enter image description here

    The error "Access is denied. Check credentials and try again." usually occurs if the access token does not have required permissions to perform the action. Hence make sure to grant Mail.Send application type API permission to the Microsoft Entra ID application.

    enter image description here

    Reference:

    user: sendMail - Microsoft Graph v1.0 | Microsoft