Modern Oauth2 authentication for sending mails using Nodemailer nodejs

I am using nodemailer to send email in my nodejs application.

var payload = { auth: 
               {
                user: smtpuser,
                pass: smtppass
               },
                to : toAddr,
                from  : emailfrom,
                cc : ccAddr,
                subject : subject,
                html    : content,
                attachments: attachments
              };

var transporter = nodemailer.createTransport(
                   { host: payload.host || 'smtp.office365.com', // Office 365 server
                     port: payload.port || 587,     // secure SMTP
                     secure:payload.secure || false, // false for TLS - as a boolean not string - but the default is false so just remove this completely
                     auth: payload.auth,
                     debug: true,
                     tls: payload.tls || {ciphers: 'SSLv3'}
                   });

transporter.sendMail(payload, function (error, info) {
                if (error) {
                    return console.log(error);
                }
                updateMessage(updatedMsg);
            });

I started getting this error:

Error: Invalid log in: 535 5.7.3 Authentication unsuccessful [SN4PR0601CA0002.namprd06.prod.outlook.com]

It seems my team has now disabled basic authentication.

I need to implement modern authentication(Oauth2) to be able to send mails via nodemailer using the outlook id.

Does anyone have any idea about this?
What configuration(code) changes will that require ?

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

After long time discovering how to send an email from your server with OAuth2, I end up with this working example.

  1. Create an app https://go.microsoft.com/fwlink/?linkid=2083908
  2. Add permissions in {Your APP admin panel} > API permissions > Add permission > Microsoft Graph > Application permissions > Mail.Send > Add permissions
  3. Create certificate to get client secret {Your APP admin panel} > Certificates & secrets > Client secrets > New client secret (Save the "Value" string somewhere this is your client_secret)
  4. Make sure you have installed required node apps
  5. Now you can run this code to send any email from your server:
    const msal = require('@azure/msal-node');
    const fetch = require('node-fetch');

    const clientSecret = process.env.CLIENT_SECRET;
    const clientId = process.env.CLIENT_ID;
    const tenantId = process.env.TENANT_ID;
    const aadEndpoint =
      process.env.AAD_ENDPOINT || 'https://login.microsoftonline.com';
    const graphEndpoint =
      process.env.GRAPH_ENDPOINT || 'https://graph.microsoft.com';

    const msalConfig = {
      auth: {
        clientId,
        clientSecret,
        authority: aadEndpoint + '/' + tenantId,
      },
    };

    const tokenRequest = {
      scopes: [graphEndpoint + '/.default'],
    };

    const cca = new msal.ConfidentialClientApplication(msalConfig);
    const tokenInfo = await cca.acquireTokenByClientCredential(tokenRequest);

    const mail = {
      subject: 'Microsoft Graph JavaScript Sample',
      //This "from" is optional if you want to send from group email. For this you need to give permissions in that group to send emails from it.
      from: {
        emailAddress: {
          address: '[email protected]',
        },
      },
      toRecipients: [
        {
          emailAddress: {
            address: '[email protected]',
          },
        },
      ],
      body: {
        content:
          '<h1>MicrosoftGraph JavaScript Sample</h1>This is the email body',
        contentType: 'html',
      },
    };

    const headers = new fetch.Headers();
    const bearer = `Bearer ${tokenInfo.accessToken}`;

    headers.append('Authorization', bearer);
    headers.append('Content-Type', 'application/json');

    const options = {
      method: 'POST',
      headers,
      body: JSON.stringify({ message: mail, saveToSentItems: false }),
    };

    await fetch(
      graphEndpoint + '/v1.0/users/[email protected]/sendMail',
      options
    );

Also take a look here for email setting:

https://docs.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=javascript

May be it will help someone 😉

Solution 2

I’d suggest that you use Microsoft Graph to send emails. There’s an easy to use REST API that works greatly with OAuth.

Please find below some links to help you build this out quickly.

https://docs.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http
https://docs.microsoft.com/en-us/graph/auth/auth-concepts?view=graph-rest-1.0
https://docs.microsoft.com/en-us/graph/tutorials/node?view=graph-rest-1.0

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply