SpringBoot:邮件发送

        官网文档:39. Sending Email (spring.io)。

Sending Email

Spring框架提供了JavaMailSender实例,用于发送邮件。

如果SpringBoot项目中包含了相关的启动器,那么就会自动装配一个Bean实例到项目中。

        在SpringBoot项目中引入如下Email启动器,

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

核心接口和类

核心接口:MailSender

        org.springframework.mail是邮件发送依赖的顶级包,其中提供了邮件发送的核心接口MailSender,该接口提供了两个方法,分别用于指定逐个邮件发送、批量邮件发送。

package org.springframework.mail;/*** This interface defines a strategy for sending simple mails. Can be* implemented for a variety of mailing systems due to the simple requirements.* For richer functionality like MIME messages, consider JavaMailSender.** <p>Allows for easy testing of clients, as it does not depend on JavaMail's* infrastructure classes: no mocking of JavaMail Session or Transport necessary.*/
public interface MailSender {/*** Send the given simple mail message.-发送简单邮件* @param simpleMessage the message to send* @throws MailParseException in case of failure when parsing the message* @throws MailAuthenticationException in case of authentication failure* @throws MailSendException in case of failure when sending the message*/void send(SimpleMailMessage simpleMessage) throws MailException;/*** Send the given array of simple mail messages in batch.-批量发送一组简单邮件* @param simpleMessages the messages to send* @throws MailParseException in case of failure when parsing a message* @throws MailAuthenticationException in case of authentication failure* @throws MailSendException in case of failure when sending a message*/void send(SimpleMailMessage... simpleMessages) throws MailException;}

        可以看到,其实JavaMailSender接口也作为它的子接口存在,并且内置了一个实现类JavaMailSenderImpl可以供我们直接使用。

邮件消息接口:MailMessage

        邮件消息接口:规定一封电子邮件对应的组成元素,内置了简单邮件消息和媒体邮件消息两个实现子类。

package org.springframework.mail;import java.util.Date;/*** This is a common interface for mail messages, allowing a user to set key* values required in assembling a mail message, without needing to know if* the underlying message is a simple text message or a more sophisticated* MIME message.** <p>Implemented by both SimpleMailMessage and MimeMessageHelper,* to let message population code interact with a simple message or a* MIME message through a common interface.*/
public interface MailMessage {void setFrom(String from) throws MailParseException;void setReplyTo(String replyTo) throws MailParseException;void setTo(String to) throws MailParseException;void setTo(String... to) throws MailParseException;void setCc(String cc) throws MailParseException;void setCc(String... cc) throws MailParseException;void setBcc(String bcc) throws MailParseException;void setBcc(String... bcc) throws MailParseException;void setSentDate(Date sentDate) throws MailParseException;void setSubject(String subject) throws MailParseException;void setText(String text) throws MailParseException;}

简单邮件对象:SimpleMailMessage 

        可以用来囊括简单邮件信息的类是SimpleMailMessage类,邮件主体内容以简单文本形式为主。

A simple value object that encapsulates the properties of a simple mail such as from and to (plus many others) is the SimpleMailMessage class. 

        该类的源码如下, 

package org.springframework.mail;import java.io.Serializable;
import java.util.Date;import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;/*** Models a simple mail message, including data such as the from, to, cc, subject,* and text fields.** <p>Consider {@code JavaMailSender} and JavaMail {@code MimeMessages} for creating* more sophisticated messages, for example messages with attachments, special* character encodings, or personal names that accompany mail addresses.** @author Dmitriy Kopylenko* @author Juergen Hoeller* @since 10.09.2003* @see MailSender* @see org.springframework.mail.javamail.JavaMailSender* @see org.springframework.mail.javamail.MimeMessagePreparator* @see org.springframework.mail.javamail.MimeMessageHelper* @see org.springframework.mail.javamail.MimeMailMessage*/
@SuppressWarnings("serial")
public class SimpleMailMessage implements MailMessage, Serializable {@Nullableprivate String from;@Nullableprivate String replyTo;@Nullableprivate String[] to;@Nullableprivate String[] cc;@Nullableprivate String[] bcc;@Nullableprivate Date sentDate;@Nullableprivate String subject;@Nullableprivate String text;/*** Create a new {@code SimpleMailMessage}.*/public SimpleMailMessage() {}/*** Copy constructor for creating a new {@code SimpleMailMessage} from the state* of an existing {@code SimpleMailMessage} instance.*/public SimpleMailMessage(SimpleMailMessage original) {Assert.notNull(original, "'original' message argument must not be null");this.from = original.getFrom();this.replyTo = original.getReplyTo();this.to = copyOrNull(original.getTo());this.cc = copyOrNull(original.getCc());this.bcc = copyOrNull(original.getBcc());this.sentDate = original.getSentDate();this.subject = original.getSubject();this.text = original.getText();}@Overridepublic void setFrom(String from) {this.from = from;}@Nullablepublic String getFrom() {return this.from;}@Overridepublic void setReplyTo(String replyTo) {this.replyTo = replyTo;}@Nullablepublic String getReplyTo() {return this.replyTo;}@Overridepublic void setTo(String to) {this.to = new String[] {to};}@Overridepublic void setTo(String... to) {this.to = to;}@Nullablepublic String[] getTo() {return this.to;}@Overridepublic void setCc(String cc) {this.cc = new String[] {cc};}@Overridepublic void setCc(String... cc) {this.cc = cc;}@Nullablepublic String[] getCc() {return this.cc;}@Overridepublic void setBcc(String bcc) {this.bcc = new String[] {bcc};}@Overridepublic void setBcc(String... bcc) {this.bcc = bcc;}@Nullablepublic String[] getBcc() {return this.bcc;}@Overridepublic void setSentDate(Date sentDate) {this.sentDate = sentDate;}@Nullablepublic Date getSentDate() {return this.sentDate;}@Overridepublic void setSubject(String subject) {this.subject = subject;}@Nullablepublic String getSubject() {return this.subject;}@Overridepublic void setText(String text) {this.text = text;}@Nullablepublic String getText() {return this.text;}/*** Copy the contents of this message to the given target message.* @param target the {@code MailMessage} to copy to*/public void copyTo(MailMessage target) {Assert.notNull(target, "'target' MailMessage must not be null");if (getFrom() != null) {target.setFrom(getFrom());}if (getReplyTo() != null) {target.setReplyTo(getReplyTo());}if (getTo() != null) {target.setTo(copy(getTo()));}if (getCc() != null) {target.setCc(copy(getCc()));}if (getBcc() != null) {target.setBcc(copy(getBcc()));}if (getSentDate() != null) {target.setSentDate(getSentDate());}if (getSubject() != null) {target.setSubject(getSubject());}if (getText() != null) {target.setText(getText());}}@Overridepublic boolean equals(@Nullable Object other) {if (this == other) {return true;}if (!(other instanceof SimpleMailMessage)) {return false;}SimpleMailMessage otherMessage = (SimpleMailMessage) other;return (ObjectUtils.nullSafeEquals(this.from, otherMessage.from) &&ObjectUtils.nullSafeEquals(this.replyTo, otherMessage.replyTo) &&ObjectUtils.nullSafeEquals(this.to, otherMessage.to) &&ObjectUtils.nullSafeEquals(this.cc, otherMessage.cc) &&ObjectUtils.nullSafeEquals(this.bcc, otherMessage.bcc) &&ObjectUtils.nullSafeEquals(this.sentDate, otherMessage.sentDate) &&ObjectUtils.nullSafeEquals(this.subject, otherMessage.subject) &&ObjectUtils.nullSafeEquals(this.text, otherMessage.text));}@Overridepublic int hashCode() {int hashCode = ObjectUtils.nullSafeHashCode(this.from);hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.replyTo);hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.to);hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.cc);hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.bcc);hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.sentDate);hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.subject);return hashCode;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("SimpleMailMessage: ");sb.append("from=").append(this.from).append("; ");sb.append("replyTo=").append(this.replyTo).append("; ");sb.append("to=").append(StringUtils.arrayToCommaDelimitedString(this.to)).append("; ");sb.append("cc=").append(StringUtils.arrayToCommaDelimitedString(this.cc)).append("; ");sb.append("bcc=").append(StringUtils.arrayToCommaDelimitedString(this.bcc)).append("; ");sb.append("sentDate=").append(this.sentDate).append("; ");sb.append("subject=").append(this.subject).append("; ");sb.append("text=").append(this.text);return sb.toString();}@Nullableprivate static String[] copyOrNull(@Nullable String[] state) {if (state == null) {return null;}return copy(state);}private static String[] copy(String[] state) {return state.clone();}}

媒体邮件对象:MimeMailMessage

        MemeMailMessage表示媒体邮件对象,可以实现自定义邮件模板的动态填充和邮件发送。

/** Copyright 2002-2017 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.mail.javamail;import java.util.Date;import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;import org.springframework.mail.MailMessage;
import org.springframework.mail.MailParseException;/*** Implementation of the MailMessage interface for a JavaMail MIME message,* to let message population code interact with a simple message or a MIME* message through a common interface.** <p>Uses a MimeMessageHelper underneath. Can either be created with a* MimeMessageHelper instance or with a JavaMail MimeMessage instance.** @author Juergen Hoeller* @since 1.1.5* @see MimeMessageHelper* @see javax.mail.internet.MimeMessage*/
public class MimeMailMessage implements MailMessage {private final MimeMessageHelper helper;/*** Create a new MimeMailMessage based on the given MimeMessageHelper.* @param mimeMessageHelper the MimeMessageHelper*/public MimeMailMessage(MimeMessageHelper mimeMessageHelper) {this.helper = mimeMessageHelper;}/*** Create a new MimeMailMessage based on the given JavaMail MimeMessage.* @param mimeMessage the JavaMail MimeMessage*/public MimeMailMessage(MimeMessage mimeMessage) {this.helper = new MimeMessageHelper(mimeMessage);}/*** Return the MimeMessageHelper that this MimeMailMessage is based on.*/public final MimeMessageHelper getMimeMessageHelper() {return this.helper;}/*** Return the JavaMail MimeMessage that this MimeMailMessage is based on.*/public final MimeMessage getMimeMessage() {return this.helper.getMimeMessage();}@Overridepublic void setFrom(String from) throws MailParseException {try {this.helper.setFrom(from);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setReplyTo(String replyTo) throws MailParseException {try {this.helper.setReplyTo(replyTo);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setTo(String to) throws MailParseException {try {this.helper.setTo(to);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setTo(String... to) throws MailParseException {try {this.helper.setTo(to);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setCc(String cc) throws MailParseException {try {this.helper.setCc(cc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setCc(String... cc) throws MailParseException {try {this.helper.setCc(cc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setBcc(String bcc) throws MailParseException {try {this.helper.setBcc(bcc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setBcc(String... bcc) throws MailParseException {try {this.helper.setBcc(bcc);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setSentDate(Date sentDate) throws MailParseException {try {this.helper.setSentDate(sentDate);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setSubject(String subject) throws MailParseException {try {this.helper.setSubject(subject);}catch (MessagingException ex) {throw new MailParseException(ex);}}@Overridepublic void setText(String text) throws MailParseException {try {this.helper.setText(text);}catch (MessagingException ex) {throw new MailParseException(ex);}}}

异常接口:MailException

 This package also contains a hierarchy of checked exceptions that provide a higher level of abstraction over the lower level mail system exceptions, with the root exception being MailException.

        Mail是邮件发送的异常处理根接口,源码如下,

@SuppressWarnings("serial")
public abstract class MailException extends NestedRuntimeException {/*** Constructor for MailException.* @param msg the detail message*/public MailException(String msg) {super(msg);}/*** Constructor for MailException.* @param msg the detail message* @param cause the root cause from the mail API in use*/public MailException(@Nullable String msg, @Nullable Throwable cause) {super(msg, cause);}}

        当然,它也内置了一系列子接口,

        基本含义如下, 

MailSendException:邮件发送失败异常

MailParseException:非法的邮件配置属性

MailPreparationException:邮件模板渲染出错时,会抛出此类异常。

MailAuthenticationException:认证失败异常。

application.yml配置

        要使用JavaMailSender实现邮件发送,那么就需要先对其进行配置。通过上述内容的初步了解,基本上可以确定我们要配置的参数就和JavaMailSenderImpl实现子类相关了,其成员属性如下,和SpringBoot官网配置文档给出的配置参数也是一一对应的。

JavaMailSenderImpl实现子类
springBoot官网配置文档

        我所做的配置如下,

spring:mail:protocol: smtphost: smtp.qq.comdefault-encoding: UTF-8username: email-accountpassword: key/passwordproperties:mail:debug: true #开启日志打印smtp:auth: truestarttls:enable: truerequired: true

邮件发送

        上面了解到两种邮件形式,所以,接下来我们尝试一下,如何发送简单文本邮件,以及自定义模板的邮件。

SimpleMailMessage发送

        简单邮件的发送示例代码如下,其中:JavaMailSender 实例即为文章开头部分提到的,由Spring框架自动注入的Bean实例。


@Component
public class EmailSendServiceImpl implements EmailSenderService {@Autowiredprivate JavaMailSender mailSender;@Overridepublic R sendSimpleEmail(String from, String to, String subject, String text) {try {//创建邮件对象SimpleMailMessage mailMessage = new SimpleMailMessage();//设置邮件属性mailMessage.setFrom(from);//发件人mailMessage.setTo(to);//收件人mailMessage.setSubject(subject);//主题mailMessage.setText(text);//文本内容mailMessage.setSentDate(new Date());//发送日期//发送邮件this.mailSender.send(mailMessage);//返回消息return R.ok("邮件发送成功!");} catch (MailException e) {e.printStackTrace();return R.fail("邮件发送失败!");}}
}

MimeMailMessage发送

        为了方便向邮件中写入自定义内容,所以自定义邮件模板需要借助后端的模板引擎来实现,此处我们选择thymeleaf模板引擎。以下为此时的依赖,

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

thymeleaf配置

         如上图所示,thymeleaf模板引擎内置了一套配置规则,最简单的方式就是将其原模原样的写到application.yml配置文件中即可。

        以下为我的配置项,

spring:thymeleaf:prefix: classpath:/templates/suffix: .htmlmode: HTML

邮件模板定制

邮件模板定制,其实就是写一个前端页面,然后借助thymeleaf模板引擎的表达式语法,实现自定义内容的动态填充即可。

关于Thymeleaf的表达式语法,详情可参阅官网文档:Tutorial: Using Thymeleaf

        但是说实话,对于简单的文本替换,以下的简单表达式语法基本就能满足了。

 关于邮件模板的定制,如果要求特别高的话,可以自己从零开始写;但是,如果要快速实现的话,也可以借助在线生成工具,这里比较推荐:拉易网提供的精美邮件定制服务,里面内置了一些可以直接使用的邮件模板,也可以在此基础上进行个性化定制,零代码自动生成。

最终将定制好的模板下载下来即可。

       

 如何使用邮件模板

        那么我们下载下来的邮件模板如何使用呢?

其实和我们的Thymeleaf模板引擎配置相关,毕竟是要将这个模板交给Thymeleaf模板引擎进行值的动态替换和渲染的。

这里对应于thymeleaf的prefix配置项,我的email.html邮件模板就放在templates路径下。

        另外,为了实现动态替换文本,例如:我这里想要实现邮件验证码,那么,我就要通过表达式语法,提供一个文本字符串的变量verifyCode,以便于在后面发送邮件时,将这个变量替换为任何我们随机生成的验证码字符串。

示例代码

终于来到代码环节了,但是前面的环节也确实缺一不可。

@Component
public class EmailSendServiceImpl implements EmailSenderService {@Autowiredprivate JavaMailSender mailSender;@Autowiredprivate TemplateEngine templateEngine;@Overridepublic R sendMimeEmail(String from, String to, String subject) {//create a new JavaMail MimeMessageMimeMessage mimeMailMessage = this.mailSender.createMimeMessage();MimeMessageHelper mimeMessageHelper = null;try {/*** mimeMessage – the mime message to work on* multipart – whether to create a multipart message that supports alternative texts, inline elements and attachments (corresponds to MULTIPART_MODE_MIXED_RELATED)*/mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);//setting basic paramsmimeMessageHelper.setFrom(from);mimeMessageHelper.setTo(to);mimeMessageHelper.setSubject(subject);//create html-text based on thymeleaf templateContext context = new Context();context.setVariable("verifyCode","456935");String process = templateEngine.process("email", context);//设置邮件内容/*** process:the text for the message* html:whether to apply content type "text/html" for an HTML mail, using default content type ("text/plain") else*/mimeMessageHelper.setText(process,true);//发送邮件this.mailSender.send(mimeMailMessage);return R.ok("邮件发送成功!");} catch (MessagingException e) {e.printStackTrace();return R.fail("邮件发送失败!");}}
}

* 模板变量替换:Context探究

        先看一下源码注释,

IContext接口的非web(场景)实现,适用于非web场景。

        我们继续查看Context父类AbstractContext实现的IContext接口,可以看到,有一个我们刚才用于动态替换thymeleaf模板变量的方法,

        注意到它还提供了一个重载方法,可以实现多个模板变量值的设置,都是以key-value键值对的形式出现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/207559.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode算法题解(动态规划)|LeetCode343. 整数拆分、LeetCode96. 不同的二叉搜索树

一、LeetCode343. 整数拆分 题目链接&#xff1a;343. 整数拆分 题目描述&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入…

坚鹏:湘潭市银行业协会BLM银行数字化转型战略培训圆满结束

在数字化转型背景下&#xff0c;湘潭市银行业协会为了落实监管政策《关于银行业保险业数字化转型的指导意见》&#xff0c;充分认识到学习银行银行数字化转型战略的价值和重要性&#xff0c;特别举办《2023年数字化转型战略专题培训班》。为了改变大家的认知&#xff0c;为了拓…

VMware三种网络模式

桥接模式 NAT(网络地址转换模式) Host-Only(仅主机模式) 参考&#xff1a; vmware虚拟机三种网络模式 - 知乎 (zhihu.com)

linux之进程地址空间

文章目录 1.进程地址空间回顾1.1进程地址空间划分1.2验证进程地址空间划分1.简单划分2.完整划分 2.初探进程地址空间2.1初看现象2.2Makefile的简便写法 3.进程地址空间详解3.1地址空间是什么?3.2地址空间的设计/由来3.3空间区域划分3.4如何理解地址空间?3.5解释3.2的&#x1…

【Linux】-进程间通信-共享内存(SystemV),详解接口函数以及原理(使用管道处理同步互斥机制)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

93.STL-系统内置仿函数

目录 算术仿函数 关系仿函数 逻辑仿函数 C 标准库中提供了一些内置的函数对象&#xff0c;也称为仿函数&#xff0c;它们通常位于 <functional> 头文件中。以下是一些常见的系统内置仿函数&#xff1a; 算术仿函数 功能描述&#xff1a; 实现四则运算其中negate是一元…

CURL踩坑记录

因为项目使用的windows server&#xff0c;且没有安装Postman&#xff0c;所以对于在本地的Postman上执行的请求&#xff0c;要拷贝到服务器执行&#xff0c;只能先转化成为curl命令&#xff0c;操作也很简单&#xff0c;如下&#xff1a; 注意&#xff0c;Postman默认对url包围…

不停的挖掘硬盘的最大潜能

从 NAS 上退休的硬盘被用在了监控的存储上了。 随着硬盘使用寿命的接近尾声&#xff0c;感觉就是从高附加值数据到低附加值数据上。监控数据只会保留那么几个月的时间&#xff0c;很多时候都会被覆盖重新写入。 有人问为什么监控数据不保留几年的&#xff0c;那是因为监控数据…

2023 年 亚太赛 APMCM 国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 cs数模团队在亚太赛 APMCM前为大家提供了许多资料的内容呀&…

基于跳蛛算法优化概率神经网络PNN的分类预测 - 附代码

基于跳蛛算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于跳蛛算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于跳蛛优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

千帆Llama 2中文增强技术介绍--SFT,预训练,指令优化

目录 千帆Llama 2中文增强技术介绍 SFT&#xff0c;预训练&#xff0c;指令优化 千帆Llama 2中文增强技术介绍 SFT&#xff0c;预训练&#xff0c;指令优化

基于鹈鹕算法优化概率神经网络PNN的分类预测 - 附代码

基于鹈鹕算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于鹈鹕算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于鹈鹕优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…