SpringBootspringboot 与 Email 邮箱

Posted 技术能量站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBootspringboot 与 Email 邮箱相关的知识,希望对你有一定的参考价值。

学过计算机网络后,我们都知道,发送邮件就需要使用某种协议。比如什么SMTP、IMAP、POP3.

1. 基础知识

  • 什么是SMTP:SMTP全称为Simple Mail Transfer Protocol(简单邮件传输协议),它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP认证要求必须提供账号和密码才能登陆服务器,其设计目的在于避免用户受到垃圾邮件的侵扰。
  • 什么是IMAP:IMAP全称为Internet Message Access Protocol(互联网邮件访问协议),IMAP允许从邮件服务器上获取邮件的信息、下载邮件等。IMAP与POP类似,都是一种邮件获取协议。
  • 什么是POP3:POP3全称为Post Office Protocol 3(邮局协议),POP3支持客户端远程管理服务器端的邮件。POP3常用于“离线”邮件处理,即允许客户端下载服务器邮件,然后服务器上的邮件将会被删除。目前很多POP3的邮件服务器只提供下载邮件功能,服务器本身并不删除邮件,这种属于改进版的POP3协议。

2. 进阶知识

2.1 什么是JavaMailSender和JavaMailSenderImpl?

javaMailSender和JavaMailSenderImpl是Spring官方提供的集成邮件服务的接口和实现类,以简单高效的设计著称,目前是Java后端发送邮件和集成邮件服务的主流工具。

如何通过JavaMailSenderImpl发送邮件?非常简单,直接在业务类注入JavaMailSenderImpl并调用send方法发送邮件。其中简单邮件可以通过SimpleMailMessage来发送邮件,而复杂的邮件(例如添加附件)可以借助MimeMessageHelper来构建MimeMessage发送邮件。例如:

    @Autowired
    private JavaMailSenderImpl mailSender;
 
    public void sendMail() throws MessagingException 
        //简单邮件
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom("jiuyue@163.com");
        simpleMailMessage.setTo("September@qq.com");
        simpleMailMessage.setSubject("BugBugBug");
        simpleMailMessage.setText("一杯茶,一根烟,一个Bug改一天");
        mailSender.send(simpleMailMessage);
 
        //复杂邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
        messageHelper.setFrom("jiuyue@163.com");
        messageHelper.setTo("September@qq.com");
        messageHelper.setSubject("BugBugBug");
        messageHelper.setText("一杯茶,一根烟,一个Bug改一天!");
        messageHelper.addInline("bug.gif", new File("xx/xx/bug.gif"));
        messageHelper.addAttachment("bug.docx", new File("xx/xx/bug.docx"));
        mailSender.send(mimeMessage);
    

为什么JavaMailSenderImpl 能够开箱即用?所谓开箱即用其实就是基于官方内置的自动配置,翻看源码可知晓邮件自动配置类(MailSenderPropertiesConfiguration) 为上下文提供了邮件服务实例(JavaMailSenderImpl)。具体源码如下:
 

@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration 
    private final MailProperties properties;
    MailSenderPropertiesConfiguration(MailProperties properties) 
        this.properties = properties;
    
    @Bean
    @ConditionalOnMissingBean
    public JavaMailSenderImpl mailSender() 
        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        applyProperties(sender);
        return sender;
    

其中MailProperties是关于邮件服务器的配置信息,具体源码如下:

@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties 
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private String host;
    private Integer port;
    private String username;
    private String password;
    private String protocol = "smtp";
    private Charset defaultEncoding = DEFAULT_CHARSET;
    private Map<String, String> properties = new HashMap<>();

3. 如何使用

3.1 开启邮件服务

登陆网易163邮箱,在设置中打开并勾选POP3/SMTP/IMAP服务,然后会得到一个授权码,这个邮箱和授权码将用作登陆认证

3.2 配置邮件服务

在项目中添加spring-boot-starter-mail依赖

        <!--邮件模块依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

在application.yml添加如下配置:

# tomcat port
server.port=8088
 
# thymeleaf
 
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.mode=html
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false
 
# datasource
#druid数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/db_blog?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1111
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 
# mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
 
#关闭默认的favicon,将自己的图标放在static下显示自己的图标
spring.mvc.favicon.enabled=false
 
#email
spring.mail.host=smtp.163.com
spring.mail.username=your_email@163.com
spring.mail.password=your_password
spring.mail.port=465
#设置为SSL协议
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.from=m19978528200@163.com

通过前面的进阶知识,我们知道在发送邮件前,需要先构建 SimpleMailMessage或 MimeMessage邮件信息类来填写邮件标题、邮件内容等信息,最后提交给JavaMailSenderImpl发送邮件,这样看起来没什么问题,也能实现既定目标,但在实际使用中会出现大量零散和重复的代码,还不便于保存邮件到数据库。

那么如何优雅的发送邮件呢?应该屏蔽掉这些构建信息和发送邮件的细节,不管是简单还是复杂邮件,都可以通过统一的API来发送邮件。例如: mailService.send(mailVo)

例如通过邮件信息类(MailVo) 来保存发送邮件时的邮件主题、邮件内容等信息 :
 

@Data
public class MailVo 
    private String id;//邮件id
    private String from;//邮件发送人
    private String to;//邮件接收人
    private String subject;//邮件主题
    private String text;//邮件内容
    private Date   sentDate;//发送时间
    private String cc; //抄送
    private String bcc; //密送
    private String status; //状态
    private String error; //报错信息
    @JsonIgnore
    private MultipartFile[] multipartFiles;//邮件附件

3.3 发送邮件和附件

除了发送邮件之外,还包括检测邮件和保存邮件等操作,例如:检测邮件 checkMail(); 校验合法性:邮件收信人、邮件主题和邮件内容均为必填项,缺一不可。

  • 发送邮件 sendMimeMail(); 首先通过MimeMessageHelper来解析MailVo和构建MimeMessage,调用JavaMailSenderImpl快速发送邮件。
  • 保存邮件 sendMimeMail(); 最后将邮件保存到数据库,便于统计和追查邮件问题。

业务类 MailService 的具体源码如下:


@Service
public  class MailServiceImpl implements MailService 
    @Autowired
    private JavaMailSenderImpl mailSender;//注入邮件工具类
    @Async
    @Override
    public MailVo sendMail(MailVo mailVo) 
        try 
            checkMail(mailVo); //1.检测邮件
            sendMimeMail(mailVo); //2.发送邮件
            return saveMail(mailVo); //3.保存邮件
         catch (Exception e) 
            mailVo.setStatus("fail");
            mailVo.setError(e.getMessage());
            return mailVo;
        
    
 
    //检测邮件信息类
    private void checkMail(MailVo mailVo) 
        if (StringUtils.isEmpty(mailVo.getTo())) 
            throw new RuntimeException("邮件收信人不能为空");
        
        if (StringUtils.isEmpty(mailVo.getSubject())) 
            throw new RuntimeException("邮件主题不能为空");
        
        if (StringUtils.isEmpty(mailVo.getText())) 
            throw new RuntimeException("邮件内容不能为空");
        
    
 
    //构建复杂邮件信息类
    private void sendMimeMail(MailVo mailVo) 
        try 
            MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);//true表示支持复杂类型
            //mailVo.setFrom(getMailSendFrom());//邮件发信人从配置项读取
            messageHelper.setFrom(mailVo.getFrom());//邮件发信人
            messageHelper.setTo(mailVo.getTo().split(","));//邮件收信人
            messageHelper.setSubject(mailVo.getSubject());//邮件主题
            messageHelper.setText(mailVo.getText());//邮件内容
            if (!StringUtils.isEmpty(mailVo.getCc())) //抄送
                messageHelper.setCc(mailVo.getCc().split(","));
            
            if (!StringUtils.isEmpty(mailVo.getBcc())) //密送
                messageHelper.setCc(mailVo.getBcc().split(","));
            
            if (mailVo.getMultipartFiles() != null) //添加邮件附件
                for (MultipartFile multipartFile : mailVo.getMultipartFiles()) 
                    messageHelper.addAttachment(multipartFile.getOriginalFilename(), multipartFile);
                
            
            if (StringUtils.isEmpty(mailVo.getSentDate())) //发送时间
                mailVo.setSentDate(new Date());
                messageHelper.setSentDate(mailVo.getSentDate());
            
            mailSender.send(messageHelper.getMimeMessage());//正式发送邮件
            mailVo.setStatus("ok");
         catch (Exception e) 
            throw new RuntimeException(e);//发送失败
        
    
 
    //保存邮件
    private MailVo saveMail(MailVo mailVo) 
 
        //将邮件保存到数据库..
 
        return mailVo;
    
 
    //获取邮件发信人
    public String getMailSendFrom() 
        return mailSender.getJavaMailProperties().getProperty("from");
    
 

引用方式也很方便


        //发送邮件
        MailVo mailVo = new MailVo();
        mailVo.setFrom("jiyue@163.com");
        mailVo.setTo("789654@qq.com");
        mailVo.setSubject("收到您朋友【"+author+"】的信件,Ta的邮箱:"+mail);
        mailVo.setText(text);
        mailService.sendMail(mailVo);

上面的代码,可以在本地运行,也可以部署到云服务器上运行。没有什么问题,不会出现在本地运行发布评论的时候可以调用邮件服务给你发送邮件,而部署到云服务器却接收不到邮件的情况

为什么之前我在本地运行时候,可以接收到邮件,而发布到服务器上却没有接收到邮件呢?

  • 阿里云服务器禁用了25端口,所以改为465端口采用SSL协议传输邮件

3.4 使用thymeleaf模板

  • 依赖
        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
  • 服务接口
   /**
     * 使用thymeleaf模板
     * @param from
     * @param to
     * @param subject
     * @param context
     */
    public void sendHtmlMail(String from,String to ,String subject,String context)
        try 
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
            mimeMessageHelper.setFrom(from);
            mimeMessageHelper.setTo(to);
            mimeMessageHelper.setText(context);
            mimeMessageHelper.setSubject(subject);
            javaMailSender.send(mimeMessage);
         catch (MessagingException e) 
            e.printStackTrace();
        
    
  • 在resources/templates目录下创建mailtemplate.html文件,代码如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org:">
<head>
    <meta charset="UTF-8">
    <title>邮件</title>
</head>
<body>
 
<div>
    邮件激活
</div>
<span th:text="$username"></span>
<a href="http://www.baidu.com">核对无误请点击本链接激活邮箱</a>
</body>
</html>
  • 测试
   @Autowired
   private TemplateEngine templateEngine;
 
    public void sendHtmlMailThymeleaf()
        Context context = new Context();
        context.setVariable("username","cyc");
        String mail = templateEngine.process("mailtemplate.html",context);
        mailService.sendHtmlMail("cyc@qq.com","zxc@qq.com","标题",mail);
    

 

相关文章

  1. 使用SpringBoot集成邮件模块
  2. SpringBoot整合mail邮件发送
  3. SpringBoot整合Email 邮件发送
  4. SpringBoot发送Html格式邮件

 

开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于SpringBootspringboot 与 Email 邮箱的主要内容,如果未能解决你的问题,请参考以下文章

SpringBootSpringBoot 与 Swagger整合(三十)

SpringBootspringboot 与 Email 邮箱

SpringBootspringboot 与 单元测试经验

SpringBootSpringBoot Web开发

SpringBootSpringBoot 整合RabbitMQ(二十)

springbootSpringBoot任务