Java使用企业邮箱发送预警邮件
前言:最近接到一个需求,需要根据所监控设备的信息,在出现问题时发送企业微信进行预警。
POM依赖
<!-- 邮件 -->
<dependency><groupId>com.sun.mail</groupId><artifactId>jakarta.mail</artifactId><version>1.6.7</version>
</dependency>
yml配置项
mail:service:smtpSslEnable: truesmtpAuth: truesmtpHost: smtp.exmail.qq.com # 企业微信的hostsmtpPort: 465account: 发信人邮箱名password: 发信人邮箱密码
邮箱工具类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "mail.service")
public class MailServiceProperties {private String account;/*** 登录密码*/private String password;/*** 邮件服务器地址*/private String smtpHost;/*** 发信端口*/private String smtpPort;/*** 是否认证*/private String smtpAuth;private String smtpSslEnable;}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class MailContent {private String aliasName;private String recipients;private String subject;private String content;
}
import com.ruoyi.common.config.MailServiceProperties;
import com.ruoyi.common.constant.MailContent;
import com.sun.mail.util.MailSSLSocketFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.GeneralSecurityException;
import java.util.Date;
import java.util.Properties;@Slf4j
@Component
public class MailUtils {@Autowiredprivate MailServiceProperties properties;/*** 批量发送邮件** @param aliasName 别名* @param subject 主题* @param content 内容*/public void batchSendEmail(String recipientList, String aliasName, String subject, String content) {if (!StringUtils.isEmpty(recipientList)) {String[] arrs = recipientList.split(",");for (String arr : arrs) {send(new MailContent(aliasName, arr, subject, content));}} else {log.error("收件人为空,发送失败。");}}/*** 批量发送邮件 带图片** @param aliasName 别名* @param subject 主题* @param content 内容* @param is 图片*/public void batchSendEmail(String recipientList, String aliasName, String subject, String content,InputStream is) {if (!StringUtils.isEmpty(recipientList)) {String[] arrs = recipientList.split(",");for (String arr : arrs) {send(new MailContent(aliasName, arr, subject, content),is);}} else {log.error("收件人为空,发送失败。");}}/*** 发送邮件** @param content*/private void send(MailContent content) {// 设置邮件属性Properties prop = new Properties();prop.setProperty("mail.transport.protocol", "smtp");prop.setProperty("mail.smtp.host", properties.getSmtpHost());prop.setProperty("mail.smtp.port", properties.getSmtpPort());prop.setProperty("mail.smtp.auth", properties.getSmtpAuth());prop.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");MailSSLSocketFactory sslSocketFactory = null;try {sslSocketFactory = new MailSSLSocketFactory();sslSocketFactory.setTrustAllHosts(true);} catch (GeneralSecurityException e1) {log.error("开启 MailSSLSocketFactory 失败", e1);}if (sslSocketFactory == null) {log.error("开启 MailSSLSocketFactory 失败");} else {prop.put("mail.smtp.ssl.enable", properties.getSmtpSslEnable());prop.put("mail.smtp.ssl.socketFactory", sslSocketFactory);// 创建邮件会话(注意,如果要在一个进程中切换多个邮箱账号发信,应该用 Session.getInstance)Session session = Session.getDefaultInstance(prop, new MyAuthenticator(properties.getAccount(), properties.getPassword()));try {MimeMessage mimeMessage = new MimeMessage(session);// 设置发件人别名(如果未设置别名就默认为发件人邮箱)if (content.getAliasName() != null && !content.getAliasName().trim().isEmpty()) {mimeMessage.setFrom(new InternetAddress(properties.getAccount(), content.getAliasName()));} else {mimeMessage.setFrom(new InternetAddress(properties.getAccount(), properties.getAccount()));}// 设置主题和收件人、发信时间等信息mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(content.getRecipients()));mimeMessage.setSubject(content.getSubject());mimeMessage.setSentDate(new Date());// 添加正文信息MimeMultipart multipart = new MimeMultipart();MimeBodyPart body = new MimeBodyPart();body.setContent(content.getContent(), "text/html; charset=UTF-8");multipart.addBodyPart(body);mimeMessage.setContent(multipart);// 开始发信mimeMessage.saveChanges();Transport.send(mimeMessage);} catch (Exception e) {log.error("发送邮件错误:", e);}}}/*** 发送邮件(带图片)** @param content 文本内容* @param inputStream 图片内容*/private void send(MailContent content, InputStream inputStream) {// 设置邮件属性Properties prop = new Properties();prop.setProperty("mail.transport.protocol", "smtp");prop.setProperty("mail.smtp.host", properties.getSmtpHost());prop.setProperty("mail.smtp.port", properties.getSmtpPort());prop.setProperty("mail.smtp.auth", properties.getSmtpAuth());prop.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");MailSSLSocketFactory sslSocketFactory = null;try {sslSocketFactory = new MailSSLSocketFactory();sslSocketFactory.setTrustAllHosts(true);} catch (GeneralSecurityException e1) {log.error("开启 MailSSLSocketFactory 失败", e1);}if (sslSocketFactory == null) {log.error("开启 MailSSLSocketFactory 失败");} else {prop.put("mail.smtp.ssl.enable", properties.getSmtpSslEnable());prop.put("mail.smtp.ssl.socketFactory", sslSocketFactory);// 创建邮件会话(注意,如果要在一个进程中切换多个邮箱账号发信,应该用 Session.getInstance)Session session = Session.getDefaultInstance(prop, new MyAuthenticator(properties.getAccount(), properties.getPassword()));try {MimeMessage mimeMessage = new MimeMessage(session);// 设置发件人别名(如果未设置别名就默认为发件人邮箱)if (content.getAliasName() != null && !content.getAliasName().trim().isEmpty()) {mimeMessage.setFrom(new InternetAddress(properties.getAccount(), content.getAliasName()));} else {mimeMessage.setFrom(new InternetAddress(properties.getAccount(), properties.getAccount()));}// 设置主题和收件人、发信时间等信息mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(content.getRecipients()));mimeMessage.setSubject(content.getSubject());mimeMessage.setSentDate(new Date());// 添加正文信息MimeMultipart multipart = new MimeMultipart();//邮件内容//准备图片数据MimeBodyPart image=new MimeBodyPart();File tmpFile =File.createTempFile("123",".jpg");Files.copy(inputStream,tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING);DataHandler dh=new DataHandler(new FileDataSource(tmpFile));image.setDataHandler(dh);//id自己设置image.setContentID("123");//image.setFileName("999.png");//正文MimeBodyPart text=new MimeBodyPart();text.setContent(content.getContent()+"<br/><a><img src='cid:123'></a>","text/html;charset=UTF-8");// text.setContent("<h1 style='color:red'>带图片的邮件<img src='cid:bz.jpg'></h1>","text/html;charset=UTF-8");MimeMultipart mmTextImage = new MimeMultipart();mmTextImage.addBodyPart(text);mmTextImage.addBodyPart(image);// 关联关系mmTextImage.setSubType("related");MimeBodyPart textImage = new MimeBodyPart();textImage.setContent(mmTextImage);multipart.addBodyPart(textImage);multipart.setSubType("mixed");mimeMessage.setContent(multipart);// 开始发信mimeMessage.saveChanges();Transport.send(mimeMessage);tmpFile.deleteOnExit();} catch (Exception e) {log.error("发送邮件错误:", e);}}}/*** 认证信息*/static class MyAuthenticator extends Authenticator {/*** 用户名*/String username = null;/*** 密码*/String password = null;/*** 构造器** @param username 用户名* @param password 密码*/public MyAuthenticator(String username, String password) {this.username = username;this.password = password;}@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(username, password);}}}
Controller
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.MailUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/aicut")
@Slf4j
public class MailController {@Autowiredprivate MailUtils mailUtils;@PostMapping("/sendMail")public R sendMail() {String recipientList = "xxx@xx.com"; //收件人邮箱,以逗号分割,可同时发给多个人String aliasName = "测试邮件";String subject = "邮件主题";String content = "邮件内容";mailUtils.batchSendEmail(recipientList, aliasName, subject, content);return R.ok();}
}
测试结果
相关文章:

Java使用企业邮箱发送预警邮件
前言:最近接到一个需求,需要根据所监控设备的信息,在出现问题时发送企业微信进行预警。 POM依赖 <!-- 邮件 --> <dependency><groupId>com.sun.mail</groupId><artifactId>jakarta.mail</artifactId>…...

Unity编辑器扩展之是否勾选Text组件BestFit选项工具(此篇教程也可以操作其他组件的属性)
想要批量化是否勾选项目预制体资源中Text组件BestFit属性(此篇教程也可以操作其他组件的属性,只不过需要修改其中对应的代码),可以采用以下步骤。 1、在项目的Editor文件中,新建一个名为TextBestFitBatchProcessor的…...
分布式场景怎么Join | 京东云技术团队
背景 最近在阅读查询优化器的论文,发现System R中对于Join操作的定义一般分为了两种,即嵌套循环、排序-合并联接。在原文中,更倾向使用排序-合并联接逻辑。 考虑到我的领域是在处理分库分表或者其他的分区模式,这让我开始不由得…...

24-k8s的附件组件-Metrics-server组件与hpa资源pod水平伸缩
一、概述 Metrics-Server组件目的:获取集群中pod、节点等负载信息; hpa资源目的:通过metrics-server获取的pod负载信息,自动伸缩创建pod; 参考链接: 资源指标管道 | Kubernetes https://github.com/kuberne…...
Spring RabbitMQ 配置多个虚拟主机(vhost)
文章目录 前言一、相关文章二、相关代码1.yml文件配置2.RabbitMq配置类3.接收MQ消息前言 在日常开发中,同时需要用到RabbitMQ多个虚拟机(vhost)。应用场景:需要接收多个交换机的数据,而交换机都在不同的虚拟机(vhost) 一、相关文章 Docker安装RabbitMQ 【SpringCloud…...

「Qt Widget中文示例指南」如何实现文档查看器?(一)
Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。 文档查看器是一个显…...

如何创建WordPress付款表单(简单方法)
您是否正在寻找一种简单的方法来创建付款功能WordPress表单? 小企业主通常需要创建一种简单的方法来在其网站上接受付款,而无需设置复杂的购物车。简单的付款表格使您可以轻松接受自定义付款金额、设置定期付款并收集自定义详细信息。 在本文中&#x…...

虹科方案 | 释放总线潜力:汽车总线离线模拟解决方案
来源:虹科汽车智能互联 虹科方案 | 释放总线潜力:汽车总线离线模拟解决方案 原文链接:https://mp.weixin.qq.com/s/KGv2ZOuQMLIXlOiivvY6aQ 欢迎关注虹科,为您提供最新资讯! #汽车总线 #ECU #汽车网关 导读 传统的…...

欲速则不达,慢就是快!
引言 随着生活水平的提高,不少人的目标从原先的解决温饱转变为追求内心充实,但由于现在的时间过得越来越快以及其他外部因素,我们对很多东西的获取越来越没耐心,例如书店经常会看到《7天精通Java》、《3天掌握XXX》等等之类的书籍…...

ubuntu22.04@Jetson OpenCV安装
ubuntu22.04Jetson OpenCV安装 1. 源由2. 分析3. 证实3.1 jtop安装3.2 jtop指令3.3 GPU支持情况 4. 安装OpenCV4.1 修改内容4.2 Python2环境【不需要】4.3 ubuntu22.04环境4.4 国内/本地环境问题4.5 cudnn版本问题 5. 总结6. 参考资料 1. 源由 昨天用Jetson跑demo程序发现帧率…...

OpenGL学习——17.模型
前情提要:本文代码源自Github上的学习文档“LearnOpenGL”,我仅在源码的基础上加上中文注释。本文章不以该学习文档做任何商业盈利活动,一切著作权归原作者所有,本文仅供学习交流,如有侵权,请联系我删除。L…...

6.2 数据库
本节介绍Android的数据库存储方式--SQLite的使用方法,包括:SQLite用到了哪些SQL语法,如何使用数据库管理操纵SQLitem,如何使用数据库帮助器简化数据库操作,以及如何利用SQLite改进登录页面的记住密码功能。 6.2.1 SQ…...

计算机设计大赛 深度学习人体跌倒检测 -yolo 机器视觉 opencv python
0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习的人体跌倒检测算法研究与实现 ** 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满…...
本地模拟发送、接收RabbitMQ数据
文章目录 前言一、相关文章二、相关代码1.模拟的 Channel 类2.接收消息3.模拟推送MQ数据前言 日常开发中,当线上RabbitMQ坏境还没准备好时,可在本地模拟发送、接收消息 一、相关文章 Docker安装RabbitMQ 【SpringCloud】整合RabbitMQ六大模式应用(入门到精通) Spring R…...

前端 webSocket 的使用
webSocket使用 注意要去监听websocket 对象事件,处理我们需要的数据 我是放在了最外层的index 内,监听编辑状态,去触发定义的方法。因为我这个项目是组件化开发,全部只有一个总编辑按钮,我只需监听是否触发了编辑即可…...

opencv图像处理(一)
一. OpenCV 简介 OpenCV 是一个跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 应用领域 1、人机互动 2、物体识别 3、图像分割 4、人脸识别 5、动作识别 6、运动跟踪 7、机器人 8、运动分析 9、机器视觉 10、…...

消息队列-RabbitMQ:workQueues—工作队列、消息应答机制、RabbitMQ 持久化、不公平分发(能者多劳)
4、Work Queues Work Queues— 工作队列 (又称任务队列) 的主要思想是避免立即执行资源密集型任务,而不得不等待它完成。我们把任务封装为消息并将其发送到队列,在后台运行的工作进程将弹出任务并最终执行作业。当有多个工作线程时,这些工作…...

前端秘法基础式(HTML)(第二卷)
目录 一.表单标签 1.表单域 2.表单控件 2.1input标签 2.2label/select/textarea标签 2.3无语义标签 三.特殊字符 一.表单标签 用来完成与用户的交互,例如登录系统 1.表单域 <form>通过action属性,将用户填写的数据转交给服务器 2.表单控件 2.1input标签 type…...
PTA-统计英文字母和数字字符[2]
本题要求编写程序,输入N个字符,统计其中英文字母、数字字符和其他字符的个数。 输入格式: 输入在第一行中给出正整数N,第二行输入N个字符,最后一个回车表示输入结束,不算在内。 输出格式: 在一行内按照 letter 英…...

Elasticsearch:将 IT 智能和业务 KPI 与 AI 连接起来 - 房间里的大象
作者:Fermi Fang 大象寓言的智慧 在信息技术和商业领导力的交叉点,蒙眼人和大象的古老寓言提供了一个富有洞察力的类比。 这个故事起源于印度次大陆,讲述了六个蒙住眼睛的人第一次遇到大象的故事。 每个人触摸大象的不同部位 —— 侧面、象牙…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...