spring已经集成了邮件模块,使用JavaMailSender进行邮件发送,让发邮件变的更简单、可靠。
1.引入对应依赖
*build.gradle*
dependencies {
implementation "org.springframework.boot:spring-boot-starter-mail"
}
*pom.xml*
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.yaml配置
spring:
mail:
host: xxx #邮件服务器地址
port: 80 #邮件服务器端口
protocol: smtp #使用的协议
default-encoding: UTF-8 #默认编码
username: user #这个是通过邮件服务器认证的用户名和密码,不一定是邮箱,看服务器的要求
password: password
properties: #properties中的属性都是比较灵活可配置的,其实是javax.mail.Session中对应的配置项,可以参考对应文档
mail:
from: 1@qq.com #统一设置发件人邮箱
smtp:
auth: true #如果邮件服务器需要实名需要认证开启此选项
starttls:
enable: true
required: false
socketFactory:
class: javax.net.ssl.SSLSocketFactory
default-encoding: utf-8
定义邮件实体类
/**
* 邮件实体类
*/
@Getter
@Setter
@ToString
public class MimeEmail implements Serializable {
private static final long serialVersionUID = 4006574481733672739L;
/**
* 主题
*/
private String subject;
/**
* 主题内容
*/
private String content;
/**
* html主题内容
*/
private String html;
/**
* 收件人, 多个邮箱以','分隔, example = "xx@test.com,zz@test.com"
*/
private String receivers;
/**
* 抄送人, 多个邮箱以','分隔, example = "xx@test.com,zz@test.com"
*/
private String cc;
/**
* 附件名字
*/
private String attachmentName;
/**
* 获取附件的输入流
*/
private transient InputStreamSource inputStreamSource;
}
邮件发送
//发送邮件
MimeEmail mimeEmail = new MimeEmail();
mimeEmail.setSubject(param.getTitle());
mimeEmail.setContent(StrUtil.format(param.getContent(), cn.hutool.core.date.DateUtil.format(new Date(),
YYYY_MM_DD_HH_MM)));
mimeEmail.setReceivers(param.getEmail());
mimeEmail.setCc(param.getCc());
try {
log.info("邮件参数:{}", mimeEmail.toString());
mailService.sendHtmlMails(mimeEmail, map);
} catch (Exception e) {
log.error("send email exception:{}", e.getMessage(), e);
}
service层实现
@Service
@Slf4j
public class MailService {
@Resource
private JavaMailSender javaMailSender;
@Value("${spring.mail.username}")
private String from;
public void sendHtmlMail(MimeEmail mimeEmail) throws Exception {
//创建一个MINE消息
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper mineHelper;
try {
//创建一个MimeMessageHelper对象
mineHelper = new MimeMessageHelper(message, true);
//谁发
mineHelper.setFrom(from);
log.info("==========="+from+"============");
//谁要接收
mineHelper.setTo(mimeEmail.getReceivers().split(CommonConstant.COMMENT_SPLIT));
//抄送人
if (mimeEmail.getCc() != null && !"".equals(mimeEmail.getCc())) {
mineHelper.setCc(mimeEmail.getCc().split(CommonConstant.COMMENT_SPLIT));
}
//邮件主题
mineHelper.setSubject(mimeEmail.getSubject());
//邮件内容 true 表示带有附件或html
mineHelper.setText(mimeEmail.getContent(), true);
if (mimeEmail.getAttachmentName()!=null && !ObjectUtil.isEmpty(
mimeEmail.getInputStreamSource())) {
//添加附件
mineHelper.addAttachment(mimeEmail.getAttachmentName(), new ByteArrayResource(
IOUtils.toByteArray(mimeEmail.getInputStreamSource().getInputStream())));
}
} catch (IOException | MessagingException e) {
throw new Exception("init message helper exception", e);
}
javaMailSender.send(message);
}
/**
* 发送多个附件
* @param mimeEmail
* @throws Exception
*/
public void sendHtmlMails(MimeEmail mimeEmail, Map<String, InputStreamSource> map) throws Exception {
//创建一个MINE消息
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper mineHelper;
try {
//创建一个MimeMessageHelper对象
mineHelper = new MimeMessageHelper(message, true);
//谁发
mineHelper.setFrom(from);
log.info("==========="+from+"============");
//谁要接收
mineHelper.setTo(mimeEmail.getReceivers().split(CommonConstant.COMMENT_SPLIT));
//抄送人
if (mimeEmail.getCc() != null && !"".equals(mimeEmail.getCc())) {
mineHelper.setCc(mimeEmail.getCc().split(CommonConstant.COMMENT_SPLIT));
}
//邮件主题
mineHelper.setSubject(mimeEmail.getSubject());
//邮件内容 true 表示带有附件或html
mineHelper.setText(mimeEmail.getContent(), true);
if(map.size() > 0) {
for (String attachmentName : map.keySet()) {
//添加附件
mineHelper.addAttachment(attachmentName, new ByteArrayResource(
IOUtils.toByteArray(map.get(attachmentName).getInputStream())));
}
}
} catch (IOException | MessagingException e) {
throw new Exception("init message helper exception", e);
}
javaMailSender.send(message);
}
}
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;
/**
* Extended {@link org.springframework.mail.MailSender} interface for JavaMail,
* supporting MIME messages both as direct arguments and through preparation
* callbacks. Typically used in conjunction with the {@link MimeMessageHelper}
* class for convenient creation of JavaMail {@link MimeMessage MimeMessages},
* including attachments etc.
*
* <p>Clients should talk to the mail sender through this interface if they need
* mail functionality beyond {@link org.springframework.mail.SimpleMailMessage}.
* The production implementation is {@link JavaMailSenderImpl}; for testing,
* mocks can be created based on this interface. Clients will typically receive
* the JavaMailSender reference through dependency injection.
*
* <p>The recommended way of using this interface is the {@link MimeMessagePreparator}
* mechanism, possibly using a {@link MimeMessageHelper} for populating the message.
* See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
*
* <p>The entire JavaMail {@link javax.mail.Session} management is abstracted
* by the JavaMailSender. Client code should not deal with a Session in any way,
* rather leave the entire JavaMail configuration and resource handling to the
* JavaMailSender implementation. This also increases testability.
*
* <p>A JavaMailSender client is not as easy to test as a plain
* {@link org.springframework.mail.MailSender} client, but still straightforward
* compared to traditional JavaMail code: Just let {@link #createMimeMessage()}
* return a plain {@link MimeMessage} created with a
* {@code Session.getInstance(new Properties())} call, and check the passed-in
* messages in your mock implementations of the various {@code send} methods.
*
* @author Juergen Hoeller
* @since 07.10.2003
* @see javax.mail.internet.MimeMessage
* @see javax.mail.Session
* @see JavaMailSenderImpl
* @see MimeMessagePreparator
* @see MimeMessageHelper
*/
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) {
this(mimeMessage, null);
}
public MimeMessageHelper(MimeMessage mimeMessage, @Nullable String encoding) {
this.mimeMessage = mimeMessage;
this.encoding = (encoding != null ? encoding : getDefaultEncoding(mimeMessage));
this.fileTypeMap = getDefaultFileTypeMap(mimeMessage);
}
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart) throws MessagingException {
this(mimeMessage, multipart, null);
}
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, @Nullable String encoding)
throws MessagingException {
this(mimeMessage, (multipart ? MULTIPART_MODE_MIXED_RELATED : MULTIPART_MODE_NO), encoding);
}
public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
this(mimeMessage, multipartMode, null);
}
public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode, @Nullable String encoding)
throws MessagingException {
this.mimeMessage = mimeMessage;
createMimeMultiparts(mimeMessage, multipartMode);
this.encoding = (encoding != null ? encoding : getDefaultEncoding(mimeMessage));
this.fileTypeMap = getDefaultFileTypeMap(mimeMessage);
}
使用MimeMessageHelper注意点:
- 一是multipart字段,如果要进行附件传输的话,这个要设置为true,如果配置文件中没有设置默认字符集,然后发送邮件出现乱码情况,可以在encoding设置编码。
- 还有setText方法,如果需要发送的邮件正文不是简单的文本格式,而是使用了模板或者有图片表格等内容,需要在setText方法设置strict属性为true。
- 邮件的附件如果需要http请求进行传输,但是又不方便使用Multipartfile类型,可以使用byte数组发送,如果是JSON需要注意序列化时编码问题;直接使用form-data也可以。