Java 对接 Office 365 邮箱全攻略:OAuth2 认证 + JDK8 兼容 + Spring Boot 集成(2025 版)

🚨 重要通知:微软强制 OAuth2,传统认证已失效!

2023 年 10 月起,Office 365 全面禁用用户名 + 密码认证,Java 开发者必须通过OAuth 2.0实现邮件发送。本文针对 CSDN 技术栈,提供从 Azure AD 配置到生产级代码的全流程方案,附 JDK 8 兼容实现和 Spring Boot 集成示例。

一、Office 365 对接核心流程(图示)
二、Azure AD 应用注册(分步教程)
  1. 创建应用

    • 登录Azure 门户 → Azure AD → 应用注册 → 新建注册
    • 记录:Client IDClient SecretTenant ID(租户域名或 ID)
  2. 配置权限

    • API 权限中添加Microsoft GraphMail.Send权限(选择应用权限
    • 点击授予管理员同意(需管理员账号操作)
  3. 获取令牌端点

    plaintext

    令牌URL:https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
    
三、Java 原生 API 实现(JDK 8 兼容)
1. 核心依赖(Maven)

xml

<dependency><groupId>com.sun.mail</groupId><artifactId>mail</artifactId><version>1.6.2</version> <!-- JDK8唯一兼容版本 -->
</dependency>
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version> <!-- HTTP请求工具 -->
</dependency>
2. 完整代码示例

java

import javax.mail.*;
import javax.mail.internet.*;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;public class Office365MailClient {private static final String TOKEN_URL = "https://login.microsoftonline.com/%s/oauth2/v2.0/token";private static final String SCOPE = "https://outlook.office365.com/.default";private final String tenantId, clientId, clientSecret, senderEmail;private final ConcurrentHashMap<String, String> tokenCache = new ConcurrentHashMap<>();public Office365MailClient(String tenantId, String clientId, String clientSecret, String senderEmail) {this.tenantId = tenantId;this.clientId = clientId;this.clientSecret = clientSecret;this.senderEmail = senderEmail;}public void sendHtmlEmail(String to, String subject, String htmlContent) throws Exception {String accessToken = getAccessToken();Properties props = getSmtpProperties(accessToken);Session session = Session.getInstance(props);MimeMessage msg = createMimeMessage(session, to, subject, htmlContent);try (Transport transport = session.getTransport("smtp")) {transport.connect(); // 自动触发XOAUTH2认证transport.sendMessage(msg, msg.getAllRecipients());System.out.println("发送成功,响应码:" + ((SMTPTransport) transport).getLastServerResponse());}}private Properties getSmtpProperties(String accessToken) {Properties props = new Properties();props.put("mail.smtp.host", "smtp.office365.com");props.put("mail.smtp.port", "587");props.put("mail.smtp.auth", "true");props.put("mail.smtp.starttls.enable", "true");props.put("mail.smtp.auth.mechanisms", "XOAUTH2");// 注入OAuth2认证器props.put("mail.smtp.user", senderEmail);props.put("mail.smtp.password", accessToken);return props;}private MimeMessage createMimeMessage(Session session, String to, String subject, String htmlContent) throws MessagingException {MimeMessage msg = new MimeMessage(session);msg.setFrom(new InternetAddress(senderEmail));msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));msg.setSubject(subject, "UTF-8");msg.setContent(htmlContent, "text/html; charset=utf-8");return msg;}// 令牌获取与缓存(简化实现)private String getAccessToken() throws Exception {// 实际需实现HTTP请求获取令牌,参考后文Spring Boot方案return "your_oauth2_token";}
}
四、Spring Boot 集成方案(生产级)
1. 依赖配置

xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><exclusions><exclusion><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version>
</dependency>
2. 配置文件(application.properties)

properties

spring.mail.host=smtp.office365.com
spring.mail.port=587
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.auth.mechanisms=XOAUTH2office365.tenant-id=your_tenant_id
office365.client-id=your_client_id
office365.client-secret=your_client_secret
office365.sender-email=your_sender@example.com
3. 服务类实现

java

import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;@Service
public class Office365MailService {private final JavaMailSender mailSender;private final String tenantId, clientId, clientSecret, senderEmail;private final Office365TokenProvider tokenProvider;public Office365MailService(JavaMailSender mailSender,@Value("${office365.tenant-id}") String tenantId,@Value("${office365.client-id}") String clientId,@Value("${office365.client-secret}") String clientSecret,@Value("${office365.sender-email}") String senderEmail) {this.mailSender = mailSender;this.tenantId = tenantId;this.clientId = clientId;this.clientSecret = clientSecret;this.senderEmail = senderEmail;this.tokenProvider = new Office365TokenProvider(tenantId, clientId, clientSecret);}public void sendEmail(String to, String subject, String htmlContent) throws MessagingException {MimeMessage message = mailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");helper.setFrom(senderEmail);helper.setTo(to);helper.setSubject(subject);helper.setText(htmlContent, true); // 支持HTML// 注入令牌到邮件头(非必须,Spring自动处理认证)message.setHeader("Authorization", "Bearer " + tokenProvider.getAccessToken());mailSender.send(message);}
}
五、常见错误与解决方案
错误码 / 提示原因分析解决方案
535 Authentication failed令牌无效或权限不足检查 Azure AD 应用权限,重新获取令牌
550 5.7.1 SendAs permission缺少发送权限通过 PowerShell 分配SendAs权限
421 Service not available服务器临时繁忙添加重试机制,设置指数退避(如 1s→2s→4s)
ClassNotFoundException: SMTPTransportJDK 版本不兼容确保使用 JavaMail 1.6.2+,JDK 8 需显式引入com.sun.mail:mail:1.6.2
六、性能优化与安全实践
  1. 令牌缓存
    使用ConcurrentHashMap或 Redis 缓存令牌,设置提前 5 分钟刷新:

    java

    private static final long TOKEN_EXPIRE = 3600; // 有效期1小时
    private static final long REFRESH_BUFFER = 300; // 提前5分钟刷新
    
  2. 连接池配置
    在 Spring Boot 中配置连接池参数:

    properties

    spring.mail.properties.mail.smtp.connectionpool.size=20
    spring.mail.properties.mail.smtp.connectionpool.timeout=5000
    
  3. 敏感信息管理

    • 禁止硬编码,使用环境变量或 Spring 配置中心
    • 通过azure-keyvault组件从 Key Vault 获取Client Secret
七、权威参考
  1. 微软官方文档

    • Office 365 SMTP OAuth2 认证
    • Azure AD 应用权限配置
  2. JavaMail 最佳实践

    • XOAUTH2 认证示例
    • JDK 8 兼容性指南
🌟 总结

本文提供了 Java 对接 Office 365 邮箱的完整解决方案,覆盖原生 API 和 Spring Boot 集成,特别针对 JDK 8 兼容性和 OAuth 2.0 认证做了深度优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文详谈Linux中的时间管理和定时器编程

&#xff08;目录&#xff09; 先说一些在计算机中需要用到时间的地方&#xff1a;系统日志log、OS调度(时间片、定时器)等等~~ 时间的计量 计时的方式发展&#xff1a;日晷、沙漏 -> 机械钟 -> 石英振荡器、晶振 -> 铯原子钟 -> 氢原子钟 计算机中的计时方式&…

使用FastAPI+Sqlalchemy从一个数据库向另一个数据库更新数据(sql语句版)

from sqlalchemy import create_engine, text from sqlalchemy.orm import sessionmaker # 配置数据库连接&#xff08;示例为PostgreSQL->MySQL&#xff09; SRC_DB_URL postgresql://user:passsource_host:5432/source_db DST_DB_URL mysqlpymysql://user:passdest_hos…

基于python脚本进行Maxwell自动化仿真

本文为博主进行Maxwell自动化研究过程的学习记录&#xff0c;同时对Maxwell自动化脚本&#xff08;pythonIron&#xff09;实现方法进行分享。 文章目录 脚本使用方法脚本录制与查看常用脚本代码通用开头定义项目调整设计变量软件内对应位置脚本 设置求解器软件内对应位置脚本…

pikachu通关教程-RCE

目录 RCE(remote command/code execute)概述: exec "ping" 管道符 乱码问题 RCE(remote command/code execute)概述: RCE漏洞&#xff0c;可以让攻击者直接向后台服务器远程注入操作系统命令或者代码&#xff0c;从而控制后台系统 分为远程代码和远程命令两种.当…

JavaScript性能优化全景指南

JavaScript性能优化全景指南 Ⅰ. 加载性能优化 1.1 代码分割与懒加载 动态导入(ES2020) javascript // 路由级代码分割 const ProductPage () > import(/* webpackChunkName: "product" */ ./ProductPage.vue); // 交互驱动加载 document.querySelector(#char…

BaseTypeHandler用法-笔记

1.BaseTypeHandler简介 org.apache.ibatis.type.BaseTypeHandler 是 MyBatis 提供的一个抽象类&#xff0c;通过继承该类并实现关键方法&#xff0c;可用于实现 Java 类型 与 JDBC 类型 之间的双向转换。当数据库字段类型与 Java 对象属性类型不一致时&#xff08;如&#xff…

t015-预报名管理系统设计与实现 【含源码!!!】

项目演示地址 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装预报名管理系统软件来发挥其高效地信息处理的…

Day12 - 计算机网络 - HTTP

HTTP常用状态码及含义&#xff1f; 301和302区别&#xff1f; 301&#xff1a;永久性移动&#xff0c;请求的资源已被永久移动到新位置。服务器返回此响应时&#xff0c;会返回新的资源地址。302&#xff1a;临时性性移动&#xff0c;服务器从另外的地址响应资源&#xff0c;但…

【python深度学习】Day 40 训练和测试的规范写法

知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#xff1a;仔细学习下测试和训练代码…

亡羊补牢与持续改进 - SRE 的安全日志、审计与事件响应

亡羊补牢与持续改进 - SRE 的安全日志、审计与事件响应 如果说我们之前讨论的安全措施(如 IAM、网络策略、密钥管理、漏洞补丁)是为我们的“数字城堡”修筑坚固的城墙、设置精密的门锁、定期检查和修补潜在的裂缝,那么安全日志就像是遍布城堡内外的监控摄像头和出入登记簿,…

CppCon 2014 学习第2天:Using Web Services in C++

概述 这是一个会议或演讲的概述内容&#xff0c;主要介绍一个关于C Rest SDK的分享&#xff0c;翻译和理解如下&#xff1a; 翻译 概述 先介绍什么是典型的Web服务结构和它的特征讲讲调用这些Web服务的几种方式重点介绍自己团队开发的一个C库&#xff08;C Rest SDK&#xf…

【OpenHarmony】【交叉编译】使用gn在Linux编译3568a上运行的可执行程序

linux下编译arm64可执行程序 一.gn ninja安装二.交叉编译工具链安装1.arm交叉编译工具2.安装arm64编译器 三. gn文件添加arm及arm64工具链四.编译验证 本文以gn nijia安装中demo为例&#xff0c;将其编译为在arm64(rk_3568_a开发板)环境下可运行的程序 一.gn ninja安装 安装g…

【开发心得】AstrBot对接飞书失败的问题探究

飞书与AstrBot的集成使用中,偶尔出现连接不稳定的现象。尽管不影响核心功能,但为深入探究技术细节并推动后续优化,需系统性记录该问题。先从底层通信机制入手,分析连接建立的逻辑与数据交互流程。基于实际现象,明确问题发生的具体场景和表现特征,进而梳理潜在影响因素,为…

Spring Boot 3.5.0中文文档上线

Spring Boot 3.5.0 中文文档翻译完成&#xff0c;需要的可收藏 传送门&#xff1a;Spring Boot 3.5.0 中文文档

7.atlas安装

1.服务器规划 软件版本参考&#xff1a; https://cloud.google.com/dataproc/docs/concepts/versioning/dataproc-release-2.2?hlzh-cn 由于hive3.1.3不完全支持jdk8,所以将hive的版本调整成4.0.1。这个版本没有验证过&#xff0c;需要读者自己抉择。 所有的软件都安装再/op…

c# 获取电脑 分辨率 及 DPI 设置

using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices;/// <summary> /// 这个可以 /// </summary> class Program {static void Main(){//设置DPI感知try{SetProcessDpiAwareness(…

LangChain表达式(LCEL)实操案例1

案例1&#xff1a;写一篇短文&#xff0c;然后对这篇短文进行打分 from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.runnables import RunnableWithMessageHist…

OleDbParameter.Value 与 DataTable.Rows.Item.Value 的性能对比

OleDbParameter.Value 与 DataTable.Rows.Item.Value 的性能对比 您提到的两种赋值操作属于不同场景&#xff0c;它们的性能和稳定性取决于具体使用方式。下面从几个维度进行分析&#xff1a; 1. 操作本质对比 &#xff08;1&#xff09;OleDbParameter.Value 用途&#xf…

【Opencv+Yolo】Day2_图像处理

目录 一、图像梯度计算 图像梯度-sobal算子&#xff1a; Scharr&#xff1a;权重变化更大&#xff08;线条更加丰富&#xff0c;比Sobel更加细致捕捉更多梯度信息&#xff09; Laplacian算子&#xff1a;对噪音点敏感&#xff08;可以和其他一起结合使用&#xff09; 二、边…

STM32通过rt_hw_hard_fault_exception中的LR寄存器追溯程序问题​

1. 问题现象 程序运行导致rt_hw_hard_fault_exception 如图 显示错误相关代码 struct exception_stack_frame {uint32_t r0;uint32_t r1;uint32_t r2;uint32_t r3;uint32_t r12; uint32_t lr; // 链接寄存器 (LR)uint32_t pc; // 程序计数器 (PC)uint32_t psr; // 程序状态…