'How can I send an e-mail from Microsoft Outlook using MSAL in Java?
I'm trying to develop an application in Java / Spring that connects to an Microsoft Outlook / Exchange SMTP Relay to send e-mails using MSAL4J, but I keep getting an authentication error when I try to connect to the mail server.
Am I doing anything wrong here?
package com.email;
import com.microsoft.aad.msal4j.ClientCredentialFactory;
import com.microsoft.aad.msal4j.ClientCredentialParameters;
import com.microsoft.aad.msal4j.ConfidentialClientApplication;
import com.microsoft.aad.msal4j.IAuthenticationResult;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import java.net.MalformedURLException;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class SmtpTestMSAL {
private static final String clientId = "<removed>";
private static final String tenantId = "<removed>";
private static final String secret = "<removed>";
private static final String to = "<removed>";
private static final String from = "<removed>";
private static final String pwd = "<removed>";
private static final String authUrl = "https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/authorize";
private static final Set<String> scope = Set.of("https://graph.microsoft.com/.default");
public static void main(String[] args) throws MalformedURLException, ExecutionException, InterruptedException {
String token = getAccessToken();
System.out.println("token: " + token);
JavaMailSender mailSender = prepareSender(token);
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setSubject("testing modern auth");
message.setText("testing modern auth");
mailSender.send(message);
}
private static String getAccessToken() throws MalformedURLException, ExecutionException, InterruptedException {
ConfidentialClientApplication app = ConfidentialClientApplication
.builder(
clientId,
ClientCredentialFactory.createFromSecret(secret)
)
.authority(authUrl)
.build();
ClientCredentialParameters clientCredentialParam = ClientCredentialParameters
.builder(scope)
.build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
return future.get().accessToken();
}
private static JavaMailSender prepareSender(String oauthToken) {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
Properties props = mailSender.getJavaMailProperties();
mailSender.setHost("smtp.office365.com");
mailSender.setPort(587);
mailSender.setUsername(from);
mailSender.setPassword(pwd);
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");
props.put("mail.smtp.starttls.required", "true");
props.put("mail.smtp.sasl.enable", "true");
props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
props.put("mail.smtp.sasl.mechanisms.oauth2.oauthToken", oauthToken);
props.put("mail.transport.protocol", "smtp");
return mailSender;
}
}
this is the log of the SMTP session:
DEBUG: Jakarta Mail version 1.6.7
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle]}
DEBUG: Providers Listed By Protocol: {imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: enable SASL
DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to host "smtp.office365.com", port 587, isSSL false
220 <removed>.outlook.office365.com Microsoft ESMTP MAIL Service ready at Fri, 13 May 2022 13:36:12 +0000
DEBUG SMTP: connected to host "smtp.office365.com", port: 587
EHLO pc-364.home
250-<removed>.outlook.office365.com Hello [37.135.92.227]
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 pc-364.home
250-PAZP264CA0194.outlook.office365.com Hello [37.135.92.227]
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=<removed>, password=<non-null>
DEBUG SMTP: Authenticate with SASL
DEBUG SMTP: SASL mechanisms allowed: XOAUTH2
DEBUG SMTP: SASL Mechanisms:
DEBUG SMTP: XOAUTH2
DEBUG SMTP:
DEBUG SMTP: SASL client XOAUTH2
DEBUG SMTP: SASL callback length: 2
DEBUG SMTP: SASL callback 0: javax.security.auth.callback.NameCallback@1188e820
DEBUG SMTP: SASL callback 1: javax.security.auth.callback.PasswordCallback@2f490758
AUTH XOAUTH2 <removed>
535 5.7.3 Authentication unsuccessful [<removed>.OUTLOOK.COM]
DEBUG SMTP: SASL authentication failed
Any help is super appreciated!
Solution 1:[1]
Ok, I've managed to make it work using Microsoft Graph API instead of MSAL, posting an example here in case anyone ever needs it:
package com.email;
import com.azure.identity.UsernamePasswordCredential;
import com.azure.identity.UsernamePasswordCredentialBuilder;
import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
import com.microsoft.graph.models.BodyType;
import com.microsoft.graph.models.EmailAddress;
import com.microsoft.graph.models.ItemBody;
import com.microsoft.graph.models.Message;
import com.microsoft.graph.models.Recipient;
import com.microsoft.graph.models.UserSendMailParameterSet;
import com.microsoft.graph.requests.GraphServiceClient;
import okhttp3.Request;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Set;
public class GraphAPIExample {
private static final String clientId = System.getenv("SMTP_CLIENT_ID");
private static final String to = "[email protected]";
private static final String mailbox = System.getenv("SMTP_MAILBOX");
private static final String pwd = System.getenv("SMTP_MAILBOX_PWD");
private static final Set<String> scopes = Set.of("Mail.Send");
public static void main(String[] args) {
final UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder()
.clientId(clientId)
.username(mailbox)
.password(pwd)
.build();
final TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(new ArrayList<>(scopes), usernamePasswordCredential);
final GraphServiceClient<Request> graphClient =
GraphServiceClient
.builder()
.authenticationProvider(tokenCredentialAuthProvider)
.buildClient();
graphClient.me()
.sendMail(UserSendMailParameterSet
.newBuilder()
.withMessage(createMessage())
.build())
.buildRequest()
.post();
}
private static Message createMessage() {
Message message = new Message();
ItemBody body = new ItemBody();
message.subject = "testing modern auth";
body.contentType = BodyType.TEXT;
body.content = "testing modern auth";
message.body = body;
LinkedList<Recipient> toRecipientsList = new LinkedList<>();
Recipient toRecipients = new Recipient();
EmailAddress emailAddress = new EmailAddress();
emailAddress.address = to;
toRecipients.emailAddress = emailAddress;
toRecipientsList.add(toRecipients);
message.toRecipients = toRecipientsList;
return message;
}
}
You're going to need the following dependencies to run this example:
implementation("com.microsoft.graph:microsoft-graph:5.23.0")
implementation("com.azure:azure-identity:1.5.1")
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | felipecao |