springboot 发送邮件实战(完整代码)
springboot 发送邮件实战
前言:在我们实际项目中,有一些需求涉及到使用邮箱发送邮件的功能。Spring 框架提供了使用
JavaMailSender
接口发送电子邮件的抽象,Spring Boot 为其提供了自动配置以及启动模块。所以我们使用实现邮件发送功能还是相对来比较简单,spring官网邮件发送功能:https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.email
一、准备工作
发送邮箱要开启邮件服务(以163邮箱为例)
进入对应的发送邮箱的设置
开启IMAP或者POP3任意一个服务都可以
至此,准备工作已经结束。
二、进入项目代码环节
2.1 项目引入邮箱的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.2 邮件的基本配置
# 属性名称:属性类型
属性说明
# mail.smtp.user:String
SMTP 的默认用户名。
# mail.smtp.host:String
要连接的 SMTP 服务器。
# mail.smtp.port:int
要连接的 SMTP 服务器端口,如果 connect() 方法没有明确指定一个。默认为 25。
# mail.smtp.connectiontimeout:int
以毫秒为单位的套接字连接超时值。这个超时是由 java.net.Socket 实现的。默认为无限超时。
# mail.smtp.timeout:int
以毫秒为单位的套接字读取超时值。这个超时是由 java.net.Socket 实现的。默认为无限超时。
# mail.smtp.writetimeout:int
以毫秒为单位的套接字写入超时值。此超时是通过对每个连接使用 java.util.concurrent.ScheduledExecutorService 来实现的,
该服务会在超时到期时安排线程关闭套接字。因此,使用此超时的开销是每个连接一个线程。默认为无限超时。
# mail.smtp.from:String
用于 SMTP MAIL 命令的电子邮箱地址。这将设置信封返回地址。默认为 msg.getFrom() 或 InternetAddress.getLocalAddress()。
注意:mail.smtp.user 以前用于此目的。
# mail.smtp.localhost:String
SMTP HELO 或 EHLO 命令中使用的本地主机名。默认为InetAddress.getLocalHost().getHostName().
如果您的 JDK 和名称服务配置正确,则通常不需要设置。
# mail.smtp.localaddress:String
创建 SMTP 套接字时要绑定到的本地地址(主机名)。默认为 Socket 类选择的地址。通常不需要设置,
但对于选择要绑定到的特定本地地址很重要的多宿主主机很有用。
# mail.smtp.localport:int
创建 SMTP 套接字时要绑定到的本地端口号。默认为 Socket 类选择的端口号。
# mail.smtp.ehlo:boolean
如果为 false,则不要尝试使用 EHLO 命令登录。默认为真。通常 EHLO 命令失败将回退到 HELO 命令;
此属性仅适用于未正确使 EHLO 失败 或未正确实现 EHLO 的服务器。
# mail.smtp.auth:boolean
如果为 true,则尝试使用 AUTH 命令对用户进行身份验证。默认为假。
# mail.smtp.auth.mechanisms:String
如果设置,则列出要考虑的身份验证机制,以及考虑它们的顺序。只会使用服务器支持和当前实现支持的机制。
默认为"LOGIN PLAIN DIGEST-MD5 NTLM",包括当前实现支持的所有认证机制,除了 XOAUTH2。
# mail.smtp.auth.login.disable:boolean
如果为 true,则阻止使用该AUTH LOGIN命令。默认为假。
# mail.smtp.auth.plain.disable:boolean
如果为 true,则阻止使用该AUTH PLAIN命令。默认为假。
# mail.smtp.auth.digest-md5.disable:boolean
如果为 true,则阻止使用该AUTH DIGEST-MD5命令。默认为假。
# mail.smtp.auth.ntlm.disable:boolean
如果为 true,则阻止使用该AUTH NTLM命令。默认为假。
# mail.smtp.auth.ntlm.domain:String
NTLM 身份验证域。
# mail.smtp.auth.ntlm.flags:int
NTLM 协议特定标志。有关详细信息,请参阅 http://curl.haxx.se/rfc/ntlm.html#theNtlmFlags。
# mail.smtp.auth.xoauth2.disable:boolean
如果为 true,则阻止使用该AUTHENTICATE XOAUTH2命令。由于 OAuth 2.0 协议需要特殊的访问令牌而不是密码,因此默认情况下
禁用此机制。通过将此属性显式设置为“false”或将“mail.smtp.auth.mechanisms”属性设置为“XOAUTH2”来启用它。
# mail.smtp.submitter:String
要在 MAIL FROM 命令的 AUTH 标记中使用的提交者。通常由邮箱中继用于传递有关邮箱原始提交者的信息。
另请参阅 的setSubmitter 方法SMTPMessage。邮箱客户端通常不使用它。
# mail.smtp.dsn.notify:String
RCPT 命令的 NOTIFY 选项。NEVER 或 SUCCESS、FAILURE 和 DELAY(以逗号分隔)的某种组合。
# mail.smtp.dsn.ret:String
MAIL 命令的 RET 选项。FULL 或 HDRS。
# mail.smtp.allow8bitmime:boolean
如果设置为 true,并且服务器支持 8BITMIME 扩展,则使用“quoted-printable”或“base64”编码的邮箱的文本部分
如果遵循 8bit 文本的 RFC2045 规则,则将转换为使用“8bit”编码。
# mail.smtp.sendpartial:boolean
如果设置为 true,并且消息具有一些有效地址和一些无效地址,则无论如何都要发送消息,并使用 SendFailedException 报告部分失败。
如果设置为 false(默认值),则如果收件人地址无效,则不会将邮箱发送给任何收件人。
# mail.smtp.sasl.enable:boolean
如果设置为 true,则尝试使用 javax.security.sasl 包来选择登录的身份验证机制。默认为假。
# mail.smtp.sasl.mechanisms:String
要尝试使用的 SASL 机制名称的空格或逗号分隔列表。
# mail.smtp.sasl.authorizationid:String
在 SASL 身份验证中使用的授权 ID。如果未设置,则使用身份验证 ID(用户名)。
# mail.smtp.sasl.realm:String
用于 DIGEST-MD5 身份验证的领域。
# mail.smtp.sasl.usecanonicalhostname:boolean
如果设置为 true,则返回的规范主机名将 InetAddress.getCanonicalHostName 传递给 SASL 机制,
而不是用于连接的主机名。默认为假。
# mail.smtp.quitwait:boolean
如果设置为 false,则发送 QUIT 命令并立即关闭连接。如果设置为 true(默认值),则导致传输等待对 QUIT 命令的响应。
# mail.smtp.quitonsessionreject:boolean
如果设置为 false(默认值),会话发起拒绝时不发送 QUIT 命令并立即关闭连接。
如果设置为 true,则导致传输在关闭连接之前发送 QUIT 命令。
# mail.smtp.reportsuccess:boolean
如果设置为 true,则会导致传输SMTPAddressSucceededException 为每个成功的地址包含一个 。还要注意 ,
即使所有地址都正确并且消息已成功发送,这将导致SendFailedException 从sendMessage方法中 抛出 a SMTPTransport。
# mail.smtp.socketFactory:SocketFactory
如果设置为实现该javax.net.SocketFactory接口的类,则 该类将用于创建 SMTP 套接字。请注意,这是一个类的实例,
而不是名称,并且必须使用put方法而不是setProperty方法来设置 。
# mail.smtp.socketFactory.class:String
如果设置,则指定实现javax.net.SocketFactory接口的类的名称 。此类将用于创建 SMTP 套接字。
# mail.smtp.socketFactory.fallback:boolean
如果设置为 true,则无法使用指定的套接字工厂类创建套接字将导致使用java.net.Socket该类创建套接字。默认为真。
# mail.smtp.socketFactory.port:int
指定使用指定套接字工厂时要连接的端口。如果未设置,将使用默认端口。
# mail.smtp.ssl.enable:boolean
如果设置为 true,则默认使用 SSL 连接并使用 SSL 端口。“smtp”协议默认为 false,“smtps”协议默认为 true。
# mail.smtp.ssl.checkserveridentity:boolean
如果设置为 true,请检查RFC 2595指定的服务器标识 。这些基于服务器证书内容的额外检查旨在防止中间人攻击。默认为假。
# mail.smtp.ssl.trust:String
如果设置,并且未指定套接字工厂,则启用 MailSSLSocketFactory. 如果设置为“*”,则所有主机都是可信的。如果设置为以
空格分隔的主机列表,则这些主机是可信的。否则,信任取决于服务器提供的证书。
# mail.smtp.ssl.socketFactory:SSLSocketFactory
如果设置为扩展 javax.net.ssl.SSLSocketFactory类的类,则此类将用于创建 SMTP SSL 套接字。请注意,这是一个类的实例,
而不是名称,并且必须使用put方法而不是setProperty方法来设置 。
# mail.smtp.ssl.socketFactory.class:String
如果设置,则指定扩展javax.net.ssl.SSLSocketFactory类的类的名称 。此类将用于创建 SMTP SSL 套接字。
# mail.smtp.ssl.socketFactory.port:int
指定使用指定套接字工厂时要连接的端口。如果未设置,将使用默认端口。
# mail.smtp.ssl.protocols:String
指定将为 SSL 连接启用的 SSL 协议。属性值是该javax.net.ssl.SSLSocket.setEnabledProtocols方法
可接受的以空格分隔的标记列表。
# mail.smtp.ssl.ciphersuites:String
指定将为 SSL 连接启用的 SSL 密码套件。属性值是该javax.net.ssl.SSLSocket.setEnabledCipherSuites方法
可接受的以空格分隔的标记列表。
# mail.smtp.starttls.enable:boolean
如果为 true,则启用该STARTTLS命令(如果服务器支持)在发出任何登录命令之前将连接切换到受 TLS 保护的连接。
如果服务器不支持 STARTTLS,则连接继续而不使用 TLS;mail.smtp.starttls.required 如果不支持 STARTTLS,
请查看失败的 属性。请注意,必须配置适当的信任库,以便客户端信任服务器的证书。默认为假。
# mail.smtp.starttls.required:boolean
如果为 true,则需要使用该STARTTLS命令。如果服务器不支持 STARTTLS 命令,或者命令失败,connect 方法就会失败。默认为假。
# mail.smtp.proxy.host:String
指定将用于连接到邮箱服务器的 HTTP Web 代理服务器的主机名。
# mail.smtp.proxy.port:String
指定 HTTP Web 代理服务器的端口号。默认为端口 80。
# mail.smtp.proxy.user:String
指定用于向 HTTP Web 代理服务器进行身份验证的用户名。默认情况下,不进行身份验证。
# mail.smtp.proxy.password:String
指定用于向 HTTP Web 代理服务器进行身份验证的密码。默认情况下,不进行身份验证。
# mail.smtp.socks.host:String
指定将用于连接到邮箱服务器的 SOCKS5 代理服务器的主机名。
# mail.smtp.socks.port:String
指定 SOCKS5 代理服务器的端口号。仅当代理服务器未使用标准端口号 1080 时才需要使用此选项。
# mail.smtp.mailextension:String
附加到 MAIL 命令的扩展字符串。扩展字符串可用于指定标准 SMTP 服务扩展以及特定于供应商的扩展。通常,
应用程序应使用该 SMTPTransport 方法supportsExtension 来验证服务器是否支持所需的服务扩展。
请参阅RFC 1869 和其他定义特定扩展的 RFC。
# mail.smtp.userset:boolean
如果设置为true,则在isConnected方法中使用RSET 命令而不是NOOP 命令。
在某些情况下,sendmail 在多次 NOOP 命令后响应会很慢;使用 RSET 避免了这个 sendmail 问题。默认为假。
# mail.smtp.noop.strict:boolean
如果设置为 true(默认值),则坚持来自 NOOP 命令的 250 响应代码以指示成功。该isConnected方法使用 NOOP 命令 来确定
连接是否仍然有效。一些较旧的服务器在成功时返回错误的响应代码,一些服务器根本不执行 NOOP 命令,因此总是返回失败代码。
将此属性设置为 false 以处理以这种方式损坏的服务器。通常,当服务器超时连接时,它会发送 421 响应代码,客户端将其视
为对其发出的下一个命令的响应。某些服务器在连接超时时发送错误的失败响应代码。在处理以这种方式损坏的服务器时,
不要将此属性设置为 false。
上述是邮箱properties 扩展配置,下面是基本配置
spring:
mail:
host: smtp.163.com #smtp服务器主机(163的)
port: 25 # 连接邮件服务器端口(默认SMTP 25 POP 110)
protocol: smtp # 连接协议(默认SMTP)
username: xxxxx@163.com # 登录服务器邮箱账号
password: xxxxxxxxxxxx # 登录服务器邮箱授权码(不是邮箱密码,这个是我们开通SMTP、POP时得到的授权码)
default-encoding: UTF-8 # 编码
test-connection: false # 是否测试连接
properties:
mail:
smtp:
from: xxxxx@163.com #默认发送方邮箱账号(当程序未指定发件人邮箱则默认取这个)
auth: true # 开启权限认证
timeout: 25000 # 邮件接收时间的限制
connectiontimeout: 25000 # 连接时间的限制
writetimeout: 25000 # 邮件发送时间的限制(毫秒)
debug: true # 日志打印,邮件发送过程的日志会被输出
2.2 实现发送邮件的功能
JavaMailSender和JavaMailSenderImpl;它们是Spring官方提供的一套邮件功能集成接口及实现。我们在业务里直接注入JavaMailSenderImpl后并调用send方法。其中简单的邮件我们可以通过SimpleMailMessage来发送,对于复杂的带有附件的我们可以借助MimeMessageHelper来构建MimeMessage发送邮件。
发送邮件有三种常见的发送方式:
1、发送简单的文本内容
2、发送复杂的邮件HTML+图片资源+附件
3、发送复杂邮件使用Thymeleaf模板
2.2.1 发送简单的文本内容
@Autowired
private JavaMailSender javaMailSender;
@Override
public void sendSimpleMail(String from, String to, String subject, String text) {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
// 发件人
simpleMailMessage.setFrom(from);
// 收件人
simpleMailMessage.setTo(to);
// 邮件主题
simpleMailMessage.setSubject(subject);
// 邮件内容
simpleMailMessage.setText(text);
javaMailSender.send(simpleMailMessage);
}
2.2.2 发送带附件的邮件
@Override
public Boolean sendMimeMail(String from, String to, String subject, String text) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
String url = "https://www.w3school.com.cn/example/xmle/note.xml";
String filePath = "D:\\workFile";
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text);
String fileName = XFileUtils.downLoadByUrl(url, filePath, null);
String fullFilePath = filePath + File.separator + fileName;
File file = new File(fullFilePath);
if (!file.exists()) {
return false;
}
FileSystemResource fileSystemResource = new FileSystemResource(file);
helper.addAttachment(fileName, fileSystemResource);
javaMailSender.send(mimeMessage);
file.delete();
} catch (Exception e) {
log.error("发送复杂邮箱失败",e);
return false;
}
return true;
}
2.2.3 发送使用模板的邮件
a. 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
b. resource/templates文件夹中添加一个名为template.html的文件
<!DOCTYPE html>
<html lang="en">
<head>
<title>邮箱验证</title>
<meta charset="utf-8">
</head>
<body>
<!-- 头部 -->
<div style="padding: 10px; background-color: #393D49;">
<h2 style="color: #FFFFFF; margin: 0px;"></h2>
</div>
<!-- 内容 -->
<div style="padding-top: 10px; padding-bottom: 10px;">
<div style="background-color: snow; padding: 20px;">
<div>
<h3>尊敬的用户:您好!</h3>
<p>说明:您现在正在进行敏感操作,为了确保您的账户安全,我们将通过邮件对您进行身份验证。</p>
<p th:text="${message}"></p>
<div>
<h4>本次的验证码为:</h4>
<div style="background-color: #EBEEF5; padding: 10px;">
<h3 th:text="${code}"></h3>
</div>
<h4>有效期为5分钟</h4>
</div>
</div>
</div>
</div>
<!-- 页底 -->
<div style="padding: 10px; text-align: center; background-color: #2F4056;">
<p style="margin: 0px; color: #FFFFFF;"></p>
</div>
</body>
</html>
c. 发送邮件代码
@RequestMapping("/sendTemplateMail")
public Boolean sendTemplateMail(){
String from = "XXXXX@163.com";
String to = "XXXXX@163.com";
String subject = "这是模板邮件的标题";
String message = "详情:您正在尝试进行登录操作,若非是您本人的行为,请忽略!";
String code = "123456789";
Context context = new Context();
context.setVariable("message", message);
context.setVariable("code", code);
return emailService.sendTemplateMail(from, to, subject, context );
}
@Override
public Boolean sendTemplateMail(String from, String to, String subject, Context context) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
String mail = templateEngine.process("template.html", context);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(mail,true);
javaMailSender.send(mimeMessage);
} catch (Exception e) {
log.error("发送模板邮箱失败",e);
return false;
}
return true;
}