草庐IT

springboot:java实现邮件及附件发送、HTML正文的三种方式(三)【附带源码】

wu_55555 2023-03-28 原文

0. 引言

邮件发送是我们日常开发中比较常见的功能,常用于预警信息提醒、统计数据定期发送等需求。一般该方法会由前人封装好,实际开发时只需要调用即可,但具体怎么实现的,如何从零实现邮件发送,这是我们要掌握的。

之前我们讲解了基于​​javax.mail​​​和​​org.apache.commons.mail​​​实现邮件发送, 今天继续讲解第三种方式基于​​spring-boot-starter-mail​​实现。

  • ​​基于javax.mail实现邮件发送​​
  • ​​基于commons.mail实现邮件发送​​

1. 环境准备

1.1 开发环境

以下演示基于当前项目使用的springboot版本,jdk基于1.8版本

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

1.2 开启邮箱协议与授权

其次我们需要了解的是,程序要发送邮件,是需要一个邮箱账号的, 并且其账号需要开启SMTP邮件协议以及邮件授权码,并不是密码。

以下我们以QQ邮箱为例,示范其开启过程,其他邮箱大同小异。

1、登陆邮箱,点击​​设置​​​,进入​​账户​​,下拉页面

2、找到​​POP3/IMAP/SMTP​​​服务设置。这里我们可以开启​​POP3/SMTP​​​或者​​IMAP/SMTP​​服务,两者的区别

3、点击​​开启​​后,会要求你发送短信验证

4、发送后,点击​​我已发送​​,然后会给你一个授权码,将该码保存下来,这就是我们需要的授权码。

5、其次我们需要获取到邮件服务器的smtp地址,比如我们这里用的是qq邮箱,其地址就是​​smtp.qq.com​​。对应类型邮箱的smtp地址直接百度即可。

1.3 常见的邮箱服务及端口

服务商

smtp服务地址

smtp服务端口

pop3服务地址

pop3服务端口

新浪 sina.com

smtp.sina.com.cn

25

pop3.sina.com.cn

110

搜狐 sohu.com

smtp.sohu.com

25

pop3.sohu.com

110

163 163.com

smtp.163.com

25

pop3.163.com

110

QQ qq.com

smtp.qq.com

25

pop3.qq.com

110

foxmail foxmail.com

smtp.foxmail.com

25

pop3.foxmail.com

110

QQ企业邮箱 exmail.qq.com

smtp.exmail.qq.com

995

pop3.exmail.qq.com

587/465

2. 实现

2.1 spring-boot-starter-mail实现

2.1.1 思路

1、我们观察​​spring-boot-starter-mail​​​依赖包,发现其实内部使用​​jakarta.mail​​来实现

而​​jakarta​​​内部其实也有​​javax.mail​​​的包。所以后续我们会发现很多用法与​​javax.mail​​类似

2.1.2 实操

1、引入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2、修改配置文件​​application.yml​​中

spring:
# spring-boot-starter-mail配置项
mail:
host: smtp.qq.com
username: xxx@qq.com
password: xxx
default-encoding: UTF-8
properties.mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
# 打印邮件发送过程,生产环境关闭
properties.mail.debug: true
3、创建工具类,实现发送功能(注意这里已经将工具类声明为bean了,所以我们使用时要用依赖注入的形式调用)

/**
* @author benjamin_5
* @Description spring-boot-starter-mail邮件工具类
* @date 2022/10/5
*/
@Component
@AllArgsConstructor
public class EmailSpringUtil {

private final JavaMailSender javaMailSender;
private final MailProperties mailProperties;
/**
* 邮件发送
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileNames 文件名(本地路径)
* @throws GeneralSecurityException
* @throws UnsupportedEncodingException
* @throws MessagingException
*/
public void sendEmail(String subject, String content,boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, List<String> fileNames) throws MessagingException, UnsupportedEncodingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,true);
helper.setFrom(mailProperties.getUsername(),fromMailPersonalName);
helper.setTo(toMail);
if(!ObjectUtils.isEmpty(ccMail)){
helper.setCc(ccMail);
}
if(!ObjectUtils.isEmpty(bccMail)){
helper.setBcc(bccMail);
}
helper.setSubject(subject);
helper.setText(content,contentIsHtml);
// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
if(!CollectionUtils.isEmpty(fileNames)){
for (String fileName : fileNames) {
FileDataSource fileDataSource = new FileDataSource(fileName);
helper.addAttachment(fileDataSource.getName(),fileDataSource);
}
}
javaMailSender.send(message);
}
}
4、调用测试,我们创建一个接口来模拟测试

@RestController
@AllArgsConstructor
public class EmailController {

private final EmailSpringUtil emailSpringUtil;

@GetMapping("sendSpringEmail")
public void sendSpringEmail(){
String subject = "这是一个测试标题";
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
String toMail = "wuhanxue5@sina.com";
String ccMail = "wuhanxue5@163.com";
String fileName = "/Users/wuhanxue/Downloads/供应商接口参数.xlsx";
try {
emailSpringUtil.sendEmail(subject,html,true,"邮件提醒系统",toMail,ccMail,null, Arrays.asList(fileName));
} catch (MessagingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
4、浏览器访问该接口​​http://localhost:8080/sendSpringEmail​

邮件接收成功,附件和HTML正文也显示正常

查看抄送邮箱,接收正常

补充问题

如果出现接收到的附件为​​.bin​​​格式,这是因为附件名称过长导致,mime.mail中的参数​​splitlongparameters​​​默认为
true,当附件名过长时,他会自动截取,就会导致我们接收到的附件格式变成​​​.bin​​形式的。

要解决该问题就需要将其设置为false。于是我们创建一个启动执行类来单独设置

@Configuration
public class EmailToLongConfig {

@PostConstruct
private void init(){
// 解决邮件附件名称太长会自动截取,导致附件变成.bin格式问题
System.setProperty("mail.mime.splitlongparameters","false");
}
}
当然我们也可以将​​System.setProperty("mail.mime.splitlongparameters","false");​​放到邮件发送的方法中去。

当然如果需求允许,也可以设置一个短一点的附件名来规避该问题

源码地址

以上演示的源码可以在如下地址中下载

​git源码地址​

总结

从代码可以看出​​spring-boot-starter-mail​​​与​​javax.mail​​​的实现类似,都是通过​​MimeMessageHelper​​类实现的

至此我们已经讲解完三种实现邮件发送的方法了,实际上邮件发送功能实现非常简单,毕竟我们只是在前人做好的组件上开发,已经站在了巨人的肩膀上。之前演示的代码大家也可以直接应用到生产中,但一定不要盲目的复制粘贴,理解,自己一行一行的复写一遍代码,这是千万不能省的!


有关springboot:java实现邮件及附件发送、HTML正文的三种方式(三)【附带源码】的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  5. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  8. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  9. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  10. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

随机推荐