SpringBoot快速实现发送邮件

1、添加发送邮件需要的maven依赖

在 pom.xml 配置文件中加入 spring-boot-starter-mail 依赖。

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2、添加邮箱配置参数

如其他自动化配置模块一样,在完成了依赖引入之后,只需要在application.properties中配置相应的属性内容。

下面我们以QQ邮箱为例,注意替换成自己的发件邮箱和授权码

xml 复制代码
#邮箱配置
#平台地址,这里用的是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

java 复制代码
package com.lcz.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;
 
/**
 * 发送邮件工具类 MailUtil
 *
 * @author lcz
 * @date 2024/3/22 15:00
 */
 
@Service
public class EmailUtil implements EmailService
{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
    //Spring Boot 提供了一个发送邮件的简单抽象,使用的是下面这个接口,这里直接注入即可使用
    @Autowired
    private JavaMailSender mailSender;
 
    // 配置文件中我的qq邮箱
    @Value("${spring.mail.from}")
    private String from;
 
    /**
     * 简单文本邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    @Override
    public void sendSimpleMail(String to, String subject, String content) {
        //创建SimpleMailMessage对象
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件发送人
        message.setFrom(from);
        //邮件接收人
        message.setTo(to);
        //邮件主题
        message.setSubject(subject);
        //邮件内容
        message.setText(content);
        //发送邮件
        mailSender.send(message);
    }
 
    /**
     * html邮件
     * @param to 收件人,多个时参数形式 :"xxx@xxx.com,xxx@xxx.com,xxx@xxx.com"
     * @param subject 主题
     * @param content 内容
     */
    @Override
    public void sendHtmlMail(String to, String subject, String content) {
        //获取MimeMessage对象
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper;
        try {
            messageHelper = new MimeMessageHelper(message, true);
            //邮件发送人
            messageHelper.setFrom(from);
            //邮件接收人,设置多个收件人地址
            InternetAddress[] internetAddressTo = InternetAddress.parse(to);
            messageHelper.setTo(internetAddressTo);
            //messageHelper.setTo(to);
            //邮件主题
            message.setSubject(subject);
            //邮件内容,html格式
            messageHelper.setText(content, true);
            //发送
            mailSender.send(message);
            //日志信息
            logger.info("邮件已经发送。");
        } catch (Exception e) {
            logger.error("发送邮件时发生异常!", e);
        }
    }
 
    /**
     * 带附件的邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     * @param filePath 附件
     */
    @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接口

java 复制代码
package com.lcz.demo.mail;
 
/**
 * @author lcz
 */
 
public interface EmailService {
    /**
     * 发送文本邮件
     *
     * @param to      收件人
     * @param subject 主题
     * @param content 内容
     */
    void sendSimpleMail(String to, String subject, String content);
 
    /**
     * 发送HTML邮件
     *
     * @param to      收件人
     * @param subject 主题
     * @param content 内容
     */
    public void sendHtmlMail(String to, String subject, String content);
 
    /**
     * 发送带附件的邮件
     *
     * @param to       收件人
     * @param subject  主题
     * @param content  内容
     * @param filePath 附件
     */
    public void sendAttachmentsMail(String to, String subject, String content, String filePath);
}

(3)单元测试

java 复制代码
package com.lcz.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)发邮件方法代码

java 复制代码
    /**
     * 发送html邮件
     *
     * @param to
     * @param cc
     * @param subject
     * @param content
     */
    public void sendHtmlMail(String[] to, String[] cc, String subject, String content) {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = null;
        try {
            //true表示需要创建一个multipart message
            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)从异常获取无效地址的方法代码

java 复制代码
    /**
     * 从异常获取无效地址
     * @param e
     * @return
     */
    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;
    }
 
    /**
     * 将Address[]转成String[]
     * @param address
     * @return
     */
    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)过滤发件人中无效地址的方法代码

java 复制代码
    /**
     * 过滤数组source,规则为数组元素包含了数组filter中的元素则去除
     *
     * @param source
     * @param filter
     * @return
     */
    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);
    }
相关推荐
骑士雄师2 分钟前
Java 泛型中级面试题及答案
java·开发语言·面试
曾令胜6 小时前
excel导出使用arthas动态追踪方法调用耗时后性能优化的过程
spring·性能优化·excel
.格子衫.6 小时前
Spring Boot 原理篇
java·spring boot·后端
多云几多6 小时前
Yudao单体项目 springboot Admin安全验证开启
java·spring boot·spring·springbootadmin
摇滚侠8 小时前
Spring Boot 3零基础教程,Spring Intializer,笔记05
spring boot·笔记·spring
Jabes.yang8 小时前
Java求职面试实战:从Spring Boot到微服务架构的技术探讨
java·数据库·spring boot·微服务·面试·消息队列·互联网大厂
聪明的笨猪猪8 小时前
Java Redis “高可用 — 主从复制”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
兮动人8 小时前
Spring Bean耗时分析工具
java·后端·spring·bean耗时分析工具
MESSIR229 小时前
Spring IOC(控制反转)中常用注解
java·spring
摇滚侠9 小时前
Spring Boot 3零基础教程,Demo小结,笔记04
java·spring boot·笔记