boot项目配置邮箱发送

news2024/12/23 10:39:23

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

邮箱设置-开启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.coloradmin.cn/o/1821830.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

达梦数据库上市,给数据库国产化加油打气

吉祥学安全知识星球&#x1f517;除了包含技术干货&#xff1a;《Java代码审计》《Web安全》《应急响应》《护网资料库》《网安面试指南》还包含了安全中常见的售前护网案例、售前方案、ppt等&#xff0c;同时也有面向学生的网络安全面试、护网面试等。 作为家乡的企业上市必须…

蓝牙音频解码芯片TD5163介绍,支持红外遥控—拓达半导体

蓝牙芯片TD5163A是一颗支持红外遥控、FM功能和IIS音频输出的蓝牙音频解码芯片&#xff0c;此颗芯片的亮点在于同时支持真立体声&单声道、TWS功能、PWM、音乐频谱和串口AT指令控制等功能&#xff0c;芯片在支持蓝牙无损音乐播放的同时&#xff0c;还支持简单明了的串口发送A…

RTE Open Day 联手 AGI Playground,最先锋 RTE+AI Builders 齐聚北京丨活动招募

6 月 22 日至 23 日&#xff0c;北京&#xff0c;AGI Playground 2024 即将引燃今夏&#xff01; 这场备受瞩目的 AGI 盛会&#xff0c;将汇聚王小川、杨植麟等众多创业者。RTE 开发者社区的 Builders 和 RTE Open Day 也将亮相其中&#xff01; 「有一群人在一起&#xff0c…

云计算【第一阶段(13)】Linux的Find命令

一、查找文件或目录Find 格式 find 查找的范围 类型 查找数据 1.1、常用查找类型 查找类型关键字说明按名称查找-name根据目标文件的名称进行查找&#xff0c;允许使用“*”及“&#xff1f;”通配符按文件大小查找-size根据目标文件的大小进行查找&#xff0c;一般使用…

[华为北向网管NCE开发教程(6)消息订阅

1.作用 之前介绍的都是我们向网管NCE发起请求获取数据&#xff0c;消息订阅则反过来&#xff0c;是网管NCE系统给我们推送信息。其原理和MQ&#xff0c;JMS这些差不多&#xff0c;这里不过多累述。 2.场景 所支持订阅的场景有如下&#xff0c;以告警通知为例&#xff0c;当我…

基于51单片机智能路灯控制—人数、光强

基于51单片机智能路灯控制 &#xff08;仿真&#xff0b;程序&#xff09; 功能介绍 具体功能&#xff1a; 1.光敏电阻与电阻组成分压电路&#xff0c;环境光强度越强&#xff0c;光敏电阻越小&#xff0c;ADC检测的电压越强&#xff1b; 2.红外计数传感器&#xff08;按键…

Introducing Index-1.9B

简介 大家好&#xff0c;今天我们很高兴首次发布Index系列模型中的轻量版本&#xff1a;Index-1.9B系列 本次开源的Index-1.9B 系列包含以下模型&#xff1a; Index-1.9B base : 基座模型&#xff0c;具有 19亿 非词嵌入参数量&#xff0c;在2.8T 中英文为主的语料上预训练&…

01本地图像导入及参数设置

左边工具栏&#xff1a;采集-》图像源&#xff0c;点击后 拉到流程窗口中 在右边有三个按钮可以添加图像和图像文件夹。 双击 图像源 可以打开 参数设置 参数说明&#xff1a; 像素格式&#xff1a;MONO8 表示图像为黑白图像&#xff0c;RGB24为彩色图像。看你想以什么图像打开…

JS手写题解析

手写Promise class MyPromise {constructor(executor) { // executor执行器this.status pending // 等待状态this.value null // 成功或失败的参数this.fulfilledCallbacks [] // 成功的函数队列this.rejectedCallbacks [] // 失败的函数队列const that thisfunction reso…

我的创作纪念日 --- 携手CSDN的512天

起航 时间过得可真快啊&#xff0c;转眼间距离我发的第一篇文章已经有512天了&#xff0c;那是一个寒假&#xff0c;当我发现自己又浑浑噩噩的过完了一个学期时&#xff0c;我才开始思考自己想拥有怎样的人生&#xff0c;然后我就写下了自己的第一篇文章 about me&#xff0c;…

哪些国产项目管理软件最受欢迎?详细解读六大主流系统

满足国产化诉求的6款项目管理系统&#xff1a;PingCode、Worktile、Teambition、禅道、华为云DevCloud、Tapd。 国产项目管理软件以其定制化高、适应本土市场的优势&#xff0c;正成为越来越多企业的选择。本文将探讨几款优秀的国产项目管理工具&#xff0c;帮助您找到提升团队…

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

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

癫狂头歌动态规划之跳跃问题Python

第一关跳跃问题 这里我照着图片的代码敲市过不去&#xff0c;真够癫狂的 def CollectValues():n, m map(int, input().split()) #获得输入信息p [list(map(int, input().split())) for i in range(n)] #获得输入信息dp [[-10000] * m for i in range(n)] #初始化动态规划数…

【K8s】专题五(2):Kubernetes 配置之 Secret

以下内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01;如果对您有帮助&#xff0c;烦请点赞、关注、转发&#xff01;欢迎扫码关注个人公众号&#xff01; 目录 一、基本介绍 二、主要特性 三、资源清单&#xff08;示例&#xff09; 四、常用操作 一…

入职3年-我如何做一名AI产品经理(文末福利)

引言 从2021年校招加入京东开始&#xff0c;我一直从事AI产品经理的工作&#xff0c;有幸见证了AI行业的热情从一台台服务器烧到了全世界各个角落&#xff0c;也见证了京东AI中台团队的影响力如何一步步的扩大。从21年的迷茫到24年的坚定&#xff0c;很庆幸我正走在适合自己的…

深圳职工餐厅安全检测新策略:自动可燃气体报警器的作用

在现代化的都市生活中&#xff0c;安全问题一直备受关注。 对于深圳众多职工餐厅来说&#xff0c;如何确保餐厅内的燃气使用安全&#xff0c;防止因可燃气体泄露而引发的火灾事故&#xff0c;成为了一项重要的挑战。 近年来&#xff0c;自动可燃气体报警器以其高度的灵敏度和…

微软无所不知的人工智能召回功能“Recall”被推迟,将不会与 Copilot Plus PC 一起提供

微软计划下周推出新的 Copilot Plus 个人电脑&#xff0c;取消其备受争议的 Recall 功能&#xff0c;该功能可以截取您在这些新笔记本电脑上所做的所有操作。该软件制造商推迟了 Recall&#xff0c;以便可以通过 Windows Insider 程序对其进行测试&#xff0c;此前该公司最初承…

Redis 7.x 系列【2】单机部署

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. Windows2. Linux 1. Windows Redis作为一个高性能的内存数据库&#xff0c;和Linu…

爬虫-模拟登陆博客

import requests from bs4 import BeautifulSoupheaders {user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36 } # 登录参数 login_data {log: codetime,pwd: shanbay520,wp-submit: …

C++ 36 之 this指针

#include <iostream> #include <string.h> using namespace std;// this指针 永远指向当前对象 class Students06{ public:int age;// int m_age; //member成员首字母mStudents06(int age){// 1.解决命名冲突的问题 this指针找成员变量需要使用->符号this->…