基于JavaMailSenderImpl和velocity模板的邮件发送

   Java邮箱集成发送,  本文介绍了基于JavaMailSenderImpl和velocity模板引擎,发送自定义的邮件内容。

一、依赖引入

<dependency>
    <groupId>com.crygier</groupId>
    <artifactId>SpringUtils</artifactId>
    <version>1.0.1</version>
    <scope>compile</scope>
</dependency>
<!--邮件服务-->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>com.crygier</groupId>
    <artifactId>SpringUtils</artifactId>
    <version>1.0.1</version>
    <scope>compile</scope>
</dependency>

二、邮箱发送工具类(javaMailSenderImpl)

SysEmailServiceProvider.java

@Component
@Scope(value = "singleton")
public class SysEmailServiceProvider {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private IFactoryEmailManageService factoryEmailManageService;
    /**
     * 系统邮箱发送服务实例,单例模式下使用到时再去加载
     */
    private volatile JavaMailSenderImpl javaMailSender;

    /**
     * 双重检测机制懒汉式单例模式,防止多线程下多次实例化对象
     *
     * @return
     */
    public JavaMailSenderImpl getJavaMailSender() {
        if (javaMailSender == null) {
            // 在代码块上加锁,比直接在方法上加锁效率高,因为锁的范围小了
            synchronized (SysEmailServiceProvider.class) {
                if (javaMailSender == null) {
                    // 从数据库查询邮件发送服务器配置
                    FactoryEmailManage sysEmail = factoryEmailManageService.selectFactoryEmailManageById(1L);
                    // 实例化对象
                    javaMailSender = buildJavaMailSenderBySysEmail(sysEmail);
                }
            }
        }
        return javaMailSender;
    }

    /**
     * 清除当前的邮件发送对象(一般用于修改系统邮箱发送服务时)
     */
    public void clearJavaMailSender() {
        // 直接赋值为null,用的时候再实例化
        javaMailSender = null;
    }

    /**
     * 根据邮件服务配置对象生成邮件发送实例对象
     *
     * @param email
     * @return
     */
    public JavaMailSenderImpl buildJavaMailSenderBySysEmail(FactoryEmailManage email) {
        if (email == null) {
            logger.warn("邮件发送服务配置为null,无法实例化对象");
            return null;
        }
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
        try {
            javaMailSender.setHost(email.getEmailHost());
            javaMailSender.setUsername(email.getEmailName());
            javaMailSender.setPassword(RsaUtils.decryptByPrivateKey(email.getEmailPassword()));
            javaMailSender.setPort(email.getEmailPort());
            javaMailSender.setProtocol(email.getEmailProtocol());
            javaMailSender.setDefaultEncoding("utf-8");
        } catch (Exception e) {
            logger.error("实例化邮件发送对象失败,失败原因:{}", e.getMessage());
        }
        return javaMailSender;
    }

    /**
     * 邮件接收服务实例对象(不涉及多线程调用)
     */
    private Store store;

    /**
     * 简单懒汉式单例模式,因为这个对象不涉及到多线程调用
     *
     * @return
     */
    public Store getStore() throws Exception {
        if (store == null) {
            // 从数据库查询邮件发送服务器配置
            FactoryEmailManage sysEmail = factoryEmailManageService.selectFactoryEmailManageById((long) 1);
            store = buildStoreBySysEmail(sysEmail);
        }
        return store;
    }

    /**
     * 清除当前的邮件接收对象(一般用于修改系统邮箱接收服务时)
     */
    public void clearStore() {
        // 直接赋值为null,用的时候再实例化
        store = null;
    }


    /**
     * 根据邮件服务配置对象生成邮件接收实例对象
     *
     * @param email
     * @return
     */
    public Store buildStoreBySysEmail(FactoryEmailManage email) throws Exception {
        if (email == null) {
            logger.warn("邮件接收服务配置为null,无法实例化对象");
            return null;
        }
        Properties props = System.getProperties();
        if ("pop3s".equals(email.getEmailProtocol())) {
            props.setProperty("mail.pop3s.host", email.getEmailHost());
            props.setProperty("mail.pop3s.port", email.getEmailPort().toString());
            props.setProperty("mail.pop3s.auth", "true");
            props.setProperty("mail.pop3s.socketFactory.class",
                    "javax.net.ssl.SSLSocketFactory");
            props.setProperty("mail.pop3s.ssl.trust", "*");
        } else if ("pop3".equals(email.getEmailProtocol())) {
            props.setProperty("mail.pop3.host", email.getEmailHost());
            props.setProperty("mail.pop3.port", email.getEmailPort().toString());
        } else {
            throw new Exception("邮件接收服务器暂不支持pop3以及pop3s之外的协议");
        }
        Session session = Session.getDefaultInstance(props, null);
        Store store = null;
        try {
            store = session.getStore(email.getEmailProtocol());
        } catch (NoSuchProviderException e) {
            logger.error(e.getMessage(), e);
            throw new Exception(e.getMessage());
        } finally {
            return store;
        }
    }


}

三、邮箱发送工具类(自定义内容)

样式调整、发件人、收件人、内容、主题等自定义设置,本文加上了图片和模板内容。

@Component
public class EmailSendUtils {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private IFactoryEmailManageService factoryEmailManageService;
    @Autowired
    private SysEmailServiceProvider sysEmailServiceProvider;


    public void sendEmailAssignManage(Map<String, Object> addresseeMap, String content) throws Exception {

        try {
            JavaMailSenderImpl javaMailSender = sysEmailServiceProvider.getJavaMailSender();
            
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "utf-8");
            mimeMessageHelper.setFrom(javaMailSender.getUsername());
            if(addresseeMap.get("toReceiverGroup")!=null){ //收件人设置
                mimeMessageHelper.setTo((String[]) addresseeMap.get("toReceiverGroup"));
            }else if(addresseeMap.get("toReceiver")!=null){
                mimeMessageHelper.setTo(new String[]{addresseeMap.get("toReceiver").toString()});
            }
            //邮件主题
            mimeMessageHelper.setSubject(addresseeMap.get("emailSubject").toString());
            //邮件内容
            mimeMessageHelper.setText(content, true);
             //邮件内容-图片
            if(addresseeMap.get("logopng")!=null){
                mimeMessageHelper.addInline("logo", (ClassPathResource)addresseeMap.get("logopng"));
            }
            if(addresseeMap.get("topbackground")!=null){
                mimeMessageHelper.addInline("topbackground", (ClassPathResource)addresseeMap.get("topbackground"));
            }
            javaMailSender.send(mimeMessage);
        } catch (MailAuthenticationException e) {
            logger.error(e.getMessage(), e);
            logger.error("邮箱用户名或密码不正确");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.error("发送邮件失败,请检查邮箱配置");

        }
    }

}

四、邮箱发送

1、velocity模板内容设置

        SimpleDateFormat formatterDay = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        StringWriter sw = new StringWriter();
        VelocityContext context = new VelocityContext();
/内容设置
       

        context.put("warningType", "一次直通率预警");
        context.put("caId", "S01");
        context.put("content", factoryWarning.getContent());
        context.put("responsibility", "责任人name");
        context.put("happenTime", formatterDay.format(factoryWarning.getHappenTime()));
        context.put("currentTime", formatterDay.format(new Date()));

        Template template = Velocity.getTemplate("vm/warningSingleEmail.vm");
        template.merge(context, sw);
        String mailText = sw.toString();

2、velocity模板

warningSingleEmail.vm

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body style="font-size: 14px ;width: 100%;height: 100%;">

<div style="background: #EEE;width: 90%; height: 100%;margin:0px auto;">
    <div style="max-width: 680px;width: 680px;margin:0px auto;">
        <table align="center" border="0" cellpadding="0" cellspacing="0"
               style='background: rgb(255, 255, 255); width: 680px; font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", 微软雅黑, Arial, sans-serif; border: none; border-collapse: collapse; max-width: 680px; margin: 0; auto; empty-cells: show;'>
            <tbody>
            <tr style="user-select: none;">
                <td align="center"
                    style="width: 680px; padding: 0px; text-align: center; min-width: 5px;  user-select: text;">
                    <img
                            alt="top-background" width="680"
                            src="cid:topbackground"
                            style="width: 680px; max-width: 100%;height: 150px; cursor: pointer;"
                            >
##                    <p style="position: absolute;left: 35%; top: 1%;color: white; font-size: 3rem; font-weight:bolder; font-family: fantasy">预警系统提醒</p>
            </tr>
            </tbody>
        </table>
        <table align="center" border="0" cellpadding="0" cellspacing="0"
               style='background: rgb(239, 249, 254); width: 680px; font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", 微软雅黑, Arial, sans-serif; border: none; border-collapse: collapse; max-width: 680px; margin: 0px; empty-cells: show;'>
            <tbody>
            <tr style="background: rgb(239, 249, 254); user-select: none;">
                <td style="background: rgb(239, 249, 254); width: 40px; color: rgb(160, 160, 160); line-height: 1.6; padding: 10px 0px; font-size: 14px; min-width: 5px;  user-select: text;">
                    &nbsp;
                </td>
                <td style="background: rgb(239, 249, 254); max-width: 600px;height: 500px; width: 600px; color: rgb(160, 160, 160); line-height: 1.6; padding: 10px 0px; font-size: 14px; min-width: 5px; user-select: text; text-align: left;">
                    <p style="text-align: left;"><span style="color: rgb(71, 85, 119);">尊敬的用户:</span></p>
                    <p><span style="color: rgb(71, 85, 119);">&nbsp; &nbsp; &nbsp; &nbsp;您有新的${warningType}产生,请及时处理!</span>
                    </p>
                    <p><span style="color: rgb(71, 85, 119);"><br></span></p>
                    <p><span style="color: rgb(71, 85, 119);">以下为本次预警的主要信息:</span></p>
                    <p><span style="color: rgb(71, 85, 119);"><b>预警类别:</b>${warningType}</span></p>
                    #if(${caId})
                        <p><span style="color: rgb(71, 85, 119);"><b>线别:</b>${caId}</span></p>
                    #end
                    <p><span style="color: rgb(71, 85, 119);"><b>描述:</b>${content}</span></p>
                    <p><span style="color: rgb(71, 85, 119);"><b>责任人:</b>${responsibility}</span></p>
                    <p><span style="color: rgb(71, 85, 119);"><b>发生时间:</b>${happenTime}</span></p>
                    <div style="float: right;font-size: 16px;font-weight: bold;margin-top: 20px">${currentTime}</div>
                </td>
                <td style="background: rgb(239, 249, 254); width: 40px; color: rgb(160, 160, 160); line-height: 1.6; padding: 10px 0px; font-size: 14px; min-width: 5px;  user-select: text;">
                    <br></td>
            </tr>
            </tbody>
        </table>
        <table align="center" border="0" cellpadding="0" cellspacing="0"
               style='background: rgb(255, 255, 255); width: 680px; height: 150px;font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", 微软雅黑, Arial, sans-serif; border: none; border-collapse: collapse; max-width: 680px; margin: 0px auto; empty-cells: show;'>
            <tbody>
            <tr style="user-select: none;">
                <td align="center"
                    style="width: 680px; padding: 0px; text-align: center; min-width: 5px; height: 150px; user-select: text;">
                    <img
                            alt="lbs-foot" width="680"
                            src="cid:logo"
                            style="width: 680px; max-width: 40%; min-height: 50%;cursor: pointer;"
                            />
            </tr>
            </tbody>
        </table>

    </div>
</div>
</body>
</html>



3、收发件人和主题等设置

            Map<String, Object> content = new HashMap<>();
            //设置收件人邮箱
//            content.put("toReceiver", "**@163.com");
            //设置收件人邮箱-多人群组
                String receiversEmail[] = ["**@163.com","**@126.com"];
                content.put("toReceiverGroup", receiversEmail);
            //设置邮件主题
            content.put("emailSubject", "预警系统:您有新的预警产生!");
            ClassPathResource logoPng = new ClassPathResource("vm/warning-logo.png");//从本地文件夹中获取所需图片
            content.put("logopng",logoPng);
            ClassPathResource topbackground = new ClassPathResource("vm/warning-top.png");//从本地文件夹中获取所需图片
            content.put("topbackground",topbackground);

4、发送邮件调用

//发送邮件
emailSendUtils.sendEmailAssignManage(content, mailText);

五、效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/798133.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

秋招突击——7/12——复习{每日温度、完全平方数、无重复最长子串}——新作{字节面试——控制多线程按照顺序输出}

文章目录 引言复习每日温度复习实现参考学习 完全平方数复习实现参考学习 无重复字符的最长子串复习实现参考学习 新作控制多线程输出Java实现线程——不使用锁实现使用synchronized关键实现——使用锁实现使用synchronized、wait和notify关键字实现 总结 引言 今天又要面试字…

CSS相对定位和绝对定位的区别

CSS相对定位和绝对定位的区别 区别1&#xff1a;相对的对象不同 相对定位是相对于自己绝对定位是相对于离自己最近的有定位的祖先 区别2:是否会脱离文档流 相对定位不会脱离文档流&#xff0c;不会影响其他元素的位置绝对定位会脱离文档流&#xff0c;会影响其他元素的布局 代…

MAC通过SSH连接VirtualBox中的虚拟机

1、虚拟机网络连接方式使用桥接方式-桥接网卡 2、重启虚拟机&#xff0c;查看虚拟机ip地址是否跟Mac宿主机在同一网段 3、SSH工具&#xff08;推荐Tabby&#xff09;输入IP、用户名和密码就能连接虚拟机了

JS进阶-异常处理

学习目标&#xff1a; 掌握异常处理 学习内容&#xff1a; throw抛异常try/catch捕获异常debugger throw抛异常&#xff1a; 异常处理是预估代码执行过程中可能发生的错误&#xff0c;然后最大程度的避免错误的发生导致整个程序无法继续运行。 <title>throw抛异常</…

基于AT89C51单片机的多功能自行车测速计程器(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的多功能自行车测速计程器的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 选题背景 原理图 PCB图 仿真图 代码 系统论文 资源下载 选题背景 美丽的夜晚&…

Ubuntu 安装 XRDP,替代系统自带RDP远程桌面

起因&#xff0c;Ubuntu的自带RDP远程桌面很好用&#xff0c;但很傻卵&#xff0c;必须登录。 而设置了自动登录也不能解开KEYRING&#xff0c;必须必须必须用GUI手动登录。 &#xff08;我远程我用头给你坐机子面前开显示器先登录&#xff1f;&#xff1f;&#xff09; 比起VN…

Linux - 基础开发工具(yum、vim、gcc、g++、make/Makefile、git)

目录 Linux软件包管理器 - yum Linux下安装软件的方式 认识yum 查找软件包 安装软件 如何实现本地机器和云服务器之间的文件互传 卸载软件 Linux编辑器 - vim vim的基本概念 vim下各模式的切换 vim命令模式各命令汇总 vim底行模式各命令汇总 vim的简单配置 Linux编译器 - gc…

网络技术相关知识概念

网络技术&#xff1a; 进程&#xff08;Process&#xff09; 定义&#xff1a;进程是程序的一次执行过程&#xff0c;它有自己的内存空间和系统资源&#xff08;资源独立&#xff09;。特性&#xff1a; 每个进程都有唯一的PID&#xff08;进程ID&#xff09;。进程间通信&am…

笔记 4 :linux 0.11 中继续分析 0 号进程创建一号进程的 fork () 函数

&#xff08;27&#xff09;本条目开始&#xff0c; 开始分析 copy_process () 函数&#xff0c;其又会调用别的函数&#xff0c;故先分析别的函数。 get_free_page &#xff08;&#xff09; &#xff1b; 先 介绍汇编指令 scasb &#xff1a; 以及 指令 sstosd &#xff1a;…

Vue1-Vue核心

目录 Vue简介 官网 介绍与描述 Vue的特点 与其它 JS 框架的关联 Vue周边库 初识Vue Vue模板语法 数据绑定 el与data的两种写法 MVVM模型 数据代理 回顾Object.defineProperty方法 何为数据代理 Vue中的数据代理 数据代理图示 事件处理 事件的基本使用 事件修…

Appium自动化测试系列: 2. 使用Appium启动APP(真机)

历史文章&#xff1a;Appium自动化测试系列: 1. Mac安装配置Appium_mac安装appium-CSDN博客 一、准备工作 1. 安卓测试机打开调试模式&#xff0c;然后使用可以传输数据的数据线连接上你的电脑。注意&#xff1a;你的数据线一定要支持传输数据&#xff0c;有的数据线只支持充…

MySQL:库操作

1. 创建数据库 create database [if not exists] name [create_specification], [create_specification]... []内为可选的选项 create_specification: character set charset_name -- 指定数据库采用的字符集 -- 数据库未来存储数据 collate collation_name -- 指定数据库字符…

Python3极简教程(一小时学完)下

目录 PEP8 代码风格指南 知识点 介绍 愚蠢的一致性就像没脑子的妖怪 代码排版 缩进 制表符还是空格 每行最大长度 空行 源文件编码 导入包 字符串引号 表达式和语句中的空格 不能忍受的情况 其他建议 注释 块注释 行内注释 文档字符串 版本注记 命名约定 …

github actions方式拉取docker镜像

参考&#xff1a; https://wkdaily.cpolar.cn/archives/gc 注意github actions提供的免费虚拟机空间有限&#xff0c;空间不足会报错&#xff0c;查看大概语句有10来G 我在workflow file里加了df -h 运行查看磁盘情况&#xff1a; 通过pwd命令&#xff0c;可以知道运行目录/ho…

深度加速器 为游戏而生

使用深度加速器的基本步骤如下 首先&#xff0c;访问深度加速器的官方网站或授权下载渠道&#xff0c;下载最新版本的深度加速器客户端。 下载完成后&#xff0c;电脑版直接双击打开免安装&#xff0c;将深度加速器安装到您的计算机或移动设备上。 注册与登录&#xff1a; 打…

OrangePi AI Pro 实测:感受 AI 应用的独特魅力与强大性能

OrangePi AiPro介绍和初始化配置 小寒有话说一、OrangePi AiPro介绍1. 主板详情2. 开发配置3. 镜像烧录4. 设备连接5. WiFi连接6. NVMe SSD的安装和挂载7. 更新下载源并下载必要的软件8. 扩展内存 二、Jupyter Lab AI测评应用案例1. 获取Jupyter Lab 网址链接2. 图像提取文字3.…

python开发prometheus exporter--用于hadoop-yarn监控

首先写python的exporter需要知道Prometheus提供4种类型Metrics 分别是&#xff1a;Counter, Gauge, Summary和Histogram * Counter可以增长&#xff0c;并且在程序重启的时候会被重设为0&#xff0c;常被用于任务个数&#xff0c;总处理时间&#xff0c;错误个数等只增不减的指…

电脑硬盘里的文件能保存多久?电脑硬盘文件突然没了怎么办

在数字化时代&#xff0c;电脑硬盘作为我们存储和访问数据的重要设备&#xff0c;承载着无数珍贵的回忆、工作成果和创意灵感。然而&#xff0c;硬盘里的文件能保存多久&#xff1f;当这些文件突然消失时&#xff0c;我们又该如何应对&#xff1f;本文将深入探讨这两个问题&…

【Python】深入了解`zip()`函数:高效地组合迭代对象

文章目录 1. zip()函数的基本用法2. 处理不同长度的可迭代对象3. 解压缩序列4. 使用zip()处理多个可迭代对象5. 结合for循环使用zip()6. 与字典结合使用7. 处理嵌套结构8. 与*运算符结合使用9. 实际应用示例&#xff1a;合并多个数据源10. 总结 Python中的zip()函数是一个强大且…

71.WEB渗透测试-信息收集- WAF、框架组件识别(11)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;70.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;10&#xff09;-CSDN博客 如果有…