以前发送邮件可能大家需要使用javax下的mail包,自己创建session,mimemessage这种;其实spring帮我们集成了一下,让发邮件变的更简单、可靠。

1.引入对应依赖

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

2.具体使用

首先spring 的依赖常规使用方式就是配置加注入,邮件模块也不例外。先来看看配置

spring:
	mail:
    	host: 10.110.xxx.xxx   #邮件服务器地址
    	port: 25               #邮件服务器端口
    	protocol: smtp         #使用的协议
    	default-encoding: UTF-8 #默认编码
    	username: user         #这个是通过邮件服务器认证的用户名和密码,不一定是邮箱,看服务器的要求
    	password: password
    	properties:            #properties中的属性都是比较灵活可配置的,其实是javax.mail.Session中对应的配置项,可以参考对应文档
      		mail.smtp.auth: true   #如果邮件服务器需要实名需要认证开启此选项
      		mail.from: 100010@qq.com   #统一设置发件人邮箱

然后放具体代码,后面一点一点分析

邮件实体类

import lombok.*;
import org.springframework.core.io.InputStreamSource;

import javax.activation.DataSource;
import javax.mail.internet.InternetAddress;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 
 * @Description
 * @create 2022-07-12 14:23
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MailInfo {
    /**
     * 邮件标题
     */
    private String subject;
    /**
     * 邮件正文
     */
    private String content;
    /**
     * 发件时间,默认当前时间
     */
    private Date sentDate;
    /**
     * 收件人
     */
    private List<String> recipients;
    /**
     * 抄送人
     */
    private List<String> ccs;
    /**
     * 密件抄送人
     */
    private List<String> bccs;
    /**
     * 是否为邮件组
     */
    private Boolean isGroup;
    /**
     * 文件形式附件
     */
    @Setter(AccessLevel.NONE)
    private Map<String, byte[]> attachments = new HashMap<>();

    public void addAttachment(String fileName, byte[] file){ attachments.put(fileName, file); }

}

service层实现

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.cicc.op.mail.api.MailService;

import javax.activation.DataSource;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.util.ByteArrayDataSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 
 * @Description
 * @create 2022-07-26 15:39
 */
@Slf4j
@Service
public class MailController {
    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public MailResponse sendMail(MailInfo mailInfo) {
        Long id = recordLog(mailInfo);
        log.info("----------开始邮件发送------------");
        checkValue(mailInfo, id);
        //html加附件邮件发送
        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message, true);
            if(mailInfo.getIsGroup() != null && mailInfo.getIsGroup()){
                List<InternetAddress> internetAddressList = new ArrayList<>();
                mailInfo.getRecipients().forEach(to ->{
                    try {
                        internetAddressList.add(new InternetAddress(to, true));
                    } catch (AddressException e) {
                        log.error("邮件发送失败,地址信息有误", e);
                        throw new CommonMailException("邮件发送失败,地址信息有误", id, e);
                    }
                });
                mimeMessageHelper.setTo(internetAddressList.toArray(new InternetAddress[internetAddressList.size()]));
            }else {
                mimeMessageHelper.setTo(mailInfo.getRecipients().toArray(new String[mailInfo.getRecipients().size()]));
            }
            mimeMessageHelper.setSubject(mailInfo.getSubject());
            mimeMessageHelper.setText(mailInfo.getContent(), true);
            if (mailInfo.getAttachments() != null && !mailInfo.getAttachments().isEmpty()) {
                for (String fileName : mailInfo.getAttachments().keySet()) {
                    byte[] file = mailInfo.getAttachments().get(fileName);
                    if(file != null){
                    mimeMessageHelper.addAttachment(fileName, new ByteArrayResource(file));
                    } else {
                        throw new CommonMailException("不支持的附件类型", id);
                    }
                }
            }
            if (mailInfo.getSentDate() != null) {
                mimeMessageHelper.setSentDate(mailInfo.getSentDate());
            }
            if (mailInfo.getCcs() != null && !mailInfo.getCcs().isEmpty()) {
                for (String cc : mailInfo.getCcs()) {
                    mimeMessageHelper.setCc(cc);
                }
            }
            if (mailInfo.getBccs() != null && !mailInfo.getBccs().isEmpty()) {
                for (String bcc : mailInfo.getBccs()) {
                    mimeMessageHelper.setBcc(bcc);
                }
            }

            javaMailSender.send(message);
        } catch (MessagingException e) {
            log.error("邮件发送失败", e);
            throw new CommonMailException("邮件发送失败", id, e);
        }
        return new MailResponse(true, "发送成功");
    }

    private void checkValue(MailInfo mailInfo, Long id) {
        if (!StringUtils.hasText(mailInfo.getSubject())) {
            throw new CommonMailException("邮件标题不能为空", id);
        } else if (!StringUtils.hasText(mailInfo.getContent())) {
            throw new CommonMailException("邮件内容不能为空", id);
        } else if (mailInfo.getRecipients().isEmpty()) {
            throw new CommonMailException("收件人不能为空", id);
        }
    }
}

3.深入了解

首先是JavaMailSender,只要配置好spring.mail相关,就可以直接注入此Bean。

package org.springframework.mail.javamail;

import java.io.InputStream;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;

public interface JavaMailSender extends MailSender {
    MimeMessage createMimeMessage();

    MimeMessage createMimeMessage(InputStream contentStream) throws MailException;

    void send(MimeMessage mimeMessage) throws MailException;

    void send(MimeMessage... mimeMessages) throws MailException;

    void send(MimeMessagePreparator mimeMessagePreparator) throws MailException;

    void send(MimeMessagePreparator... mimeMessagePreparators) throws MailException;
}

根据接口来看,一共两个环节,创建MimeMessage对象(里面是邮件相关属性),然后send发送。

具体的实现类JavaMailSenderImpl截取

 public synchronized Session getSession() {
        if (this.session == null) {
            this.session = Session.getInstance(this.javaMailProperties);
        }

        return this.session;
    }


public MimeMessage createMimeMessage() {
        return new SmartMimeMessage(this.getSession(), this.getDefaultEncoding(), this.getDefaultFileTypeMap());
    }

    public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
        try {
            return new MimeMessage(this.getSession(), contentStream);
        } catch (Exception var3) {
            throw new MailParseException("Could not parse raw MIME content", var3);
        }
    }

getSession方法可以看出,spring是对javax实现的邮件发送进行了一层封装,还是用的session,之前的properties配置也是在这里给到session,然后通过session创建MimeMessage。直接操作MimeMessage写入也可以,但是一个是不太方便,一个是不能发送附件,所以借助MimeMessageHelper来实现。

public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart) throws MessagingException {
        this(mimeMessage, multipart, (String)null);
    }

    public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, @Nullable String encoding) throws MessagingException {
        this(mimeMessage, multipart ? 3 : 0, encoding);
    }

    public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
        this(mimeMessage, multipartMode, (String)null);
    }

    public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode, @Nullable String encoding) throws MessagingException {
        this.encodeFilenames = false;
        this.validateAddresses = false;
        this.mimeMessage = mimeMessage;
        this.createMimeMultiparts(mimeMessage, multipartMode);
        this.encoding = encoding != null ? encoding : this.getDefaultEncoding(mimeMessage);
        this.fileTypeMap = this.getDefaultFileTypeMap(mimeMessage);
    }

使用MimeMessageHelper的时候注意三个点,

  1. 一个是multipart字段,如果要进行附件传输的话,这个要设置为true,还有就是如果配置文件中没有设置默认字符集,然后发送邮件出现乱码情况,可以在encoding设置编码。

  2. 还有一个是setText方法,如果需要发送的邮件正文不是简单的文本格式,而是使用了模板或者有图片表格等内容,需要在setText方法设置strict属性为true

  3. 邮件的附件如果需要http请求进行传输,但是又不方便使用Multipartfile类型,可以使用byte数组发送,如果是JSON需要注意序列化时编码问题;直接使用form-data也可以。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐