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 大象寓言的智慧 在信息技术和商业领导力的交叉点,蒙眼人和大象的古老寓言提供了一个富有洞察力的类比。 这个故事起源于印度次大陆,讲述了六个蒙住眼睛的人第一次遇到大象的故事。 每个人触摸大象的不同部位 —— 侧面、象牙…...
记录一次线上问题排查:JDK序列化问题
在技术领域,我们常常被那些闪耀的、可见的成果所吸引。今天,这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力,让我们得以一窥未来的轮廓。然而,作为在企业一线构建、部署和维护复杂系统的实践者,我们深知…...
终极优化指南:NodeSource Node.js 二进制分发版的 Docker 镜像体积与启动速度革命
终极优化指南:NodeSource Node.js 二进制分发版的 Docker 镜像体积与启动速度革命 【免费下载链接】distributions NodeSource Node.js Binary Distributions 项目地址: https://gitcode.com/gh_mirrors/di/distributions NodeSource Node.js 二进制分发版为…...
如何在5分钟内搭建终端风格网站:LiveTerm自动化安装完整指南
如何在5分钟内搭建终端风格网站:LiveTerm自动化安装完整指南 【免费下载链接】LiveTerm 💻 Build terminal styled websites in minutes! 项目地址: https://gitcode.com/gh_mirrors/li/LiveTerm LiveTerm是一款功能强大的开源工具,能…...
AI辅助游戏开发新体验:让快马平台的AI模型为你的Superpowers项目编写剧情与平衡技能
最近在尝试用Superpowers框架开发一款魔法题材的RPG游戏,发现InsCode(快马)平台的AI辅助功能特别适合快速原型开发。这里分享下如何用AI模型辅助完成游戏剧情脚本和技能平衡设计的实践过程。 剧情脚本生成 输入"魔法学校学徒发现古老卷轴"这个简单设定后&…...
OpenClaw+Qwen3.5-9B低成本方案:自建接口替代OpenAI API
OpenClawQwen3.5-9B低成本方案:自建接口替代OpenAI API 1. 为什么选择Qwen3.5-9B作为OpenClaw的本地大脑 去年冬天,当我第一次尝试用OpenClaw自动化处理周报时,被OpenAI API的账单吓了一跳——简单的文件整理和摘要生成,一周竟消…...
Cache 维护实战:深入理解 ARMv8-A 架构下的 Invalidate 与 Clean 操作
1. 为什么需要关注Cache维护? 在嵌入式开发中,Cache就像是你办公桌上的文件架。当你频繁访问某些数据时,CPU会把这些数据放在Cache里,就像把常用文件放在手边一样。但问题来了:如果文件内容更新了(比如内存…...
避开高速接口时序坑:用IDELAY2和ODDR实战优化FPGA的input delay约束
高速接口时序优化实战:IDELAY2与ODDR的精细控制艺术 当FPGA设计遭遇GHz级高速接口时,传统的时序约束方法往往捉襟见肘。我曾在一个25Gbps背板项目中发现,即使精确计算了input delay约束,时序报告仍显示关键路径存在0.3ns的违例—…...
快速SEO排名服务需要多长时间见效_快速SEO排名服务有哪些常见的手段
快速SEO排名服务需要多长时间见效 在当今数字化时代,网站的在线可见度对于企业的成功至关重要。快速SEO排名服务应运而生,旨在帮助企业尽快在搜索引擎上获得更好的排名,从而提高流量和业务。但是,很多人都会疑惑,快速…...
Tomato-Novel-Downloader:高性能小说下载工具的技术实践与应用指南
Tomato-Novel-Downloader:高性能小说下载工具的技术实践与应用指南 【免费下载链接】Tomato-Novel-Downloader 番茄小说下载器不精简版 项目地址: https://gitcode.com/gh_mirrors/to/Tomato-Novel-Downloader 1 核心价值:重新定义小说下载体验 …...
Z-Image-GGUF文生图案例分享:看看AI能画出多美的图片
Z-Image-GGUF文生图案例分享:看看AI能画出多美的图片 1. 开篇:当文字遇见画笔 想象一下,你只需要输入一段描述,就能得到一张精美的图片。这不是科幻电影里的场景,而是Z-Image-GGUF带给我们的现实体验。作为阿里巴巴通…...
