Using msal4j trying to send email (SMTP with OAUTH2) fails
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)
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?
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 EntraEnabled 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 followsDEBUG: Jakarta Mail version 2.1.3DEBUG SMTP: useEhlo true, useAuth trueDEBUG SMTP: trying to connect to host “smtp.office365.com”, port 587, isSSL false220 GV3PEPF00002E53.outlook.office365.com Microsoft ESMTP MAIL Service ready at Tue, 9 Jul 2024 18:27:03 +0000DEBUG SMTP: connected to host “smtp.office365.com”, port: 587EHLO —hidden—250-GV3PEPF00002E53.outlook.office365.com Hello [94.255.242.89]250-SIZE 157286400250-PIPELINING250-DSN250-ENHANCEDSTATUSCODES250-STARTTLS250-8BITMIME250-BINARYMIME250-CHUNKING250 SMTPUTF8DEBUG 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 “”STARTTLS220 2.0.0 SMTP server readyEHLO —hidden—250-GV3PEPF00002E53.outlook.office365.com Hello [—ip hidden—]250-SIZE 157286400250-PIPELINING250-DSN250-ENHANCEDSTATUSCODES250-AUTH LOGIN XOAUTH2250-8BITMIME250-BINARYMIME250-CHUNKING250 SMTPUTF8DEBUG 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: XOAUTH2DEBUG SMTP: Using mechanism XOAUTH2AUTH 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) 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? Read More