前言:Spring提供了非常好用的JavaMailSender
接口实现邮件发送。由于SpringBoot的Starter模块也为此提供了自动化配置,所以在引入了spring-boot-starter-mail
依赖之后,会根据配置文件中的内容去创建JavaMailSender
实例,因此我们可以直接在需要使用的地方直接@Autowired
来引入邮件发送对象。
SpringBoot中发送邮件具体的使用步骤如下
1、添加Starter模块依赖
2、添加Spring Boot邮箱配置(QQ/网易163/Gmail)
3、调用JavaMailSender接口发送邮件
1、添加发送邮件需要的maven依赖
在 pom.xml 配置文件中加入 spring-boot-starter-mail 依赖。
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
|
2、添加邮箱配置参数
如其他自动化配置模块一样,在完成了依赖引入之后,只需要在**application.properties
**中配置相应的属性内容。
下面我们以QQ邮箱为例,注意替换成自己的发件邮箱和授权码,关于如何获取授权码请点击这里:获取QQ邮箱授权码
1 2 3 4 5 6 7 8 9 10 11
| #邮箱配置 #平台地址,这里用的是qq邮箱,使用其他邮箱请更换 spring.mail.host=smtp.qq.com #端口号 spring.mail.port=XXX #发送邮件的邮箱地址:改成自己的邮箱 spring.mail.username=xxxxxxxxxxx #发送短信后它给你的授权码 填写到这里 spring.mail.password=xxxxxxxxxxxx #与发件邮箱一致 spring.mail.from=xxxxxxxxxxx
|
3、调用JavaMailSender接口发送邮件
由于Spring Boot的starter模块提供了自动化配置,所以在引入了spring-boot-starter-mail依赖之后,会根据配置文件中的内容去创建JavaMailSender实例,因此我们可以直接在需要使用的地方直接@Autowired来引入邮件发送对象。
(1)发送邮件工具类 MailUtil
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 115 116 117
| package com.hs.demo.mail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.FileSystemResource; import org.springframework.mail.SimpleMailMessage; 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.io.File;
@Service public class EmailUtil implements EmailService { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private JavaMailSender mailSender; @Value("${spring.mail.from}") private String from;
@Override public void sendSimpleMail(String to, String subject, String content) { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from); message.setTo(to); message.setSubject(subject); message.setText(content); mailSender.send(message); }
@Override public void sendHtmlMail(String to, String subject, String content) { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper messageHelper; try { messageHelper = new MimeMessageHelper(message, true); messageHelper.setFrom(from); InternetAddress[] internetAddressTo = InternetAddress.parse(to); messageHelper.setTo(internetAddressTo); message.setSubject(subject); messageHelper.setText(content, true); mailSender.send(message); logger.info("邮件已经发送。"); } catch (Exception e) { logger.error("发送邮件时发生异常!", e); } }
@Override public void sendAttachmentsMail(String to, String subject, String content, String filePath) { MimeMessage message = mailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); FileSystemResource file = new FileSystemResource(new File(filePath)); String fileName = filePath.substring(filePath.lastIndexOf(File.separator)); helper.addAttachment(fileName, file); mailSender.send(message); logger.info("邮件已经发送。"); } catch (Exception e) { logger.error("发送邮件时发生异常!", e); } } }
|
(2)EmailService接口
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
| package com.cernet.notice.mail;
public interface EmailService {
void sendSimpleMail(String to, String subject, String content);
public void sendHtmlMail(String to, String subject, String content);
public void sendAttachmentsMail(String to, String subject, String content, String filePath); }
|
(3)单元测试
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
| package com.hs.demo; import com.hs.demo.mail.EmailService; import com.hs.demo.mail.EmailUtil; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class SendEmailApplicationTests {
@Autowired private EmailUtil mailService;
@Test public void sendmail() { mailService.sendSimpleMail("xxx@qq.com","主题:你好普通邮件","内容:第一封邮件"); } @Test public void sendmailHtml(){ mailService.sendHtmlMail("xxx@qq.com","主题:你好html邮件","<h1>内容:第一封html邮件</h1>"); } }
|
4、常见的Web网站注册,邮箱点击链接验证激活如何实现?
Java实现用户注册邮箱激活验证
功能:通过邮箱注册账号,注册成功会向邮箱发送激活邮件。提示用户登录邮箱进行账户激活,方可使用账号。
流程:本质上就是向user表里新增一条数据,user表中应有一个code字段存放随机串。code在添加用户时随机生成(uuid),发送邮件时把code值带到邮件链接中用于查找唯一账户,然后判断用户状态,进行激活。
5、存在失效邮箱地址导致JavaMailSender群发失败
问题描述
进行邮件群发,使用的是SpringBoot的org.springframework.mail.javamail.JavaMailSender。在提测过程中发现,如果待发送的邮件地址列表中存在一个无效的地址【该地址是一个合法的邮件地址,但是是无效地址,如:BingDwenDwen@163.com,它是一个合法的邮件地址,但却是无效的地址】,则会导致所有邮件发送失败。
报错异常和问题分析
异常:org.springframework.mail.MailSendException: Failed messages: javax.mail.SendFailedException: Invalid Addresses
分析:可能是收件人或抄送人列表存在无效的地址
坑:不能直接catch到SendFailedException
解决方案
遍历异常,提取无效地址后过滤原地址列表再次发送
(1)发邮件方法代码
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
|
public void sendHtmlMail(String[] to, String[] cc, String subject, String content) { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = null; try { helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setCc(cc); helper.setSubject(subject); helper.setText(content, true); mailSender.send(message); logger.info("sendHtmlMail success.from:" + from); } catch (Throwable e) { logger.error("sendHtmlMail fail.", e); String[] invalid = getInvalidAddresses(e); if (invalid != null) { sendHtmlMail(filterByArray(to, invalid), filterByArray(cc, invalid), subject, content); } } }
|
(2)从异常获取无效地址的方法代码
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
|
private static String[] getInvalidAddresses(Throwable e) { if (e == null) { return null; } if (e instanceof MailSendException) { System.out.println("e instanceof SendFailedException"); Exception[] exceptions = ((MailSendException) e).getMessageExceptions(); for (Exception exception : exceptions) { if (exception instanceof SendFailedException) { return getStringAddress(((SendFailedException) exception).getInvalidAddresses()); } } } if (e instanceof SendFailedException) { return getStringAddress(((SendFailedException) e).getInvalidAddresses()); } return null; }
private static String[] getStringAddress(Address[] address) { List<String> invalid = new ArrayList<>(); for (Address a : address) { String aa = ((InternetAddress) a).getAddress(); if (!StringUtils.isEmpty(aa)) { invalid.add(aa); } } return invalid.stream().distinct().toArray(String[]::new); }
|
(3)过滤发件人中无效地址的方法代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
private static String[] filterByArray(String[] source, String[] filter) { List<String> result = new ArrayList<>(); for (String s : source) { boolean contains = false; for (String f : filter) { if (s.contains(f)) { contains = true; break; } } if (!contains) { result.add(s); } } return result.stream().toArray(String[]::new); }
|
6、日志没有报任何异常返回发送成功,收件方却没有实际收到邮件
你可以登录的你的发送账号,查看邮件系统退信原因。试着检查你公司的企业邮箱服务器的反垃圾邮件规则是否拦截了该邮件。
比如你的发送内容是一段小说,就容易被检测为垃圾邮件被拒绝投递
参考链接:
群发邮件报:javax.mail.SendFailedException: Invalid Addresses解决办法
springboot发送邮件
java实现用户注册邮箱激活验证
Java邮箱地址无效导致群发邮件失败
java.net.UnknownHostException: mail.cernet.com. Failed messages: com.sun.mail.util.MailConnectException: Couldn’t connect to host, port: mail.cernet.com, 25; timeout -1
Java发送邮件必带超时时间配置 - 知乎
JavaMail 发送邮件阻塞问题解决——设置 smtp 超时时间