news 2026/8/29 4:58:23

彻底解决 Hutool 邮件发送 SSLHandshakeException:六种方案全记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
彻底解决 Hutool 邮件发送 SSLHandshakeException:六种方案全记录

环境:Ubuntu 24.04 LTS | OpenJDK 1.8.0_492 | Hutool 5.3.x | 阿里企业邮箱(smtp.mxhichina.com:587)


一、踩坑现场

某天,使用HutoolMailUtil.send()发送邮件时,控制台无情地抛出了:

cn.hutool.extra.mail.MailException: MessagingException: Could not connect to SMTP host: smtp.mxhichina.com, port: 587 Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

邮件服务器是阿里企业邮箱,端口 587,开启 STARTTLS。按说配置无误,为何握手失败?


二、问题根源

JDK 1.8.0_492 的java.security文件中,jdk.tls.disabledAlgorithms默认禁用了TLSv1TLSv1.1(仅保留 TLSv1.2 及以上)。而部分邮件服务商(尤其是老实例)可能只支持 TLSv1.0 或 TLSv1.1,双方无法协商出共同协议,于是抛出SSLHandshakeException


三、解决方案概览

我尝试了多种手段,最终采用方法二(修改 java.security)成功。但为了给读者更多选择,这里整理了六种方案,按推荐度排序:

方案核心操作适用场景风险
① 代码指定 TLS 协议通过MailAccount设置mail.smtp.ssl.protocols大部分场景,最推荐
② 修改java.security移除jdk.tls.disabledAlgorithms中的 TLSv1/TLSv1.1JVM 全局生效,本文采用中(影响所有 Java 应用)
③ 检查 STARTTLS 配置确保端口 587 开启 STARTTLS,关闭 SSL 直连配置遗漏导致的连接失败
④ 改用 SSL 直连(端口 465)切换端口并启用sslEnable服务商支持 465 端口
⑤ 跳过证书验证设置MailSSLSocketFactory信任所有主机仅限开发测试极高(生产禁用)
⑥ 升级依赖版本升级hutool-alljavax.mail旧版本无配置属性或Bug时

下面逐一详解。


四、方案详解

✅ 方案一:代码中指定 TLS 协议版本(首选)

此方法侵入性最小,无需修改 JVM,控制粒度细。在MailAccount中直接指定允许的协议列表:

MailAccountaccount=newMailAccount();account.setHost("smtp.mxhichina.com");account.setPort(587);account.setAuth(true);account.setUser("your@email.com");account.setPass("your-password");// 核心:启用 STARTTLSaccount.setStarttlsEnable(true);account.setSslEnable(false);// 指定可用的 TLS 版本(按优先级顺序)account.setCustomProperty("mail.smtp.ssl.protocols","TLSv1.2 TLSv1.1 TLSv1");// 如果 Hutool 版本较旧,可能不支持 setCustomProperty,可改用系统属性// System.setProperty("mail.smtp.ssl.protocols", "TLSv1.2 TLSv1.1 TLSv1");

注意setCustomProperty在 Hutool 5.7.19+ 中可用。若版本过低,可升级依赖或直接通过System.setProperty临时设置(作用域为整个 JVM)。


✅ 方案二:修改java.security(本文采用的方法)

如果代码级配置无效(比如邮件库内部强制使用了 JVM 全局设置),可直接修改 JDK 的安全策略。

步骤:
  1. 找到java.security文件
    该文件位于 JDK 安装目录下的jre/lib/security/java.security。假设你的JAVA_HOME环境变量已正确设置(例如/usr/lib/jvm/java-8-openjdk-amd64),则完整路径为:

    $JAVA_HOME/jre/lib/security/java.security

    JAVA_HOME未设置,可通过which javareadlink -f获取实际路径,再向上定位到 JDK 根目录。

  2. 备份原文件(务必执行):

    sudocp$JAVA_HOME/jre/lib/security/java.security$JAVA_HOME/jre/lib/security/java.security.bak
  3. 编辑文件,找到jdk.tls.disabledAlgorithms=...一行,删除其中的TLSv1TLSv1.1(保留其他禁用算法):

    - jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, ... + jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, ...
  4. 保存退出,重启所有使用该 JDK 的 Java 应用(无需重启操作系统)。

效果:所有基于该 JDK 的 Java 程序均可使用 TLSv1/TLSv1.1,邮件发送恢复正常。

⚠️安全提示:TLSv1 和 TLSv1.1 已被 IETF 标记为废弃,存在已知漏洞。仅在内网或临时应急时采用,后续应推动服务端升级。


✅ 方案三:检查 STARTTLS 配置

端口 587 的标准用法是STARTTLS(先明文连接,再升级为 TLS)。若错误配置为 SSL 直连,会失败。

正确配置

account.setPort(587);account.setStarttlsEnable(true);// 开启 STARTTLSaccount.setSslEnable(false);// 关闭 SSL 直连

若服务商要求必须使用 STARTTLS,且未正确设置,即使协议版本匹配,也可能连接不上。


✅ 方案四:改用 SSL 直连(端口 465)

部分邮件服务商(如阿里云、腾讯企业邮)同时支持465 端口(SMTPS)。此时可直接使用 SSL 加密,无需 STARTTLS。

account.setPort(465);account.setSslEnable(true);// 启用 SSL 直连account.setStarttlsEnable(false);// 关闭 STARTTLS// 同样可指定协议版本(可选)account.setCustomProperty("mail.smtp.ssl.protocols","TLSv1.2 TLSv1.1 TLSv1");

注意:需要服务商开放 465 端口且支持 SSL。


⚠️ 方案五:跳过 SSL 证书验证(仅限测试)

此方法用于绕过证书链校验,解决证书过期或自签名问题,但会完全丧失安全性,生产环境绝对禁止

MailSSLSocketFactorysf=newMailSSLSocketFactory();sf.setTrustAllHosts(true);// 信任所有主机account.setCustomProperty("mail.smtp.ssl.socketFactory",sf);// 或者account.setCustomProperty("mail.smtp.ssl.trust","*");

若其他方案无效且只在开发环境,可临时使用以验证是否为证书问题。


✅ 方案六:升级依赖版本

如果 Hutool 或 JavaMail 版本过旧,可能缺少某些配置属性或存在 SSL 相关 Bug。升级至较新版本通常能解决问题。

<!-- pom.xml --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.28</version><!-- 最新稳定版 --></dependency><dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version><!-- 或 jakarta.mail 3.x --></dependency>

升级后,可尝试方案一中的setCustomProperty,通常即可生效。


五、验证与测试

修改后,建议先用以下命令确认服务端支持的 TLS 版本:

openssl s_client-connectsmtp.mxhichina.com:587-starttlssmtp-tls1_2openssl s_client-connectsmtp.mxhichina.com:587-starttlssmtp-tls1_1openssl s_client-connectsmtp.mxhichina.com:587-starttlssmtp-tls1

哪个版本能成功握手,就在配置中优先列出该版本。


六、最终选择与效果

我先行尝试了方案一,但不知为何(可能 Hutool 底层未完全覆盖),仍然报错。于是采用方案二(修改java.security),问题立刻解决。后来为了安全,又联系邮件服务商确认是否支持 TLSv1.2,在确认支持后将配置改回仅 TLSv1.2,并移除java.security的修改,最终稳定运行。

个人建议:若你的服务商支持 TLSv1.2,尽量保持 JDK 默认禁用低版本,仅通过代码(方案一)指定协议列表。若服务商确实老旧,再考虑修改全局配置,但务必评估风险。


七、总结

SSLHandshakeException: No appropriate protocol的本质是 TLS 版本协商失败。本文提供的六种方案覆盖了从代码到 JVM、从轻到重的解决路径。希望这篇实战记录能帮助你快速摆脱邮件发送的困扰。

如果你有其他更好的方法,欢迎在评论区补充交流!

发布日期:2026-08-27

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 4:57:10

ARINC818协议解析到上板验证(一)

ARINC 818 协议总体概述本文档基于以下 4 份资料交叉比对编制&#xff0c;以官方规格书为权威基准&#xff1a;编号资料角色[1]Arinc_Specification_818.pdf&#xff08;ARINC SPEC 818 Supplement 1&#xff0c;ADVB 官方规格书&#xff09;权威基准[2]ARINC818视频传输系统研…

作者头像 李华
网站建设 2026/8/29 4:56:00

大厂Java后端实习备战全攻略:从基础到面试的完整指南

2021年春招那会儿&#xff0c;我为了备战阿里的Java后台开发实习&#xff0c;前前后后折腾了差不多三个月。现在回头看那段日子&#xff0c;踩过的坑、总结出来的经验&#xff0c;比面试本身还要值钱。这篇文章就把我当时从简历准备、知识复习、面试实战到offer选择的全过程拆开…

作者头像 李华
网站建设 2026/8/29 4:55:57

168亿美元算力投资,为何反而利好AIoT边缘智能?

168 亿美元、Terafab、马斯克&#xff0c;这三个关键词放在一起&#xff0c;很容易被当成一条单纯的产业新闻来读。但作为做 AIoT 和边缘智能的技术人&#xff0c;我更在意另一件事&#xff1a;这种超大规模算力计划&#xff0c;到底会把 AI 推向更集中的云端&#xff0c;还是反…

作者头像 李华
网站建设 2026/8/29 4:54:30

第二题day1弓靶训练

弓- Resort Hotel 题目大意&#xff1a;每个房间可以装下不同数量的人出掉给定方位内的房间最大容纳量的单个房间是多少 尝试1&#xff1a;直接暴力如果遇到范围内的就continue 写完不用测试都知道肯定超时&#xff0c;根据挖掉一定范围内的区间想到之前学过的前缀和&…

作者头像 李华
网站建设 2026/8/29 4:51:52

Java面试短期突击最快方式:抓住高频考点与场景题,用AI高效备战

金九银十秋招&#xff0c;Java岗位的竞争强度不用多说。真正让人焦虑的不是“知识点太多”&#xff0c;而是“时间不够”和“不知道背什么才有用”。身边有朋友用三个月把《Java核心技术》翻了两遍&#xff0c;结果面试一问“线上CPU飙升怎么排查”直接卡住&#xff1b;也有人只…

作者头像 李华
网站建设 2026/8/29 4:51:36

DirectX着色器字节码交叉编译器:原理、实现与跨平台应用指南

简介&#xff1a;这是一套面向图形开发工程师与Unity引擎着色器优化人员的DirectX着色器字节码交叉编译工具库&#xff0c;解决HLSL编译后的DXBC字节码在OpenGL、Vulkan、Metal等多平台复用难题。资源基于HLSLCrossCompiler深度重构&#xff0c;采用C11标准重写&#xff0c;支持…

作者头像 李华