java - 如何使用 Java 中的 MSAL 从 Microsoft Outlook 发送电子邮件?

标签 java email smtp exchange-server azure-ad-msal

我正在尝试使用 Java/Spring 开发一个应用程序,该应用程序连接到 Microsoft Outlook/Exchange SMTP 中继以使用 MSAL4J 发送电子邮件,但当我尝试连接到邮件服务器时,我不断收到身份验证错误。

我在这里做错了什么吗?

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;
    }
}

这是 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

非常感谢任何帮助!

最佳答案

好的,我已成功使用 Microsoft Graph API 而不是 MSAL 使其正常工作,在此发布一个示例,以防有人需要它:

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 = "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6b12041e192b0e060a020745080406" rel="noreferrer noopener nofollow">[email protected]</a>";
    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;
    }
}

您将需要以下依赖项来运行此示例:

implementation("com.microsoft.graph:microsoft-graph:5.23.0")
implementation("com.azure:azure-identity:1.5.1")

关于java - 如何使用 Java 中的 MSAL 从 Microsoft Outlook 发送电子邮件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72230546/

相关文章:

email - 电子邮件 header 字段 'thread-index' 如何工作?

javamail 邮件发不出去

google-app-engine - 去,Appengine,SMTP,Gmail

powershell - 无需身份验证通过 powershell 发送邮件

PHP 在 Windows 上发送邮件导致发送电子邮件后为 'hang'

java - 如何在 MySQL 的列中保留 1 和 0 的序列?

java - 防止文件竞争条件

java - 如何在 Spring Integration DSL 中实现简单的 echo 套接字服务

Java Hibernate AutoIncrement Identity set ID to start 0 mySQL

ruby-on-rails - Rails 4、Devise 和 Mandrill 电子邮件