阿里云ECS服务器无法发送邮件问题解决方案

news2024/12/23 17:15:51

这篇文章分享一下自己把项目部署在阿里云ECS上之后,登录邮件提醒时的邮件发送失败问题,无法连接发送邮箱的服务器。

博主使用的springboot提供的发送邮件服务,如下所示,为了实现异步的效果,新开了一个线程来发送邮件。

package cn.edu.sgu.www.mhxysy.service.system.impl;

import cn.edu.sgu.www.mhxysy.property.EmailProperties;
import cn.edu.sgu.www.mhxysy.property.SystemSettingsProperties;
import cn.edu.sgu.www.mhxysy.consts.RedisKeyPrefixConst;
import cn.edu.sgu.www.mhxysy.dto.system.UserLoginDTO;
import cn.edu.sgu.www.mhxysy.dto.system.UserUpdateDTO;
import cn.edu.sgu.www.mhxysy.entity.system.User;
import cn.edu.sgu.www.mhxysy.entity.system.UserLoginLog;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.feign.FeignService;
import cn.edu.sgu.www.mhxysy.redis.RedisRepository;
import cn.edu.sgu.www.mhxysy.redis.StringRedisUtils;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.system.UserService;
import cn.edu.sgu.www.mhxysy.util.IpUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import cn.edu.sgu.www.mhxysy.util.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
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;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author heyunlin
 * @version 1.0
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

	private final FeignService feignService;
	private final JavaMailSender javaMailSender;
	private final EmailProperties emailProperties;
	private final RedisRepository redisRepository;
	private final StringRedisUtils stringRedisUtils;
	private final SystemSettingsProperties systemSettingsProperties;

	@Autowired
	public UserServiceImpl(
			FeignService feignService,
			JavaMailSender javaMailSender,
			EmailProperties emailProperties,
			RedisRepository redisRepository,
			StringRedisUtils stringRedisUtils,
			SystemSettingsProperties systemSettingsProperties) {
		this.feignService = feignService;
		this.javaMailSender = javaMailSender;
		this.emailProperties = emailProperties;
		this.redisRepository = redisRepository;
		this.stringRedisUtils = stringRedisUtils;
		this.systemSettingsProperties = systemSettingsProperties;
	}

	@Override
	public void logout() {
		// 删除角色的权限
		redisRepository.delete(UserUtils.getLoginUsername());

		// 注销
		UserUtils.getSubject().logout();
	}

	@Override
	public void login(UserLoginDTO loginDTO) {
		// 一、验证码判断
		// 得到用户输入的验证码
		String code = loginDTO.getCode();

		// 获取正确的验证码
		String uuid = loginDTO.getUuid();
		String key = RedisKeyPrefixConst.PREFIX_CAPTCHA + uuid;
		String realCode = stringRedisUtils.get(key);

		// 得到的验证码为空,则获取验证码到登录之间的时间已经过了3分钟,验证码过期已经被删除
		if (realCode == null) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "验证码已失效,请刷新页面重新获取~");
		}
		// 验证码校验
		if (!code.equalsIgnoreCase(realCode)) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "验证码错误~");
		}

		// 二、登录流程
		// 得到用户名
		String username = loginDTO.getUsername();
		log.debug("用户{}正在登录...", username);

		// 查询用户信息,如果用户被锁定,提前退出
		User user = feignService.selectByUsername(username);

		if (user != null) {
			if (user.getEnable()) {
				// 1、shiro登录认证
				UsernamePasswordToken token = new UsernamePasswordToken(username, loginDTO.getPassword());
				Subject subject = UserUtils.getSubject();

				subject.login(token);
				// 设置session失效时间:永不超时
				subject.getSession().setTimeout(-1001);

				// 2、修改管理员上一次登录时间
				User usr = new User();

				usr.setId(user.getId());
				usr.setLastLoginTime(LocalDateTime.now());

				feignService.updateById(usr);

				// 3、邮件通知
				if (emailProperties.isEnable()) {
					new Thread(() -> {
						// 定义日期格式
						DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

						MimeMessage message = javaMailSender.createMimeMessage();
						MimeMessageHelper helper = new MimeMessageHelper(message);

						try {
							String text = "您的账号" + username + "在广州登录了。" +
									"[" + LocalDateTime.now().format(formatter) + "]";

							helper.setFrom(emailProperties.getFrom());
							helper.setTo(emailProperties.getTo());
							helper.setText(text);

							javaMailSender.send(message);
						} catch (MessagingException e) {
							e.printStackTrace();
						}
					}).start();
				}

				// 4、如果开启了系统日志,添加管理员登录历史
				if (systemSettingsProperties.isLoginLog()) {
					UserLoginLog loginLog = new UserLoginLog();

					loginLog.setId(StringUtils.uuid());
					loginLog.setUserId(user.getId());
					loginLog.setLoginTime(LocalDateTime.now());
					loginLog.setLoginIp(IpUtils.getLocalHostAddress());
					loginLog.setLoginHostName(IpUtils.getLocalHostName());

					feignService.saveLoginLog(loginLog);
				}

				// 5、从redis中删除用户权限
				redisRepository.delete(username);

				// 6、查询用户的权限信息,并保存到redis
				redisRepository.save(username);
			} else {
				throw new GlobalException(ResponseCode.FORBIDDEN, "账号已被锁定,禁止登录!");
			}
		} else {
			throw new GlobalException(ResponseCode.NOT_FOUND, "用户名不存在~");
		}
	}

	@Override
	public void updatePass(UserUpdateDTO userUpdateDTO) {
		feignService.updatePass(userUpdateDTO);
	}

}

过了一段时间之后,后台打印出了连接邮箱服务器超时的日志。 

Exception in thread "Thread-25" org.springframework.mail.MailSendException: Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.163.com, 25; timeout -1;

  nested exception is:

	java.net.ConnectException: Connection timed out (Connection timed out). Failed messages: com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.163.com, 25; timeout -1;

  nested exception is:

	java.net.ConnectException: Connection timed out (Connection timed out); message exception details (1) are:

Failed message 1:

com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.163.com, 25; timeout -1;

  nested exception is:

	java.net.ConnectException: Connection timed out (Connection timed out)

	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2210)

	at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:722)

	at javax.mail.Service.connect(Service.java:342)

	at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:518)

	at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:437)

	at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:361)

	at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:356)

	at cn.edu.sgu.www.mhxysy.service.system.impl.UserServiceImpl.lambda$login$0(UserServiceImpl.java:135)

	at java.lang.Thread.run(Thread.java:745)

Caused by: java.net.ConnectException: Connection timed out (Connection timed out)

	at java.net.PlainSocketImpl.socketConnect(Native Method)

	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)

	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)

	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)

	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)

	at java.net.Socket.connect(Socket.java:589)

	at java.net.Socket.connect(Socket.java:538)

	at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:335)

	at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:214)

	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2160)

	... 8 more

原因是:Couldn't connect to host, port: smtp.163.com, 25

但是通过终端连接smtp.163.com是成功的

ping smtp.163.com

但是尝试访问25端口,却无响应

telnet smtp.163.com 25

 

于是在网上查找了一些解决方案,最后采用了通过ssl连接的方式,在原来的邮件设置中加入以下设置

spring:
  mail:
    port: 25
    host: smtp.163.com
    default-encoding: UTF-8
    username: xxxxx@163.com
    password: xxxxxxxxxxxxx

    # 以下是新增的设置
    properties:
      mail:
        debug: true
        smtp:
          auth: true
          ssl:
            trust: smtp.163.com
          starttls:
            enable: true
            required: true
          socketFactory:
            port: 465
            class: javax.net.ssl.SSLSocketFactory

最后重启服务,登陆的时候成功发出了邮件。

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

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

相关文章

【Vim 插件管理器】Vim-plug和Vim-vbundle的区别

- vundle是一款老款的插件管理工具 - vim-plug相对较新,特点是支持异步加载,相比vundle而言 Vim-plug 是一个自由、开源、速度非常快的、极简的 vim 插件管理器。它可以并行地安装或更新插件。你还可以回滚更新。它创建浅层克隆shallow clone最小化磁盘…

【数据结构初阶】六、线性表中的队列(C语言 -- 链式结构实现队列)

相关代码gitee自取: C语言学习日记: 加油努力 (gitee.com) 接上期: 【数据结构初阶】五、线性表中的栈(C语言 -- 顺序表实现栈)_高高的胖子的博客-CSDN博客 1 . 队列(Queue) 队列的概念和结构&#xf…

如何利用niceGUI构建一个流式单轮对话界面

官方文档 参考文档 import asyncio import time import requests from fastapi import FastAPI from nicegui import app, uiclass ChatPage:temperature: ui.slider Nonetop_p: ui.slider Noneapi_key: ui.input Nonemodel_name: ui.input Noneprompt: ui.textarea None…

番外5:下载+安装+配置Linux

任务前期工作: 01. 电脑已安装好VMware Workstation软件; 02.提前下载好Rhel-8.iso映像文件(文件较大一般在9.4GB,建议采用迅雷下载),本人使用的以下版本(地址ed2k://|file|rhel-8.4-x86_64-dvd…

Tomcat启动后的日志输出为乱码

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

实现三栏布局的十种方式

本文节选自我的博客:实现三栏布局的十种方式 💖 作者简介:大家好,我是MilesChen,偏前端的全栈开发者。📝 CSDN主页:爱吃糖的猫🔥📣 我的博客:爱吃糖的猫&…

Mysql技术文档--之Mysql联查使用-快速了解联查看我这一篇就够了!国庆开卷!

阿丹: 开头先祝贺大家国庆快乐!!! 在MySQL中,联结(JOIN)是用于将两个或多个表中的数据根据指定的条件进行关联查询的操作。通过联结,你可以从多个表中检索相关的数据,并…

市场调研的步骤与技巧:助你了解市场需求

在当今快速发展的市场中,进行有效的市场研究对于了解消费者的行为、偏好和趋势至关重要。适当的市场研究可以帮助公司获得对目标受众的有价值的见解,创造更好的产品和服务,并提高客户满意度。今天,小编和大家一起讨论一下怎么做市…

10.1 今日任务:select实现服务器并发

#include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__); \perror(msg);\ }while(0)#define PORT 8888 //端口号&#xff0c;范围1024~49151 #define IP "192.168.112.115" //本机IP&#xff0c;ifco…

[Linux] 4.常用初级指令

pwd&#xff1a;显示当前文件路径 ls:列出当前文件夹下有哪些文件 mkdir空格文件名&#xff1a;创建一个新的文件夹 cd空格文件夹名&#xff1a;进入文件夹 cd..&#xff1a;退到上一层文件夹 ls -a&#xff1a;把所有文件夹列出来 .代表当前文件夹 ..代表上层文件夹 用…

第 365 场 LeetCode 周赛题解

A 有序三元组中的最大值 I 参考 B B B 题做法… class Solution { public:using ll long long;long long maximumTripletValue(vector<int> &nums) {int n nums.size();vector<int> suf(n);partial_sum(nums.rbegin(), nums.rend(), suf.rbegin(), [](int x…

Facebook Delos 中的虚拟共识协议

背景 Facebook 的软件系统栈一般包括两层&#xff1a;上层是数据平面&#xff0c; 下层是控制平面。 facebook software stack 数据平面包括大量的服务&#xff0c;他们需要存储和处理海量数据。控制平面用来支撑数据平面&#xff0c;起到一些控制作用&#xff1a;调度、配置…

XSS-labs

XSS常见的触发标签_xss标签_H3rmesk1t的博客-CSDN博客 该补习补习xss漏洞了 漏洞原理 网站存在 静态 和 动态 网站 xss 针对的网站 就是 动态网站 动态网站会根据 用户的环境 与 需求 反馈出 不同的响应静态页面 代码写死了 只会存在代码中有的内容 通过动态网站 用户体…

2023年中国火化设备行业现状分析:随着城市化进程的推进,市场需求将持续增长[图]

火化设备行业是指生产和提供用于尸体火化处理的设备和相关服务的行业。火化设备主要用于将尸体进行高温焚烧&#xff0c;将尸体转化为骨灰&#xff0c;以达到尸体处理和殡葬的目的。 火化设备行业优点 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 我国火…

C++面试八股(一)

目录 C和C的区别 1、语言特性 2、内存管理 3、C的库更加丰富 4、对异常的处理 什么是封装继承多态&#xff1f; 封装 继承 多态 new和malloc的区别 STL容器有哪些&#xff1f;容器对应的使用场景&#xff1f;&#xff08;挑一个你认为最熟悉的容器&#xff09; vector、…

评估指标Pre\Rec\F1\AUC

AUC的计算方法同时考虑了分类器对于正例和负例的分类能力&#xff0c;在样本不平衡的情况下&#xff0c;依然能够对分类器作出合理的评价。AUC代表模型预估样本之间的排序关系&#xff0c;即正负样本之间预测的gap越大&#xff0c;auc越大. 来自 https://blog.csdn.net/pearl8…

wustctf2020_name_your_cat

wustctf2020_name_your_cat Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)32位&#xff0c;开了NX和canary int shell() {return system("/bin/sh"); }有个后门函数 unsigned int…

AutoHotkey ---- 统一所有软件的快捷键(分析篇)

文章目录 引言理论编程方案 引言 快捷键大家都不陌生.但是目前的快捷键普遍存在以下几个问题。 不统一,即word、ppt、浏览器、各种编辑器、邮件客户端等等&#xff0c;都有属于自己的一套快捷键。快捷键冲突&#xff0c;即不同软件使用了相同的快捷键&#xff0c;而且作用域是…

GNN PyG~torch_geometric 学习理解

目录 1. PyG Introduction 2. PyG Installation 2.1 PyG 安装常见错误及原因 2.2 PyG 具体安装步骤 3. torch_geometric packages torch_geometric.data.Data Dataset 与 DataLoader Dropout、BatchNorm 3. torch_geometric: 理解edge_index 3.1 理解 mini-batch edg…

[H5动画制作系列]帧代码运行顺序测试

刚开始接触Animate CC(过去叫:Flash),对于帧代码的执行顺序十分迷惑。所以,专门做一个简单代码顺序测试. 准备工作: 代码图层actions,第1帧和第10帧为关键帧。 背景图层bg,就一个字符串红色Test.界面如下: 代码测试步骤: 第1帧参考代码如下: 第10帧参考代码如下: …