暑假在家做一个类似知乎的问答型网站(代码可见: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
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; /** * Created by 10412 on 2016/8/10. */ @Component public class LoginExceptionHandler implements EventHandler { @Autowired MailSender mailSender; @Override public void doHandle(EventModel model) { // xxxx判断发现这个用户登陆异常 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
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
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
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; /** * Created by 10412 on 2016/8/10. // ***@qq.com wnppafhsbrcgbfbh(16位授权码) */ @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"); //qq邮箱开启smtp服务后使用16位授权码在第三方登录 // mailSender.setHost("smtp.exmail.qq.com"); mailSender.setHost("smtp.qq.com"); mailSender.setPort(465); // mailSender.setHost("smtp.163.com"); //163邮箱 // mailSender.setPort(25); mailSender.setProtocol("smtps"); mailSender.setDefaultEncoding("utf8"); Properties javaMailProperties = new Properties(); javaMailProperties.put("mail.smtp.ssl.enable", true); //javaMailProperties.put("mail.smtp.auth", true); //javaMailProperties.put("mail.smtp.starttls.enable", true); mailSender.setJavaMailProperties(javaMailProperties); } }5. login_exception.html 发送消息模板(可自定义)
你好$username,你的登陆有问题!一切都好了,运行。
登录。
发送邮件过来了。
总结来说:这个错误就是jdk1.8中的一个jce的包,安全性机制导致访问https会报错。