You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过OAuth2.0替代密码使用Java Mail连接Outlook邮件服务器?

Java Mail 连接Outlook邮件服务器OAuth2.0认证问题

问题背景

我正在使用Java Mail连接Microsoft Outlook邮件服务器,目前通过PLAIN认证(用户名+密码)可成功连接。由于微软即将禁用Basic Authentication,我希望升级为使用OAuth2.0认证,但替换密码为OAuth2令牌后连接失败。

成功的PLAIN认证代码

Store store = null;

String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props= new Properties();

props.put("mail.imaps.ssl.enable", "true");
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.port", port);
props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put("mail.imaps.auth.login.disable", "true");
props.put("mail.imaps.auth.plain.disable", "true");
props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imaps.socketFactory.fallback", "false");
props.setProperty("mail.imaps.socketFactory.port", port);
props.setProperty("mail.imaps.starttls.enable", "true");
props.put("mail.debug", "true");
props.put("mail.debug.auth", "true");

Session session = Session.getInstance(props);
session.setDebug(true);

store = session.getStore("imaps");
logger.info("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: "+ port + ", userEmailId: " + userEmailId+", AccessToken: " + oauth2AccessToken);
try {
    Integer iPort = Integer.parseInt(port);
    store.connect(host, iPort, userEmailId, password);
    // store.connect(host, iPort, userEmailId, oauth2AccessToken);
    logger.info("IMAP connected with system properties to Host:" + host + ", Port: "+ port + ", userEmailId: " + userEmailId+", AccessToken: " + oauth2AccessToken);
    if(store.isConnected()){
        logger.info("Connection Established using imap protocol successfully !");
    } else {
        logger.info("Connection not Established using imap protocol");
    }
} catch (Exception e) {
    logger.error("Store.Connect failed with the errror: "+e.getMessage());
    StringWriter sw = new StringWriter();
    e.printStackTrace(new PrintWriter(sw));
    String exceptionAsString = sw.toString();
    logger.error(exceptionAsString);
}
return store;

OAuth2连接失败的修改

将上述代码中的密码连接替换为令牌连接后失败:

store.connect(host, iPort, userEmailId, oauth2AccessToken);

调试日志

DEBUG: JavaMail version 1.5.0-b01
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], 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.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: setDebug: JavaMail version 1.5.0-b01
DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle]
DEBUG IMAPS: mail.imap.fetchsize: 16384
DEBUG IMAPS: mail.imap.ignorebodystructuresize: false
DEBUG IMAPS: mail.imap.statuscachetimeout: 1000
DEBUG IMAPS: mail.imap.appendbuffersize: -1
DEBUG IMAPS: mail.imap.minidletime: 10
DEBUG IMAPS: disable AUTH=LOGIN
DEBUG IMAPS: disable AUTH=PLAIN
DEBUG IMAPS: enable STARTTLS
DEBUG IMAPS: enable SASL
DEBUG IMAPS: SASL mechanisms allowed: XOAUTH2


DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [XXXX]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAPS: AUTH: PLAIN
DEBUG IMAPS: AUTH: XOAUTH2
DEBUG IMAPS: protocolConnect login, host=outlook.office365.com, user=username@email.com, password=<non-null>
DEBUG IMAPS: SASL Mechanisms:
DEBUG IMAPS:  XOAUTH2
DEBUG IMAPS: 
DEBUG IMAPS: No SASL support
A1 LOGIN username@email.com {1479+}
XXXXX
A1 NO LOGIN failed.

Azure门户提示

Azure门户提示似乎在期待密码而非令牌:
Azure提示

令牌生成代码

返回的字符串看起来是有效的令牌:

String accessToken = null;
String clientId = "<client id from azure app registration>"
String secret = "<client secret from azure app registration>" - client secret value
String authority = "https://login.microsoftonline.com/<tenant-id from azure>/oauth2/v2.0/token";
String scope = "https://outlook.office365.com/.default";

try {
    ConfidentialClientApplication app = ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(secret)).authority(authority).build();

    // With client credentials flows the scope is ALWAYS of the shape "resource/.default", as the
    // application permissions need to be set statically (in the portal), and then granted by a tenant administrator
    ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(Collections.singleton(scope)).build();

    CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
    IAuthenticationResult result = future.get();
    accessToken = result.accessToken();
    if (StringUtils.isBlank(accessToken)) {
        logger.error("Access token "+accessToken);
    }
} catch(Exception e) {
    logger.error("Exception in acquiring token: "+e.getMessage(), e);
}
logger.debug("Access Token : "+accessToken);
return accessToken;

疑问

请问如何修改才能通过OAuth2.0连接邮件服务器?


内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 19:15:31