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…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...

2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...

【技巧】dify前端源代码修改第一弹-增加tab页
回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码,在知识库增加一个tab页"HELLO WORLD",完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…...
CppCon 2015 学习:Simple, Extensible Pattern Matching in C++14
什么是 Pattern Matching(模式匹配) ❝ 模式匹配就是一种“描述式”的写法,不需要你手动判断、提取数据,而是直接描述你希望的数据结构是什么样子,系统自动判断并提取。❞ 你给的定义拆解: ✴ Instead of …...

Unity-ECS详解
今天我们来了解Unity最先进的技术——ECS架构(EntityComponentSystem)。 Unity官方下有源码,我们下载源码后来学习。 ECS 与OOP(Object-Oriented Programming)对应,ECS是一种完全不同的编程范式与数据架构…...