您现在的位置是:首页 >技术教程 >SpringBoot整合Email 邮件发送网站首页技术教程

SpringBoot整合Email 邮件发送

weixin_54501932 2025-03-14 12:01:02
简介SpringBoot整合Email 邮件发送

在开发中,经常会碰到email邮件发送的场景 如发送验证码,向客户发送邮件等等。

今天,本项目将讲解通过Springboot 发送email 邮件 普通文本邮件 ,HTML内容板式邮件 ,包含静态资源邮件,以及带附件邮件。

一.准备

创建SpringBoot项目 导入下面依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

本项目是基于页面测试的,引入了相关web依赖 ,简化实体类代码引入了lombok依赖 

     <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
二.邮件发送需要的配置

因为各大邮件都有其对应安全系统,不是项目中想用就可以用的,我们必须要拿到其对应的客户端授权码才行,拿到授权码,在项目中配置SMTP服务协议以及主机 配置账户 ,就可以在项目中使用各大邮件运营商进行发送邮件了

获取客户端授权码过程

由于国内使用163邮箱以及qq邮箱较多 所以本文中仅仅展示这两个运营商获取客户端授权码的步骤

获取163邮箱授权码

登陆163邮箱
查看服务是否开启,如未开启则选择开启

 使用当前邮箱账号绑定的手机号 发送一条短信确认发送后,确认成功后,即可拿到授权码

获取QQ邮箱授权码

登陆qq邮箱后,点击设置 选择 账户选项

拿到授权码后,就可以在我们Springboot工程中的配置文件 aplication.yml 或者properties文件中配置了 

YML配置
spring:
  mail:
    #smtp服务主机  qq邮箱则为smtp.qq.com
    host: smtp.163.com
    #服务协议
    protocol: smtp
    # 编码集
    default-encoding: UTF-8
    #发送邮件的账户
    username: xxxxxxx@163.com
    #授权码
    password: xxxxxx
    test-connection: true
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

三.代码编写
下面开始Springboot项目中发送邮件的代码编写

其实也非常简单 ,Springboot已经给我们邮件发送进行了非常好的整合了,我们只需要注入邮件发送接口 调用其中的方法,就能轻松而愉悦的进行邮件发送了!

我们只需要在任意交由Spring管理的类(例如你的service层等)下注入以下接口即可

@Autowired
private JavaMailSender mailSender;

由于每一封邮件都有固定的内容 例如 收件人信息 邮件内容 邮件标题 那么我们充分利用java面向对象的特性,我们吧邮件发送抽取为一个对象

代码采用了lombok进行简化

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ToEmail implements Serializable {

  /**
   * 邮件接收方,可多人
   */
  private String[] tos;
  /**
   * 邮件主题
   */
  private String subject;
  /**
   * 邮件内容
   */
  private String content;
}

肯定有人纳闷了,那么接收方有了,发送方呢?

发送一方,肯定就是我们自身拿到的授权码账号啊 ,我们获取账户客户端授权码其目的就是为了让代码代替我们自身邮箱 向其他邮箱发送信息而已

获取发送方账户信息

 @Value("${spring.mail.username}")
  private String from;

统一说明: R为我项目自定义的Ajax 响应,结合 RestController 或者Responsebody向前端返回统一的JSON格式数据

/**
 * 响应信息主体
 *
 * @author rbs
 */
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /** 成功 */
    public static final int SUCCESS = 200;

    /** 失败 */
    public static final int FAIL =  500;

    private int code;

    private String msg;

    private T data;

    public static <T> R<T> ok()
    {
        return restResult(null, SUCCESS, "操作成功");
    }

    public static <T> R<T> ok(T data)
    {
        return restResult(data, SUCCESS, "操作成功");
    }

    public static <T> R<T> ok(T data, String msg)
    {
        return restResult(data, SUCCESS, msg);
    }

    public static <T> R<T> fail()
    {
        return restResult(null, FAIL, "操作失败");
    }

    public static <T> R<T> fail(String msg)
    {
        return restResult(null, FAIL, msg);
    }

    public static <T> R<T> fail(T data)
    {
        return restResult(data, FAIL, "操作失败");
    }

    public static <T> R<T> fail(T data, String msg)
    {
        return restResult(data, FAIL, msg);
    }

    public static <T> R<T> fail(int code, String msg)
    {
        return restResult(null, code, msg);
    }

    private static <T> R<T> restResult(T data, int code, String msg)
    {
        R<T> apiResult = new R<>();
        apiResult.setCode(code);
        apiResult.setData(data);
        apiResult.setMsg(msg);
        return apiResult;
    }

    public int getCode()
    {
        return code;
    }

    public void setCode(int code)
    {
        this.code = code;
    }

    public String getMsg()
    {
        return msg;
    }

    public void setMsg(String msg)
    {
        this.msg = msg;
    }

    public T getData()
    {
        return data;
    }

    public void setData(T data)
    {
        this.data = data;
    }

    public static <T> Boolean isError(R<T> ret)
    {
        return !isSuccess(ret);
    }

    public static <T> Boolean isSuccess(R<T> ret)
    {
        return R.SUCCESS == ret.getCode();
    }
}

Service 


@Service
@Slf4j
public class EmailSendService {

    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String from;

    public R commonEmail(ToEmail toEmail) {
        //创建简单邮件消息
        SimpleMailMessage message = new SimpleMailMessage();
        //谁发的
        message.setFrom(from);
        //谁要接收
        message.setTo(toEmail.getTos());
        //邮件标题
        message.setSubject(toEmail.getSubject());
        //邮件内容
        message.setText(toEmail.getContent());
        try {
            mailSender.send(message);
            return R.ok(toEmail.getTos(), "发送普通邮件成功");
        } catch (MailException e) {
            log.error("发送普通邮件失败", e);
            return R.fail("普通邮件方失败");
        }
    }
}

Controller


@RestController
@RequestMapping("/email")
public class EmailSendController {

    @Autowired
    private EmailSendService emailSendService;

    /**
     * 普通邮件发送
     * @param tos
     * @param subject
     * @param content
     * @return
     */
    @RequestMapping("/common")
    public R commonEmail(String[] tos, String subject, String content) {
        ToEmail toEmail = new ToEmail(tos, subject, content);
        return emailSendService.commonEmail(toEmail);
    }

}

 我们使用ApifoxWeb版本测试

HTML邮件发送
    public R htmlEmail(ToEmail toEmail) throws MessagingException {
        //创建一个MINE消息
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper minehelper = new MimeMessageHelper(message, true);
        //谁发
        minehelper.setFrom(from);
        //谁要接收
        minehelper.setTo(toEmail.getTos());
        //邮件主题
        minehelper.setSubject(toEmail.getSubject());
        //邮件内容   true 表示带有附件或html
        minehelper.setText(toEmail.getContent(), true);
        try {
            mailSender.send(message);
            return R.ok(Arrays.toString(toEmail.getTos()) + toEmail.getContent(), "HTML邮件成功");
        } catch (MailException e) {
            log.error("HTML邮件失败", e);
            return R.fail("HTML邮件失败");
        }
    }
    @GetMapping("/html")
    public R htmlEmail(String[] tos, String subject, String content) throws MessagingException {
        ToEmail toEmail = new ToEmail(tos, subject, content);
        return emailSendService.htmlEmail(toEmail);
    }

 

含静态资源邮件发送

    public R staticEmail(ToEmail toEmail, MultipartFile multipartFile, String resId) {
        //创建一个MINE消息
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            //谁发
            helper.setFrom(from);
            //谁接收
            helper.setTo(toEmail.getTos());
            //邮件主题
            helper.setSubject(toEmail.getSubject());
            //邮件内容   true 表示带有附件或html
            //邮件内容拼接
            String content =
                    "<html><body><img width='250px' src='cid:" + resId + "'>" + toEmail.getContent()
                            + "</body></html>";
            helper.setText(content, true);
            //蒋 multpartfile 转为file
            File multipartFileToFile = MultipartFileToFile(multipartFile);
            FileSystemResource res = new FileSystemResource(multipartFileToFile);
            //添加内联资源,一个id对应一个资源,最终通过id来找到该资源
            helper.addInline(resId, res);
            mailSender.send(message);
            return R.ok(Arrays.toString(toEmail.getTos()) + toEmail.getContent(), "嵌入静态资源的邮件已经发送");
        } catch (MessagingException e) {
            log.error("嵌入静态资源的邮件发送失败", e);
            return R.fail("嵌入静态资源的邮件发送失败");
        }
    }



    /**
     * 将 multpartfile 转为file
     * @param multiFile
     * @return
     */
    private File MultipartFileToFile(MultipartFile multiFile) {
        // 获取文件名
        String fileName = multiFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = fileName.substring(fileName.lastIndexOf("."));
        // 若需要防止生成的临时文件重复,可以在文件名后添加随机码

        try {
            File file = File.createTempFile(fileName, prefix);
            multiFile.transferTo(file);
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @PostMapping("/static")
    public R htmlEmail(String[] tos, String subject, String content, MultipartFile file, String resId) throws MessagingException {
        ToEmail toEmail = new ToEmail(tos, subject, content);
        return emailSendService.staticEmail(toEmail, file, resId);
    }

发附件需要注意的是一个静态资源要对应一个ID ,ID没有讲究 别重复了就行

带附件邮件发送 
    public R enclosureEmail(ToEmail toEmail, MultipartFile multipartFile) {
        //创建一个MINE消息
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            //谁发
            helper.setFrom(from);
            //谁接收
            helper.setTo(toEmail.getTos());
            //邮件主题
            helper.setSubject(toEmail.getSubject());
            //邮件内容   true 表示带有附件或html
            helper.setText(toEmail.getContent(), true);
            File multipartFileToFile = MultipartFileToFile(multipartFile);
            FileSystemResource file = new FileSystemResource(multipartFileToFile);
            String filename = file.getFilename();
            //添加附件
            helper.addAttachment(filename, file);
            mailSender.send(message);
            return R.ok(Arrays.toString(toEmail.getTos()) + toEmail.getContent(), "附件邮件成功");
        } catch (MessagingException e) {
            log.error("附件邮件发送失败", e);
            return R.fail("附件邮件发送失败");
        }
    }
    /**
     * 附件邮件发送
     * @param tos
     * @param subject
     * @param content
     * @return
     */
    @PostMapping("/attachment")
    public R attachmentEmail(String[] tos, String subject, String content, MultipartFile file) throws MessagingException {
        ToEmail toEmail = new ToEmail(tos, subject, content);
        return emailSendService.enclosureEmail(toEmail, file);
    }

 

 END

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。