暑假在家做一个类似知乎的问答型网站(代码可见:Github/wenda 喜欢的可以给个star或者自己fork然后修改,目前功能还未很完善),其中有一个站内邮件通知系统 (这里简单的讲一个例子:如果用户登录的时候出现异常,那么就会通过邮件发送通知用户)。然而却碰到一个问题。问题错误信息如下:
发送邮件失败Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: smtp.qq.com, port: 465; nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure. Failed messages: javax.mail. MessagingException: Could not connect to SMTP host: smtp.qq.com, port: 465; nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
自己在将错误信息代码google了一下,找了很久发现很多解决方案,包括stackoverflow上的一些解决方案,但还是没用。然后呢用百度试了下,结果在第一条是开源中国的一篇博客:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 。
点进去是这样的:(如下图)
结果就是:这个问题是jdk导致的,jdk1.8里面有一个jce的包,安全性机制导致的访问https会报错,官网上有替代的jar包,如果替换掉就可以了。问题的解决方法还可以就是在整个项目中把你的jdk换成是1.7去,同样也可以解决这个我问题。
这两个jar包的下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
然后下载之后,把这个压缩文件解压,得到两个jar包去覆盖jdk安装目录下的jre\lib\security\下相同的jar包就能解决java8的邮件发送问题。
接着用QQ邮箱我亲测有用,但是要注意一点就是:开启SMTP服务后要记得将你的16位授权码作为你的qq邮箱登录密码。
MailSender.java中mailSender.setPassword(“16位授权码”);
mailSender.setHost(“smtp.qq.com”); mailSender.setPort(465);
下面把完整代码发布出来:
1. LoginExceptionHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.nowcoder.async.handler;import com.nowcoder.async.EventHandler;import com.nowcoder.async.EventModel;import com.nowcoder.async.EventType;import com.nowcoder.util.MailSender;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;@Component public class LoginExceptionHandler implements EventHandler { @Autowired MailSender mailSender; @Override public void doHandle (EventModel model) { Map<String, Object> map = new HashMap<String, Object>(); map.put("username" , model.getExt("username" )); mailSender.sendWithHTMLTemplate(model.getExt("email" ), "登陆IP异常" , "mails/login_exception.html" , map); } @Override public List<EventType> getSupportEventTypes () { return Arrays.asList(EventType.LOGIN); } }
2. LoginController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 package com.nowcoder.controller; import com.nowcoder.async.EventModel; import com.nowcoder.async.EventProducer; import com.nowcoder.async.EventType; import com.nowcoder.service.UserService; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.util.Map; /** * Created by 10412 on 2016/7/2. */ @Controller public class LoginController { private static final Logger logger = LoggerFactory.getLogger(LoginController.class); @Autowired UserService userService; @Autowired EventProducer eventProducer; @RequestMapping(path = {"/reg/"}, method = {RequestMethod.POST}) public String reg(Model model, @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("next") String next, @RequestParam(value="rememberme", defaultValue = "false") boolean rememberme, HttpServletResponse response) { try { Map<String, Object> map = userService.register(username, password); if (map.containsKey("ticket")) { Cookie cookie = new Cookie("ticket", map.get("ticket").toString()); cookie.setPath("/"); if (rememberme) { cookie.setMaxAge(3600*24*5); } response.addCookie(cookie); if (StringUtils.isNotBlank(next)) { return "redirect:" + next; } return "redirect:/"; } else { model.addAttribute("msg", map.get("msg")); return "login"; } } catch (Exception e) { logger.error("注册异常" + e.getMessage()); model.addAttribute("msg", "服务器错误"); return "login"; } } @RequestMapping(path = {"/reglogin"}, method = {RequestMethod.GET}) public String regloginPage(Model model, @RequestParam(value = "next", required = false) String next) { model.addAttribute("next", next); return "login"; } @RequestMapping(path = {"/login/"}, method = {RequestMethod.POST}) public String login(Model model, @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(value="next", required = false) String next, @RequestParam(value="rememberme", defaultValue = "false") boolean rememberme, HttpServletResponse response) { try { Map<String, Object> map = userService.login(username, password); if (map.containsKey("ticket")) { Cookie cookie = new Cookie("ticket", map.get("ticket").toString()); cookie.setPath("/"); if (rememberme) { cookie.setMaxAge(3600*24*5); } response.addCookie(cookie); eventProducer.fireEvent(new EventModel(EventType.LOGIN) .setExt("username", username).setExt("email", "****@qq.com") .setActorId((int)map.get("userId"))); if (StringUtils.isNotBlank(next)) { return "redirect:" + next; } return "redirect:/"; } else { model.addAttribute("msg", map.get("msg")); return "login"; } } catch (Exception e) { logger.error("登陆异常" + e.getMessage()); return "login"; } } @RequestMapping(path = {"/logout"}, method = {RequestMethod.GET, RequestMethod.POST}) public String logout(@CookieValue("ticket") String ticket) { userService.logout(ticket); return "redirect:/"; } }
3. EventHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.nowcoder.async; import java.util.List; /** * Created by 10412 on 2016/8/10. */ public interface EventHandler { void doHandle(EventModel model); List<EventType> getSupportEventTypes(); }
4. MailSender.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package com.nowcoder.util;import org.apache.velocity.app.VelocityEngine;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.mail.javamail.JavaMailSenderImpl;import org.springframework.mail.javamail.MimeMessageHelper;import org.springframework.stereotype.Service;import org.springframework.ui.velocity.VelocityEngineUtils;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeMessage;import javax.mail.internet.MimeUtility;import java.util.Map;import java.util.Properties;@Service public class MailSender implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(MailSender.class); private JavaMailSenderImpl mailSender; @Autowired private VelocityEngine velocityEngine; public boolean sendWithHTMLTemplate (String to, String subject, String template, Map<String, Object> model) { try { String nick = MimeUtility.encodeText("***" ); InternetAddress from = new InternetAddress(nick + "<****@qq.com>" ); MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage); String result = VelocityEngineUtils .mergeTemplateIntoString(velocityEngine, template, "UTF-8" , model); mimeMessageHelper.setTo(to); mimeMessageHelper.setFrom(from); mimeMessageHelper.setSubject(subject); mimeMessageHelper.setText(result, true ); mailSender.send(mimeMessage); return true ; } catch (Exception e) { logger.error("发送邮件失败" + e.getMessage()); return false ; } } @Override public void afterPropertiesSet () throws Exception { mailSender = new JavaMailSenderImpl(); mailSender.setUsername("***@qq.com" ); mailSender.setPassword("wnppafhsbrcgbfbh" ); mailSender.setHost("smtp.qq.com" ); mailSender.setPort(465 ); mailSender.setProtocol("smtps" ); mailSender.setDefaultEncoding("utf8" ); Properties javaMailProperties = new Properties(); javaMailProperties.put("mail.smtp.ssl.enable" , true ); mailSender.setJavaMailProperties(javaMailProperties); } }
5. login_exception.html 发送消息模板(可自定义)
一切都好了,运行。
登录。
发送邮件过来了。
总结来说:这个错误就是jdk1.8中的一个jce的包,安全性机制导致访问https会报错。