简体   繁体   中英

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!

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 = "your@email.com";
    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")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM