boot项目配置邮箱发送

最近项目准备进入测试阶段,时间相对充沛些,便对邮箱的信息发送记录下!

邮箱设置-开启smtp协议及获取授权码

以QQ邮箱为例,其他邮箱大同小异!

开启协议

 获取授权码

具体代码

基于javax.mail实现

原文可看 前辈帖子

pom.xml
<!-- 邮件 -->
<dependency>
	<groupId>com.sun.mail</groupId>
	<artifactId>javax.mail</artifactId>
	<version >1.5.4 </version >
</dependency>
EmailVO.java类(前端上送参数)
package com.example.demo.vo;

import lombok.Data;

import java.util.List;

/**
 * @Auther: lr
 * @Date: 2024/6/12 16:14
 * @Description:
 */
@Data
public class EmailVO {

    private String content; //正文
    private String subject; //主题
    private List<String> toEmailPerson; //收件人
    private List<String> ccMail;  //抄送人
    private List<String> bccMail; //密送人
    private List<String> fileNames; //附件
}
EmailPropertiesConstant常量信息(一般会在系统设置中配置)
package com.example.demo.constant;

import lombok.Data;

/**
 * @Auther: lr
 * @Date: 2024/6/12 17:11
 * @Description:
 */
@Data
public class EmailPropertiesConstant {

    // 发件人smtp邮箱服务地址
    private String emailSmtpHost = "smtp.qq.com";
    // 发件人smtp端口
    private String emailSmtpPort = "25";
    // 开启TLS加密
    private String emailSmtpIsneedssl = "1";
    // 开启验证
    private String emailSmtpIsneedauth = "1";
    // 发件人邮箱地址
    private String userName = "xxx@qq.com";
    // smtp邮箱授权码
    private String userPassword = "xxx";
    // 发件人昵称
    private String userNicky = "测试人";

    // 邮箱开关状态 0关闭 1开启
    private String status = "1";
}
EmailUtil类(发送邮件)
package com.example.demo.util;

import com.example.demo.constant.EmailPropertiesConstant;
import com.example.demo.vo.EmailVO;
import com.sun.mail.util.MailSSLSocketFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.util.CollectionUtils;

import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;

/**
 * @Auther: lr
 * @Date: 2024/6/13 10:38
 * @Description:
 */
public class EmailUtil {

    private static final Logger logger = LoggerFactory.getLogger(EmailUtil.class);

    /**
     * 发送邮件
     * @param emailPropertiesConstant 系统信息配置
     * @param emailVO 邮件信息
     * @return
     */
    public static HashMap<String, Object> sendEmail(EmailPropertiesConstant emailPropertiesConstant,
                                                    EmailVO emailVO) {

        HashMap<String, Object> resultMap = new HashMap<>();

        if ("0".equals(emailPropertiesConstant.getStatus())) {
            logger.error("邮箱未开启");
            resultMap.put("code", 500);
            resultMap.put("message", "邮箱未开启!");
            return resultMap;
        }

        if (CollectionUtils.isEmpty(emailVO.getToEmailPerson())) {
            logger.error("邮件收件人为空");
            resultMap.put("code", 500);
            resultMap.put("message", "邮件收件人为空!");
            return resultMap;
        }

        try {
            // 设置参数
            Properties properties = System.getProperties();
            // smtp服务地址
            properties.put("mail.smtp.host", emailPropertiesConstant.getEmailSmtpHost());
            // smtp服务端口
            properties.put("mail.smtp.port", emailPropertiesConstant.getEmailSmtpPort());
            // 开启验证
            properties.put("mail.smtp.auth", "1".equals(emailPropertiesConstant.getEmailSmtpIsneedauth()) ? "true" : "false");
            // 开启TLS加密
            properties.put("mail.smtp.starttls.enable", "1".equals(emailPropertiesConstant.getEmailSmtpIsneedssl()) ? "true" : "false");
            // 是否启用socketFactory,默认为true
            properties.put("mail.smtp.socketFactory.fallback", "true");

            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            properties.put("mail.smtp.ssl.enable", "true");
            properties.put("mail.smtp.ssl.socketFactory", sf);
            // 建立会话,利用内部类将邮箱授权给jvm
            Session session = Session.getDefaultInstance(properties, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(emailPropertiesConstant.getUserName(), emailPropertiesConstant.getUserPassword());
                }
            });
            // 设置为true可以在控制台打印发送过程,生产环境关闭
            session.setDebug(true);
            // 创建邮件对象
            MimeMessage message = new MimeMessage(session);
            // 通过MimeMessageHelper设置正文和附件,否则会导致两者显示不全
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");

            //设置发件人 to为收件人,cc为抄送,bcc为密送
            helper.setFrom(new InternetAddress(emailPropertiesConstant.getUserName(), emailPropertiesConstant.getUserNicky()));
            helper.setTo(InternetAddress.parse(String.join(",", emailVO.getToEmailPerson()), false));
            if (!CollectionUtils.isEmpty(emailVO.getCcMail())) {
                helper.setCc(InternetAddress.parse(String.join(",", emailVO.getCcMail()), false));
            }
            if (!CollectionUtils.isEmpty(emailVO.getBccMail())) {
                helper.setBcc(InternetAddress.parse(String.join(",", emailVO.getBccMail()), false));
            }
            // 设置邮件主题
            helper.setSubject(emailVO.getSubject());
            //设置邮件正文内容
            helper.setText(emailVO.getContent());
            //设置发送的日期
            helper.setSentDate(new Date());
            // 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
            if (!CollectionUtils.isEmpty(emailVO.getFileNames())) {
                for (String fileName : emailVO.getFileNames()) {
                    FileDataSource fileDataSource = new FileDataSource(fileName);
                    helper.addAttachment(fileDataSource.getName(), fileDataSource);
                }
            }
            //调用Transport的send方法去发送邮件
            Transport.send(message);
            logger.info("发送邮件成功****************************!");
            resultMap.put("code", 200);
            resultMap.put("message", "邮件发送成功!");
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("邮件发送失败****************************!", e);
            resultMap.put("code", 500);
            resultMap.put("message", "邮件发送失败");
            resultMap.put("data", e);
            return resultMap;
        }
    }
}
EmailController类
package com.example.demo.controller;

import com.example.demo.constant.EmailPropertiesConstant;
import com.example.demo.util.EmailUtil;
import com.example.demo.vo.EmailVO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

/**
 * @Auther: lr
 * @Date: 2024/6/12 10:30
 * @Description:
 */
@RestController
@RequestMapping("/email")
public class EmailController {

    @PostMapping("/testEmail")
    public HashMap<String, Object> testEmail(@RequestBody EmailVO emailVO) {

        HashMap<String, Object> hashMap = EmailUtil.sendEmail(new EmailPropertiesConstant(), emailVO);
        return hashMap;
    }
}
测试
注意点

mail.smtp.auth,默认是true。一般用来测试QQ邮箱需要开启认证,而当时项目需求是客户方用内网连接邮箱服务器,此时不需要账号密码验证,所以设置为mail.smtp.auth=fale即可。但是当时生产上同时设置了mail.smtp.starttls.enable=false,未出现使用异常,到目前还是比较疑惑这个参数的设置。

发送邮件时 需要有网!!! 局域网也可。

org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.MessagingException: Exception reading response;
  nested exception is:
    javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?. Failed messages: javax.mail.MessagingException: Exception reading response;
  nested exception is:
    javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

解决办法:mail.smtp.socketFactory.fallback=true

基于spring-boot-starter-mail实现

系统参数是配置到application.yml文件中的,不利于系统维护邮件配置信息!!!

pom.xml
<!-- 邮件 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
application.yml文件
spring:
  mail:
    host: smtp.qq.com    #发件人smtp邮箱服务地址
    username: xxxx@qq.com    #发件人邮箱地址
    password: xxx    #smtp邮箱授权码
    default-encoding: UTF-8
    properties:
      userNicky: test    #发件人昵称
      status: 1    #邮箱开关状态 0关闭 1开启
      mail:
        smtp:
          auth: true    #开启加密
          ssl:
            enable: true
          starttls:
            enable: true    #开启TLS验证
          socketFactory:
            fallback: true
        debug: true
    port: 25    #发件人smtp端口
EmailUtil文件
package com.example.demo.util;

import com.example.demo.vo.EmailVO;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.activation.FileDataSource;
import javax.mail.internet.MimeMessage;
import java.util.HashMap;

/**
 * @Auther: lr
 * @Date: 2024/6/14 10:14
 * @Description:
 */

@Component
@AllArgsConstructor
public class EmailUtil {

    private static final Logger logger = LoggerFactory.getLogger(EmailUtil.class);

    @Autowired
    JavaMailSender javaMailSender;

    @Autowired
    MailProperties mailProperties;

    /**
     * 发送邮件
     * @param emailVO 邮件信息
     * @return
     */
    public HashMap<String, Object> sendEmail(EmailVO emailVO){

        HashMap<String, Object> resultMap = new HashMap<>();

        if ("0".equals(mailProperties.getProperties().get("status"))) {
            logger.error("邮箱未开启");
            resultMap.put("code", 500);
            resultMap.put("message", "邮箱未开启!");
            return resultMap;
        }

        if (CollectionUtils.isEmpty(emailVO.getToEmailPerson())) {
            logger.error("邮件收件人为空");
            resultMap.put("code", 500);
            resultMap.put("message", "邮件收件人为空!");
            return resultMap;
        }

        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(mailProperties.getUsername(), mailProperties.getProperties().get("userNicky"));
            helper.setTo(String.join(",", emailVO.getToEmailPerson()));
            if (!CollectionUtils.isEmpty(emailVO.getCcMail())) {
                helper.setCc(String.join(",", emailVO.getCcMail()));
            }
            if (!CollectionUtils.isEmpty(emailVO.getBccMail())) {
                helper.setBcc(String.join(",", emailVO.getBccMail()));
            }
            helper.setSubject(emailVO.getSubject());
            helper.setText(emailVO.getContent());
            // 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
            if (!CollectionUtils.isEmpty(emailVO.getFileNames())) {
                for (String fileName : emailVO.getFileNames()) {
                    FileDataSource fileDataSource = new FileDataSource(fileName);
                    helper.addAttachment(fileDataSource.getName(), fileDataSource);
                }
            }
            javaMailSender.send(message);
            logger.info("发送邮件成功****************************!");
            resultMap.put("code", 200);
            resultMap.put("message", "邮件发送成功!");
            return resultMap;
        }catch (Exception e) {
            e.printStackTrace();
            logger.error("邮件发送失败****************************!", e);
            resultMap.put("code", 500);
            resultMap.put("message", "邮件发送失败");
            resultMap.put("data", e);
            return resultMap;
        }
    }
}
controller
package com.example.demo.controller;

import com.example.demo.constant.EmailPropertiesConstant;
import com.example.demo.util.EmailUtil;
import com.example.demo.vo.EmailVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

/**
 * @Auther: lr
 * @Date: 2024/6/12 10:30
 * @Description:
 */
@RestController
@RequestMapping("/email")
public class EmailController {

    @Autowired
    EmailUtil emailUtil;

    @PostMapping("/test")
    public HashMap<String, Object> test(@RequestBody EmailVO emailVO) {

        HashMap<String, Object> hashMap = emailUtil.sendEmail(emailVO);
        return hashMap;
    }
}
测试

 目前接触到的项目使用过这两种方式,简单记录下!

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

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

相关文章

vscode 终端无法正常执行脚本命令如何解决

我们经常需要在vscode的中安装第三方依赖包&#xff0c;npm是前端目前最大的Node.js模块化管理系统&#xff0c;它能帮助开发者管理和发布Node.js模块。但很多时候我们在vscode的终端中执行npm install命令时经常会报以下错误&#xff1a; 但是在Windows的cmd命令提示符中执行n…

观测云产品更新 | BPF 网络日志、智能监控、告警策略等

观测云更新 网络 BPF 网络日志&#xff1a;优化 BPF 网络功能&#xff0c;增强 L4/L7 网络联动。 APM/RUM APM/RUM&#xff1a;新增 【Issue 自动发现】功能。启用该配置后&#xff0c;观测云会将符合配置项规则的错误数据记录自动创建 Issue。 监控 1、智能监控&#xff1…

【CT】LeetCode手撕—102. 二叉树的层序遍历

目录 题目1-思路2- 实现⭐102. 二叉树的层序遍历——题解思路 3- ACM实现3-1 二叉树构造3-2 整体实现 题目 原题连接&#xff1a;102. 二叉树的层序遍历 1-思路 1.借助队列 Queue &#xff0c;每次利用 ①while 循环遍历当前层结点&#xff0c;②将当前层结点的下层结点放入 …

GitCode热门开源项目推荐:Spider网络爬虫框架

在数字化高速发展时代&#xff0c;数据已成为企业决策和个人研究的重要资源。网络爬虫作为一种强大的数据采集工具受到了广泛的关注和应用。在GitCode这一优秀的开源平台上&#xff0c;Spider网络爬虫框架凭借其简洁、高效和易用性&#xff0c;成为了众多开发者的首选。 一、系…

反向海淘建站技术:开启跨境电商新篇章

反向海淘&#xff0c;作为跨境电商的一种创新模式&#xff0c;正逐渐改变着传统贸易的格局。在这个模式下&#xff0c;国内消费者能够直接购买到国外的商品&#xff0c;而国内的商家也能将产品销往海外市场。为了抓住这一机遇&#xff0c;建立一套高效、稳定的反向海淘网站至关…

线代老师大PK,这四位胜出!

说实话&#xff0c;线代真的别乱跟老师 因为每个老师讲课适用的人群不一样&#xff0c;比如都说李永乐老师线代讲的好&#xff0c;但是我去听完发现&#xff0c;李永乐老师的线代讲的虽然好&#xff0c;但是对于零基础或者基础不好的考生来说&#xff0c;真的有点不友好&#…

AI绘画SD3已来,本地首发实测体验,含本地部署说明(内附网盘模型及ComfyUI工作流下载)

大家好&#xff0c;我是画画的小强 SD3已来&#xff0c;Stability AI 此前宣布SD3将于6月12开源20 亿参数的SD3 模型SD3 Medium&#xff0c;昨天它已如期而至了。 根据官方内容所了解&#xff0c;SD3 Medium 可以说是目前很先进的文本到图像开放模型&#xff0c;包含 20 亿个…

C++ 34 之 单例模式

#include <iostream> #include <string.h> using namespace std;class King{// 公共的函数&#xff0c;为了让外部可以获取唯一的实例 public:// getInstance 获取单例 约定俗成static King* getInstance(){return true_king;}private: // 私有化// 构造函数设置为…

线性代数|机器学习-P12Ax=b条件下x最小值问题

文章目录 1. Axb下的最值问题-图形转换2. Gram-Schmidt 标准形3. 迭代法-Krylov子空间法 1. Axb下的最值问题-图形转换 假设我们有一个直线方程如下&#xff1a; 3 x 1 4 x 2 1 \begin{equation} 3x_14x_21 \end{equation} 3x1​4x2​1​​ 在二维平面上&#xff0c;各个范…

微信小程序投票系统(包含微信小程序端)

&#x1f4f1;微信投票小程序&#xff1a;轻松发起&#xff0c;快速统计 一、引言 在数字化时代&#xff0c;微信作为我们日常生活中不可或缺的社交工具&#xff0c;不仅为我们提供了沟通交流的平台&#xff0c;还衍生出了许多实用的小程序。其中&#xff0c;微信投票小程序凭…

C# WPF入门学习主线篇(三十三)—— 使用ICommand实现命令绑定

C# WPF入门学习主线篇&#xff08;三十三&#xff09;—— 使用ICommand实现命令绑定 在MVVM模式中&#xff0c;命令绑定是将用户交互&#xff08;如按钮点击&#xff09;与ViewModel中的方法连接起来的一种机制。使用ICommand接口可以实现这一功能&#xff0c;从而将UI逻辑与业…

快速掌握 Python requests 库发送 JSON 数据的 POST 请求技巧

在现代 Web 开发中&#xff0c;客户端与服务器之间进行数据交换的需求越来越普遍。而在 Python 这个强大的编程语言中&#xff0c;requests 库是一个广泛使用且功能强大的 HTTP 请求库。特别是在进行 API 调用时&#xff0c;发送 POST 请求并附带 JSON 数据是一个非常常见的需求…

跟卖五种常用采集方式,关键词采集升级,更加让新手上手更快!

今天给大家分享一个跟卖选品软件&#xff0c;相信很多卖家都在为选品而苦恼&#xff0c;人工筛选一天也筛选不出几个能用的链接&#xff0c;不仅耗费时间精力&#xff0c;还提升不了选品效率&#xff0c;今天就分享一款实用的选品工具&#xff0c;它能够帮助我们节省选品时间&a…

C++ 35 之 对象模型基础

#include <iostream> #include <string.h> using namespace std;class Students05{ public:// 只有非静态成员变量才算存储空间&#xff0c;其他都不算int s_a; // 非静态成员变量&#xff0c;算对象的存储空间double s_c;// 成员函数 不算对象的存储空间void f…

uniapp 仿写弹窗

页面 <template><view click"close" class"mask"><view click.stop"onClick" class"content"><text class"text">点击蒙层关闭</text></view></view> </template><scr…

Spring Cloud Alibaba Nacos作为服务配置中心实践

Nacos官网文档&#xff1a;Nacos 融合 Spring Cloud&#xff0c;成为注册配置中心 【1】服务实例 ① pom依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </de…

【Spine学习07】之跑步动作制作思路总结

前几节试着做了待机和走路动画 现在开始尝试做跑步动作 注意跑步动作和走路一样 暂时不需要使用IK约束但是会用到塞贝尔曲线&#xff08;模拟裙子飞起动效&#xff09; 第一步&#xff1a; 先将人物整体斜放置&#xff08;因为人跑步的时候&#xff0c;身体前倾&#xff09; …

平价不入耳耳机测评,5大产品超详细测评分析!

随着音乐技术的不断发展&#xff0c;开放式耳机已成为音乐发烧友们的首选。从最初的简单听歌&#xff0c;到现在高清解析&#xff0c;开放式耳机的不断改进和发展。如今&#xff0c;音质纯净&#xff0c;佩戴舒适&#xff0c;无论是配置、性能还是音质都可以做到最好&#xff0…

计算机网络 —— 应用层(DNS域名系统)

计算机网络 —— 应用层&#xff08;DNS域名系统&#xff09; 什么是DNS域名的层次结构域名分类 域名服务器的分类域名解析方式递归查询&#xff08;Recursive Query&#xff09;迭代查询&#xff08;Iterative Query&#xff09;域名的高速缓存 我们今天来看DNS域名系统 什么…

AI绘画SD下载安装教程,学习AI绘画软件必看(SD怎么安装,SD安装教程,安装stable diffusion软件必看)

大家好&#xff0c;我是设计师阿威 最近很火很有趋势的便是AI人工智能了&#xff0c;提到AI大家肯定都不陌生&#xff08;AIGC&#xff09;大家也很熟知&#xff0c;但是要问应用的工具有哪些肯定很多人说不出来几个&#xff0c;但是比较厉害的就是大众所认识的SD-stable diff…