阿里云服务器发送邮件失败 Could not connect to SMTP host: smtp.xxx.com, port: 465;
最近做了一个发送邮件的功能, 在本地调试完成后,部署到阿里云服务器就一直报错,
Could not connect to SMTP host: smtp.qiye.aliyun.com, port: 465; 网上也搜索了很多的资料,最后花了好几个小时才解决, 报错日志如下
Send mail failed. Error message : Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: smtp.qiye.aliyun.com, port: 465;nested exception is:javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate). Failed messages: javax.mail.MessagingException: Could not connect to SMTP host: smtp.qiye.aliyun.com, port: 465;nested exception is:javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
总结下来,可能的原因如下,我这里遇到的就属于第四种情况
- 网络或者端口不通
- 邮箱发件服务器地址+端口不正确
- jdk版本不支持
- 发送邮件代码侧问题
排查定位步骤如下
一、 网络或者端口不通
从提示看就是阿里云邮箱的465端口连接不上,一开始以为是阿里云禁止了465端口,所以在阿里云控制台的安全组里面给465端口都配置了入方向和出方向,但仍旧同样报错。 通过shell命令检查网络和端口,都是ok的。(有人说阿里云服务器默认是开了465的,其实无需特意在安全组规则里面配置465)
针对465端口检测,显然也是ok的
#不指定TLS版本
openssl s_client -connect smtp.qiye.aliyun.com:465
#指定TLS版本
openssl s_client -connect smtp.qiye.aliyun.com:465 -tls1_2
二、邮箱发件服务器地址+端口不正确
关于端口方面,早期的邮件端口是25,但目前大多服务商因为垃圾邮件的原因禁止了25端口(所以我这边一开始就用的是465)。阿里云服务器也不例外,但可以在阿里云控制台申请解封25端口,然而是小微服务器一般不给解封的,所以即使本地25端口也调试ok,也不考虑换25端口作为解决方向。
阿里云的stmp地址除了smtp.qiye.aliyun.com外,还有以下两个
smtp.mxhichina.com +465
smtphk.qiye.aliyun.com +80/465
但是经过部署阿里云服务器测试,报错是同样的。于是怀疑是阿里云企业邮箱有啥问题或者阿里云的企业邮箱哪里设置的不对头,所以另外申请了腾讯企业邮箱 smtp.exmail.qq.com+465/587端口进行部署阿里云测试,问题依旧。这波操作下来, 本地ok上阿里云行不通,还是环境的问题需要继续排查。
三、jdk版本不支持
网上有说法,高版本的jdk的http安全限制导致发不去邮件。我这里阿里云服务器jdk版本是1.8.0_372, 本地是 1.8.0_91,都是1.8的jdk,小版本不同应该问题不大,但也进行了尝试。关于jdk主要是两个方面,java.security文件的配置和替换jre目录下的jar包
3.1更改 java.security配置
java.security文件位于jdk安装目录的/jdk1.8.0_372/jre/lib
目录下面,服务器上忘记或者不知道jdk的安装路径的,可以参考如下
which java
ls -lrt /usr/bin/java #其中 /usr/bin/java是第一步的输出结果
ls -lrt /etc/alternatives/java #其中 /etc/alternatives/java是第二步输出的结果
# 如下图,可知安装目录是 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.0.2.al8.x86_64
编辑 java.security文件,搜索关键词jdk.tls.disabledAlgorithms=
找到如下位置
注释原来的3行或者删除其中的 SSLv3、TLSv1、TLSv1.1协议(即不禁用这三个加密协议),并保存。效果如下
3.2 用低版本jdk的jar替换高版本jdk的jre目录下的jar包
需要替换的jar文件分别是 local_policy.jar
和US_export_policy.jar
。可以从网上下载低版本的jar或者用本地jdk相同目录下的jar(因为本地能发送成功)去服务器上进行覆盖。这两个jar包的路径位于jdk安装目录下
/jdk1.8.0_372/jre/lib
或者
/jdk1.8.0_372/jre/lib/jre/lib/security/policy/limited
/jdk1.8.0_372/jre/lib/jre/lib/security/policy/unlimited
jdk1.7版本替换包网上下载地址: 点击下载,下载后解压后覆盖到上面的路径下
以上两个步骤操作后,通过阿里云控制台重启了实例和重启应用服务器,报错却依旧。
四、 发送邮件代码侧问题
先看发送邮件核心代码
Properties properties = new Properties();
properties.put("mail.smtp.auth", true);
properties.put("mail.smtp.connectiontimeout", String.valueOf(3 * 1000));
properties.put("mail.smtp.timeout", String.valueOf(3 * 1000));
//启用SSL与指定465端口
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.socketFactory.port", "465");
properties.put("mail.smtp.port", "465");
// SSL来建立连接,失败则回退兼容。如果出于某种原因无法使用SSL来建立连接(比如服务器不支持),则不会回退到非加密的连接方式,而是让连接尝试失败。
properties.put("mail.smtp.ssl.socketFactory", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.socketFactory.fallback", "false");
这段代码本地ok,上阿里云服务器就连不通stmp+465,故而又从网上找了几个别人写的发送邮件的工具类代码,都是大同小异,结果也是本地ok阿里云服务器不行,着实让人有点蒙圈。后来添加下面这行指定了ssl的加密协议才解决问题
// 握手阶段加密算法不匹配,jre高版本把加密算法禁止了 SSLv3, TLSv1, TLSv1.1等,尝试指定jdk版本或删除相关禁用配置项props.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");
下面附录一个发送邮件的工具类,以供参考和测试
package com.yulisao.utils.email;import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.Security;
import java.util.Date;
import java.util.Properties;public class EmailUtils{// 此方法调试ok后自行整理成工具类应用到项目中public static void sendmail() {try{//设置SSL连接、邮件环境Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";Properties props = System.getProperties();//协议//props.setProperty("mail.transport.protocol", "smtp");props.setProperty("mail.smtp.host", "smtp.qiye.aliyun.com");//smtp服务器地址//props.setProperty("mail.smtp.port", "25");//非加密端口// 使用ssl加密方式,进行如下配置:props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);props.setProperty("mail.smtp.socketFactory.fallback", "false");props.setProperty("mail.smtp.socketFactory.port", "465");// 不指定则是25端口了!注意阿里云禁用此端口props.setProperty("mail.smtp.port", "465");props.setProperty("mail.smtp.ssl.enable", "true");props.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");props.setProperty("mail.smtp.auth", "true");//表示SMTP发送邮件,需要进行身份验证props.setProperty("mail.smtp.from", "你的发件邮箱");//mailfrom 参数props.setProperty("mail.user","你的发件邮箱");//发件人的账号props.setProperty("mail.password","你的发件邮箱的授权码");// 发件人的账号的密码,如果开启三方客户端安全密码请使用新生产的密码System.setProperty("mail.mime.splitlongparameters", "false"); //用于解决附件名过长导致的显示异常//建立邮件会话Session session = Session.getDefaultInstance(props, new Authenticator() {//身份认证protected PasswordAuthentication getPasswordAuthentication() {//发件人的账号、密码String userName = props.getProperty("mail.user");String password = props.getProperty("mail.password");return new PasswordAuthentication(userName, password);}});//建立邮件对象MimeMessage message = new MimeMessage(session);//设置邮件的发件人InternetAddress from = new InternetAddress("你的发件邮箱","你的邮件主题"); //from 参数,可实现代发,注意:代发容易被收信方拒信或进入垃圾箱。message.setFrom(from);//设置邮件的收件人String[] to = {"abc@163.com","123456789@qq.com"};//收件人列表InternetAddress[] sendTo = new InternetAddress[to.length];for (int i=0;i<to.length;i++){System.out.println("正在执行发送到:" + to[i]);sendTo[i] = new InternetAddress(to[i]);}//传入收件人message.setRecipients(Message.RecipientType.TO,sendTo);//设置邮件的主题message.setSubject("邮件主题");//设置邮件的文本String content="邮件内容";message.setContent(content,"text/html;charset=UTF-8");//设置时间message.setSentDate(new Date());message.saveChanges();//发送邮件Transport.send(message);System.out.println("发送成功!");}catch(Exception e){System.out.println("发送邮件异常:"+e.toString());}}// 自测main方法public static void main(String[] args) {try{//设置SSL连接、邮件环境Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";Properties props = System.getProperties();//协议//props.setProperty("mail.transport.protocol", "smtp");props.setProperty("mail.smtp.host", "smtp.qiye.aliyun.com");//smtp服务器地址//props.setProperty("mail.smtp.port", "25");//非加密端口// 使用ssl加密方式,进行如下配置:props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);props.setProperty("mail.smtp.socketFactory.fallback", "false");props.setProperty("mail.smtp.socketFactory.port", "465");props.setProperty("mail.smtp.ssl.enable", "true");props.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");props.setProperty("mail.smtp.auth", "true");//表示SMTP发送邮件,需要进行身份验证props.setProperty("mail.smtp.from", "你的发件邮箱");//mailfrom 参数props.setProperty("mail.user","你的发件邮箱");//发件人的账号props.setProperty("mail.password","你的发件邮箱的授权码");// 发件人的账号的密码,如果开启三方客户端安全密码请使用新生产的密码System.setProperty("mail.mime.splitlongparameters", "false"); // 用于解决附件名过长导致的显示异常//建立邮件会话Session session = Session.getDefaultInstance(props, new Authenticator() {//身份认证protected PasswordAuthentication getPasswordAuthentication() {//发件人的账号、密码String userName = props.getProperty("mail.user");String password = props.getProperty("mail.password");return new PasswordAuthentication(userName, password);}});//建立邮件对象MimeMessage message = new MimeMessage(session);//设置邮件的发件人InternetAddress from = new InternetAddress("你的发件邮箱","你的邮件主题"); //from 参数,可实现代发,注意:代发容易被收信方拒信或进入垃圾箱。message.setFrom(from);//设置邮件的收件人String[] to = {"abc@163.com","123456789@qq.com"};//收件人列表InternetAddress[] sendTo = new InternetAddress[to.length];for (int i=0;i<to.length;i++){System.out.println("正在执行发送到:" + to[i]);sendTo[i] = new InternetAddress(to[i]);}//传入收件人message.setRecipients(Message.RecipientType.TO,sendTo);//设置邮件的主题message.setSubject("邮件主题");//设置邮件的文本String content="邮件内容";message.setContent(content,"text/html;charset=UTF-8");//设置时间message.setSentDate(new Date());message.saveChanges();//发送邮件Transport.send(message);System.out.println("发送成功!");}catch(Exception e){System.out.println("发送邮件异常:"+e.toString());}}
}
相关文章:

阿里云服务器发送邮件失败 Could not connect to SMTP host: smtp.xxx.com, port: 465;
最近做了一个发送邮件的功能, 在本地调试完成后,部署到阿里云服务器就一直报错, Could not connect to SMTP host: smtp.qiye.aliyun.com, port: 465; 网上也搜索了很多的资料,最后花了好几个小时才解决, 报错日志如下…...

Socket编程权威指南(二)完美掌握TCP流式协议及Socket编程的recv()和send()
在上一篇文章中,我们学习了Socket编程的基础知识,包括创建Socket、绑定地址、监听连接、接收连接等操作。然而,真正的套接字编程远不止于此。本文将重点介绍TCP 流式协议,什么是粘包问题?如何解决粘包问题 ?…...

当C++的static遇上了继承
比如我们想要统计下当前类被实例化了多少次,我们通常会这么写 class A { public:A() { Count_; }~A() { Count_--; }int GetCount() { return Count_; }private:static int Count_; };class B { public:B() { Count_; }~B() { Count_--; }int GetCount() { return …...

Three.js中的Raycasting技术:实现3D场景交互事件的Raycaster详解
前言 在Web开发中,Three.js是一个极为强大的库,它让开发者能够轻松地在浏览器中创建和展示3D图形。随着3D技术在网页设计、游戏开发、数据可视化等领域的广泛应用,用户与3D场景的交互变得日益重要。而要实现这种交互,一个核心的技…...

5 分钟内构建一个简单的基于 Python 的 GAN
文章目录 一、说明二、代码三、训练四、后记 一、说明 生成对抗网络(GAN)因其能力而在学术界引起轩然大波。机器能够创作出新颖、富有灵感的作品,这让每个人都感到敬畏和恐惧。因此,人们开始好奇,如何构建一个这样的网…...
智能硬件产品中常用的参数存储和管理方案
一、有哪些参数需要管理? 在智能硬件产品中,一般有三类数据需要存储并管理: 1. 系统设置数据 系统设置数据是指产品自身正常工作所依赖的一些参数。 这类数据的特点:只能在生产过程中修改,出厂后用户无权限修改。 比如:产品SN、产品密钥/token/license、传感器校准值…...

SwiftUI中Mask修饰符的理解与使用
Mask是一种用于控制图形元素可见性的图形技术,使用给定视图的alpha通道掩码该视图。在SwiftUI中,它类似于创建一个只显示视图的特定部分的模板。 Mask修饰符的定义: func mask<Mask>(alignment: Alignment .center,ViewBuilder _ ma…...

全光网络与传统网络架构的对比分析
随着信息技术的飞速发展,网络已经成为我们日常生活中不可或缺的一部分。在这个信息爆炸的时代,全光网络和传统网络架构作为两种主流的网络技术,各有其特点和适用范围。本文将对这两种网络架构进行详细的对比分析,帮助读者更好地了…...

stack overflow复现
当你在内存的栈中,存放了太多元素,就有可能在造成 stack overflow这个问题。 今天看看如何复现这个问题。 下图,是我写的程序,不断的创造1KB的栈,来看看执行了多少次,无限循环。 最后结果是7929kB时, 发…...
mybatis使用笔记
文章目录 打印sql日志mybatis-config.xml方式application.yml里面配置配置类配置方式 其他扫描方式官网文档 mybatis用了那么久,实际一直不明白,做个笔记吧。 打印sql日志 实测,mybatis-config.xml方式好用(记得注掉yml里的相关配置) mybat…...

学习笔记——路由网络基础——路由概述
一、路由概述 1、路由定义与作用 路由(routing)是指导报文转发路径信息,通过路由可以确认转发IP报文的路径。 路由:是指路由器从一个接口上收到数据包,根据数据包的目的地址进行定向并转发到另一个接口的过程。 路由(routing)的定义是指分…...
在量子计算时代,大数据技术将面临哪些挑战和机遇?
在量子计算时代,大数据技术将面临以下挑战和机遇: 挑战: 处理速度:量子计算机具有极高的计算速度,大数据技术需要适应和充分利用这种速度。现有的大数据算法和架构可能需要重新设计和优化,以充分发挥量子计…...

怎么换自己手机的ip地址
在互联网时代,IP地址已经成为了我们数字身份的一部分。无论是浏览网页、下载文件还是进行在线交流,我们的IP地址都在默默发挥着作用。然而,有时出于安全或隐私保护的考虑,我们可能需要更换手机的IP地址。那么,如何轻松…...

搭建 Langchain-Chatchat 详细过程
前言 本文参考官网和其他多方教程,将搭建 Langchain-Chatchat 的详细步骤进行了整理,供大家参考。 我的硬件 4090 显卡win10 专业版本 搭建环境使用 chatglm2-6b 模型 1. 创建虚拟环境 chatchat ,python 3.9 以上 conda create -n chat…...

C++期末复习
目录 1.基本函数 2.浅拷贝和深拷贝 3.初始化列表 4.const关键字的使用 5.静态成员变量和成员函数 6.C对象模型 7.友元 8.自动类型转换 9.继承 1.基本函数 (1)构造函数,这个需要注意的就是我们如果使用类名加括号,括号里面…...

2005-2022年各省居民人均消费支出数据(无缺失)
2005-2022年各省居民人均消费支出数据(无缺失) 1、时间:2005-2022年 2、来源:国家统计局、统计年鉴 3、指标:全体居民人均消费支出 4、范围:31省 5、缺失情况:无缺失 6、指标解释 居民人…...

swaggerHole:针对swaggerHub的公共API安全扫描工具
关于swaggerHole swaggerHole是一款针对swaggerHub的API安全扫描工具,该工具基于纯Python 3开发,可以帮助广大研究人员检索swaggerHub上公共API的相关敏感信息,整个任务过程均以自动化形式实现,且具备多线程特性和管道模式。 工具…...

【Rust】——面向对象设计模式的实现
🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大二学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL࿰…...
C#朗读语音
最近有个需求,需要在C#程序发生异常时候,朗读文字,C#提供了.net framework可以提供简单的语音朗读功能。 引入依赖 using System.Media; using System.Speech.Synthesis; using System.Runtime.InteropServices; //报警音量 SystemSounds.…...
c++ 简单的日志类 CCLog
此日志类,简单地实现了向标准输出控制台和文件输出日志信息的功能,并能在这两者之间进行切换输出,满足输出日志的不同需求。 代码如下: /** CCLog.h* c_common_codes** Created by xichen on 12-1-12.* Copyright 2012 cc_te…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...