这篇文章分享一下自己把项目部署在阿里云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
最后重启服务,登陆的时候成功发出了邮件。