Using msal4j trying to send email (SMTP with OAUTH2) fails

Copper Contributor

 

I am trying to write a Java server application that should send emails using my account with msal4j.

I have tried to find solutions online but all sources are either pointing to very old solutions and Microsoft seem to propose only using MSAL so I try to do this with OAUTH2 authentication and send with Jakarta.mail.

 

I always end up with the error 535 5.7.3 Authentication unsuccessful (details below). What have I missed?

 

  • Created app in Microsoft Entra

  • Enabled SMTP Auth (admin did this since I am not admin myself on my account)

  • Added application API grant for Mail.Send and admin gave consent (also have added Mail.Send as delegate as a test)

  • In java code I have added the following dependencies

<dependency>

    <groupId>com.microsoft.azure</groupId>

    <artifactId>msal4j</artifactId>

    <version>1.16.0</version>

</dependency>

 

<dependency>

    <groupId>jakarta.mail</groupId>

    <artifactId>jakarta.mail-api</artifactId>

    <version>2.1.3</version>

</dependency>

 

  • In code I start with getting a token (in the code below I have added the silent try since I found that on Microsoft own example code). 

private static String microsoftConnect(String strClientID, String strTenantID, String strClientSecret)

throws MalformedURLException, InterruptedException, ExecutionException {

ConfidentialClientApplication app = ConfidentialClientApplication

.builder(strClientID, ClientCredentialFactory.createFromSecret(strClientSecret))

.authority("https://login.microsoftonline.com/" + strTenantID).build();

Set<String> SCOPE = Collections.singleton("https://graph.microsoft.com/.default");

IAuthenticationResult result;

try {

SilentParameters silentParameters = SilentParameters.builder(SCOPE).build();

// try to acquire token silently. This call will fail since the token cache does

// not

// have a token for the application you are requesting an access token for

result = app.acquireTokenSilently(silentParameters).join();

} catch (Exception ex) {

if (ex.getCause() instanceof MsalException) {

ClientCredentialParameters parameters = ClientCredentialParameters.builder(SCOPE).build();

// Try to acquire a token. If successful, you should see

// the token information printed out to console

result = app.acquireToken(parameters).join();

} else {
// Handle other exceptions accordingly
throw ex;
}
}
String strAccessToken = result.accessToken();
return strAccessToken;
}

 

* The above actually gives me a token and I try to use that in my SMTP send code below (commented can see various attempts but all fails)

private void microsoftSendMessage(String strClientID, String strAccessToken, String strFromEmail, List<String> lstTo,

List<String> lstCC, List<String> lstBCC, String strSubject, String strBody)

throws AddressException, MessagingException {

Properties props = new Properties();

props.put("mail.smtp.auth", "true");

props.put("mail.smtp.starttls.enable", "true");

props.put("mail.smtp.starttls.required", "true");

props.put("mail.smtp.host", "smtp.office365.com");

props.put("mail.smtp.port", "587");

props.put("mail.smtp.auth.mechanisms", "XOAUTH2");

props.put("mail.smtp.auth.login.disable", "true");

props.put("mail.smtp.auth.plain.disable", "true");

props.put("mail.smtp.ssl.trust", "smtp.office365.com");

props.put("mail.smtp.sasl.mechanisms.oauth2.oauthToken", strAccessToken);

props.put("mail.smtp.auth.xoauth2.disable", "false");



props.put("mail.debug.auth", "true");

props.put("mail.debug", "true");

props.put("mail.transport.protocol", "smtp");



Session session = Session.getInstance(props);

Transport transport = session.getTransport("smtp");

// Alternative try, same error

// Session session = Session.getInstance(props, new Authenticator() {

// @Override

// protected PasswordAuthentication getPasswordAuthentication() {

// return new PasswordAuthentication(strFromEmail, strAccessToken);

// }

// });



MimeMessage message = new MimeMessage(session);

message.setFrom(new InternetAddress(strFromEmail));

addRecipient(message, Message.RecipientType.TO, lstTo); // This external code will add all the recipients

addRecipient(message, Message.RecipientType.CC, lstCC);

addRecipient(message, Message.RecipientType.BCC, lstBCC);

message.setSubject(strSubject);

message.setText(strBody);

transport.connect("smtp.office365.com", 587, strFromEmail, strAccessToken);

transport.send(message);

}

 

The SMTP debug is as follows

DEBUG: Jakarta Mail version 2.1.3

DEBUG SMTP: useEhlo true, useAuth true

DEBUG SMTP: trying to connect to host "smtp.office365.com", port 587, isSSL false

220 GV3PEPF00002E53.outlook.office365.com Microsoft ESMTP MAIL Service ready at Tue, 9 Jul 2024 18:27:03 +0000

DEBUG SMTP: connected to host "smtp.office365.com", port: 587

EHLO —hidden—

250-GV3PEPF00002E53.outlook.office365.com Hello [94.255.242.89]

250-SIZE 157286400

250-PIPELINING

250-DSN

250-ENHANCEDSTATUSCODES

250-STARTTLS

250-8BITMIME

250-BINARYMIME

250-CHUNKING

250 SMTPUTF8

DEBUG SMTP: Found extension "SIZE", arg "157286400"

DEBUG SMTP: Found extension "PIPELINING", arg ""

DEBUG SMTP: Found extension "DSN", arg ""

DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""

DEBUG SMTP: Found extension "STARTTLS", arg ""

DEBUG SMTP: Found extension "8BITMIME", arg ""

DEBUG SMTP: Found extension "BINARYMIME", arg ""

DEBUG SMTP: Found extension "CHUNKING", arg ""

DEBUG SMTP: Found extension "SMTPUTF8", arg ""

STARTTLS

220 2.0.0 SMTP server ready

EHLO —hidden—

250-GV3PEPF00002E53.outlook.office365.com Hello [—ip hidden—]

250-SIZE 157286400

250-PIPELINING

250-DSN

250-ENHANCEDSTATUSCODES

250-AUTH LOGIN XOAUTH2

250-8BITMIME

250-BINARYMIME

250-CHUNKING

250 SMTPUTF8

DEBUG SMTP: Found extension "SIZE", arg "157286400"

DEBUG SMTP: Found extension "PIPELINING", arg ""

DEBUG SMTP: Found extension "DSN", arg ""

DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""

DEBUG SMTP: Found extension "AUTH", arg "LOGIN XOAUTH2"

DEBUG SMTP: Found extension "8BITMIME", arg ""

DEBUG SMTP: Found extension "BINARYMIME", arg ""

DEBUG SMTP: Found extension "CHUNKING", arg ""

DEBUG SMTP: Found extension "SMTPUTF8", arg ""

DEBUG SMTP: protocolConnect login, host=smtp.office365.com, user=—email hidden—, password=<non-null>

DEBUG SMTP: Attempt to authenticate using mechanisms: XOAUTH2

DEBUG SMTP: Using mechanism XOAUTH2

AUTH XOAUTH2 —hidden—

535 5.7.3 Authentication unsuccessful [GV3PEPF00002E53.SWEP280.PROD.OUTLOOK.COM 2024-07-09T18:27:09.118Z 08DCA02F0006D0D9]

 

 

Here is a screen shot on the API setup for my app. As far as I understand I need to add the Mail.Send for Application (I have added for delegation just in case but my app will work as a daemon so Application should be the correct approach)

Screenshot 2024-07-09 at 22.40.28 blurred.png

 

Note that this issue seems related to a lot of other (unresolved) issues online. Some are older though using other authroities etc, like this one https://techcommunity.microsoft.com/t5/outlook/outlook-365-smtp-oauth/m-p/3667654#M13669.

 

Is there anyone using msal4j trying to send email via a registered app in Microsoft entra?

0 Replies