用Java发送邮件服务

用Java实现QQ邮箱发送邮件
一个邮件服务的demo

1.先开启邮箱SMPT服务,并获取授权码

对于QQ邮箱开启相关服务的步骤:
1.登录QQ邮箱网页版
2.点击右上角的账号与安全
在这里插入图片描述
3.在账号和安全里面开启授权码
在这里插入图片描述

2.开启SMPT网络端口通过本地防火墙

具体操作可见该链接:smpt网络端口通过防火墙设置
我个人按照里面设置了几个端口后,发现不起作用,后面将其设置为所有端口,才起作用。可以列表上选择配置后的入站规则里面,在配置的规则上右键,在属性里面将本地端口设置为所有端口
在这里插入图片描述

3.配置application.yml里的配置信息

spring:
  # thymeleaf配置
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
  mail:
    protocol: smtps
    host: smtp.qq.com # 发件邮箱对应的服务器域名,如果是163邮箱:smtp.163.com   qq邮箱: smtp.qq.com
    username: 111@qq.com
    password: xxxxxxx # 注意,此处不是邮箱的登录密码,而是第一步的授权码
    properties:
      mail:
        smtp:
          auth: true
          ssl:
            enable: true
            required: true
    default-encoding: utf-8

4.配置类相关信息

package com.example.ftserver.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
// 使用该注解的时候,需要在启动类上添加 @EnableConfigurationProperties
@ConfigurationProperties(prefix = "spring.mail")
@Data
public class EmailConfig {
    private String host;
    /**
     * 注意:此处不是邮箱的登录密码,而是邮箱的授权码
     */
    private String password;
    private String username;
}

5.邮件发送主类

package com.example.ftserver.mail;


import com.example.ftserver.config.EmailConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.*;
import javax.mail.internet.MimeMessage;
import java.util.Map;
import java.util.Properties;

@Component
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
@Slf4j
public class MailServer {

    private final EmailConfig config;
    private final TemplateEngine engine;

    @Value("${spring.mail.properties.mail.smtp.auth}")
    private boolean auth;
    @Value("${spring.mail.properties.mail.smtp.ssl.enable}")
    private boolean sslEnable;
    @Value("${spring.mail.properties.mail.smtp.ssl.required}")
    private boolean sslRequired;


    public boolean sendMail(String to, String subject, String content) {
        try {
            MimeMessage mimeMessage = commonSet(to, subject, content);
            Transport.send(mimeMessage);
            return true;

        } catch (MessagingException e) {
            log.error("Error sending mail", e);
            return false;
        }
    }
    /**
     * 发送邮件的方法
     * 该方法通过模板名称和参数生成邮件内容,并发送给指定的收件人
     * 它封装了邮件内容的生成和邮件发送的逻辑,使得发送带有动态内容的邮件变得简单和可重用
     *
     * @param to 收件人的邮箱地址,用于指定邮件的接收方
     * @param subject 邮件的主题,用于在收件人的邮箱中标识邮件
     * @param templateName 邮件内容的模板名称,用于生成邮件的正文
     * @param params 用于替换模板中占位符的参数集合,使得邮件内容可以动态生成
     * @return 发送邮件的结果,true表示邮件发送成功,false表示邮件发送失败
     */
    public boolean sendMail(String to, String subject, String templateName, Map<String, Object> params) {
        // 根据模板名称和参数生成邮件内容
        String content = getContent(templateName, params);
        return sendMail(to, subject, content);
    }
    /**
     * 创建并配置邮件消息的通用设置
     * 该方法用于设置邮件的基本信息,包括收件人、主题、内容等,并进行SMTP服务器的配置和身份验证
     *
     * @param to 收件人的邮箱地址
     * @param subject 邮件的主题
     * @param content 邮件的正文内容
     * @return 已配置好的MimeMessage对象
     * @throws MessagingException 如果邮件发送过程中出现异常
     */
    private MimeMessage commonSet(String to, String subject, String content) throws MessagingException {
        Properties properties = new Properties();
        properties.put("mail.smtp.auth", auth);
        properties.put("mail.smtp.host", config.getHost());
        properties.put("mail.user", config.getUsername());
        properties.put("mail.password", config.getPassword());
        properties.put("mail.smtp.ssl.enable", sslEnable);
        properties.put("mail.smtp.ssl.required", sslRequired);
        // 创建并设置认证器,用于邮件服务器的身份验证
        Authenticator authenticator = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(config.getUsername(), config.getPassword());
            }
        };
        // 根据属性配置和认证器创建邮件会话
        Session session = Session.getInstance(properties, authenticator);
        MimeMessage mimeMessage = new MimeMessage(session);
        mimeMessage.setFrom(config.getUsername());
        mimeMessage.setContent(content, "text/html;charset=UTF-8");
        mimeMessage.setSubject(subject);
        mimeMessage.setRecipients(Message.RecipientType.TO, to);
        return mimeMessage;
    }

    /**
     * 根据模板名称和参数生成内容
     * 此方法使用模板引擎和提供的参数来渲染内容
     * 它首先创建一个上下文对象,并将所有参数添加到该上下文中,
     * 然后使用模板引擎处理指定的模板和上下文,以生成最终的内容
     *
     * @param templateName 模板的名称,用于标识特定的模板
     * @param params 一个包含所有必要参数的映射,这些参数将被用于渲染模板
     * @return 渲染后的模板内容作为字符串返回
     */
    private String getContent(String templateName, Map<String, Object> params) {
        Context context = new Context();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            context.setVariable(entry.getKey(), entry.getValue());
        }
        // 使用模板引擎处理指定的模板和上下文,返回渲染后的模板内容
        return engine.process(templateName, context);
    }
}

邮件工具类

package com.example.ftserver.mail;

import cn.hutool.extra.spring.SpringUtil;

import java.util.Map;

public class MailUtil {
    // hutool工具类获取注入的bean
    private static final MailServer SERVER = SpringUtil.getBean(MailServer.class);

    public static boolean sendMail(String to, String subject, String content) {
        return SERVER.sendMail(to, subject, content);
    }

    public static boolean sendMail(String to, String subject, String templateName, Map<String, Object> params) {
        return SERVER.sendMail(to, subject, templateName, params);
    }

}

测试代码

 @Test
    public void testEmail() {
        boolean b = MailUtil.sendMail("x1@163.com", "测试邮件888", "大幅度防火防盗回家"+RandomUtil.randomString(10));
        System.out.println("邮件发送结果:" + b);
        Map<String,Object> params = new HashMap<>();
        params.put("username","独孤伽罗");
        params.put("now", DateUtil.formatLocalDateTime(LocalDateTime.now()));
        // 使用邮件模板发送邮件
        boolean mail = MailUtil.sendMail("f2x@163.com", "测试邮件6666", "test", params);
        System.out.println("新的邮件发送结果:"+mail);
    }

测试结果

在这里插入图片描述
在这里插入图片描述

收到结果

pom依赖

  <dependency>
            <groupId>org.eclipse.angus</groupId>
            <artifactId>jakarta.mail</artifactId>
            <version>2.0.3</version>
        </dependency>
        <!-- 修复报错:java.lang.ClassNotFoundException: com.sun.mail.util.MailLogger -->
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.2</version>
        </dependency>
        <!-- thymeleaf 模版引擎依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

一般网上资料很少介绍引入com.sun.mail依赖,在发送时会报错:java.lang.ClassNotFoundException: com.sun.mail.util.MailLogger,引入依赖就好了

邮件模版放置位置示例

在这里插入图片描述
模版示例:

<!DOCTYPE html>
<!-- 引入thymeleaf -->
<html lang="en" xmlns:th="http://www.thymeleaf.org"> 
<head>
    <meta charset="UTF-8">
    <title>邮件示例呢</title>
</head>
<body>
<p>欢迎您,<span style="color: blue;" th:text="${username}"></span>! </p>
<p style="color: aquamarine">欢迎测试邮箱功能,今天是<span th:text="${now}" style="color: burlywood;"th:border="'22px solid red'"></span></p>
</body>
</html>

使用SpringBoot集成邮件发送

1.引入相关依赖

 <!-- 邮件依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
       <!-- 文件上传 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-fileupload2-core</artifactId>
            <version>2.0.0-M2</version>
        </dependency>

2.application.yml设置见上边的设置

3.配置类相关信息见上面的EmailConfig类

4.邮件发送服务类

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.io.File;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
public class MailServer {
    private final EmailConfig config;
    private final JavaMailSender javaMailSender;
    private final TemplateEngine templateEngine;

    /**
     * 发送简单的文本邮件
     *
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @return 邮件发送状态,true表示发送成功,false表示发送失败
     */
    public boolean sendSimpleMail(String to, String subject, String content) {
        try {
            // 创建一个简单的邮件消息实例
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            // 设置发件人地址,从配置中获取
            mailMessage.setFrom(config.getUsername());
            // 设置收件人地址
            mailMessage.setTo(to);
            // 设置邮件主题
            mailMessage.setSubject(subject);
            // 设置邮件内容
            mailMessage.setText(content);
            javaMailSender.send(mailMessage);
            return true;
        } catch (MailException e) {
            // 邮件发送失败记录错误日志
            log.error("简单邮件发送失败", e);
            return false;
        }
    }


    /**
     * 发送HTML邮件
     *
     * @param to 收件人邮箱地址
     * @param subject 邮件主题
     * @param params 邮件模板中的参数,用于替换模板中的占位符
     * @param templateName 邮件模板的名称
     * @return 如果邮件发送成功,则返回true;否则返回false
     */
    public boolean sendHtmlEmail(String to, String subject, Map<String, Object> params, String templateName) {
        try {
            // 创建MimeMessage对象
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            // 创建MimeMessageHelper对象,用于设置邮件的各项内容
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, false);
            // 设置发件人
            messageHelper.setFrom(config.getUsername());
            // 设置收件人
            messageHelper.setTo(to);
            // 设置邮件主题
            messageHelper.setSubject(subject);
            // 设置邮件内容,使用模板生成HTML字符串
            messageHelper.setText(getTemplateStr(templateName, params), true);
            javaMailSender.send(mimeMessage);
            return true;
        } catch (MessagingException e) {
            log.error("HTML邮件发送失败", e);
            return false;
        }
    }


    /**
     * 发送电子邮件文本
     *
     * @param to 收件人地址
     * @param subject 邮件主题
     * @param context 邮件正文内容
     * @return 如果邮件发送成功,则返回true;否则返回false
     */
    public boolean sendEmailText(String to, String subject, String context) {
        try {
            // 创建MIME消息
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            // 初始化消息帮助器,第二个参数表示是否需要发送文件的内容
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, false);
            // 设置发件人
            messageHelper.setFrom(config.getUsername());
            // 设置收件人
            messageHelper.setTo(to);
            // 设置邮件主题
            messageHelper.setSubject(subject);
            // 设置邮件正文
            messageHelper.setText(context);
            javaMailSender.send(mimeMessage);
            return true;
        } catch (MessagingException e) {
            log.error("邮件文字发送失败", e);
            return false;
        }
    }

    /**
     * 发送带有文件附件的电子邮件
     *
     * @param to 收件人的邮箱地址
     * @param subject 邮件的主题
     * @param content 邮件的正文内容
     * @param file 要发送的文件附件
     * @param templateName 邮件模板名称,用于确定使用哪个模板发送邮件
     * @param params 邮件模板中的参数,用于替换模板中的占位符
     * @return 如果邮件发送成功,返回true;否则返回false
     */
    public boolean sendFileEmail(String to, String subject, String content,
                                 File file,String templateName, Map<String, Object> params) {
        try {
            // 调用内部方法实际发送带有文件附件的邮件
            sendEmailInternal(to, subject, content, templateName, params, file);
            return true;
        } catch (MessagingException e) {
            log.error("文件邮件发送失败", e);
            return false;
        }
    }


    public boolean sendFileEmail(String to, String subject, String content, List<File> files,
                                 String templateName, Map<String, Object> params) {
        try {
           sendEmailInternal(to, subject, content, templateName, params, files.toArray(new File[0]));
            return true;
        } catch (MessagingException e) {
            log.error("多文件邮件发送失败", e);
            return false;
        }
    }

    /**
     * 发送电子邮件的内部方法
     *
     * @param to 收件人邮箱地址
     * @param subject 邮件主题
     * @param content 邮件内容
     * @param templateName 邮件模板名称,如果使用模板则不应为空
     * @param params 模板参数,用于替换模板中的占位符
     * @param files 附件文件数组,可以为空
     * @throws MessagingException 如果邮件构建或发送过程中发生错误
     */
    private void sendEmailInternal(String to, String subject,String content,
                                   String templateName, Map<String, Object> params, File... files) throws MessagingException {
        // 输入验证
        if (!isValidEmail(to) || isValidString(subject) || isValidString(content)) {
            throw new IllegalArgumentException("Invalid input parameters");
        }
        // 模板验证
        if (!isValidTemplateName(templateName) || !isValidParams(params)) {
            throw new IllegalArgumentException("Invalid template or parameters");
        }
        // 创建MimeMessage对象
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        // 使用MimeMessageHelper简化邮件的构建过程,设置为可包含附件和内嵌资源
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
        // 设置发件人
        messageHelper.setFrom(config.getUsername());
        // 设置收件人
        messageHelper.setTo(to);
        // 设置邮件主题
        messageHelper.setSubject(subject);
        // 根据是否使用模板和参数设置邮件内容
        if (ObjectUtils.isEmpty(templateName) && ObjectUtils.isEmpty(params)) {
            // 直接设置内容
            messageHelper.setText(content);
        } else {
            // 使用模板和参数生成内容
            messageHelper.setText(getTemplateStr(templateName, params), true);
        }
        // 处理附件
        if (files != null && files.length > 0) {
            // 根据附件数量处理附件
            if (files.length==1) {
                // 如果只有一个附件,使用FileSystemResource添加附件
                FileSystemResource fileResource = new FileSystemResource(files[0]);
                messageHelper.addAttachment(files[0].getName(), fileResource);
            }else {
                // 如果有多个附件,遍历每个文件并添加为附件
                for (File file : files) {
                    messageHelper.addAttachment(file.getName(), file);
                }
            }
        }
        // 发送邮件
        javaMailSender.send(mimeMessage);
    }


    private String getTemplateStr(String path, Map<String, Object> params) {
        Context context = new Context();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            context.setVariable(entry.getKey(), entry.getValue());
        }
        return templateEngine.process(path, context);
    }


    private boolean isValidEmail(String email) {
        // 简单的邮箱格式验证
        return email != null && email.matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}");
    }

    private boolean isValidString(String str) {
        // 简单的字符串验证,防止注入攻击
        return str == null || str.contains("\n") || str.contains("\r") || str.contains("\0");
    }

    private boolean isValidTemplateName(String templateName) {
        // 简单的模板名称验证
        return templateName != null && !templateName.contains("\n") && !templateName.contains("\r") && !templateName.contains("\0");
    }

    private boolean isValidParams(Map<String, Object> params) {
        // 简单的参数验证
        if (params == null) {
            return true;
        }
        for (Object value : params.values()) {
            if (value instanceof String && isValidString((String) value)) {
                return false;
            }
        }
        return true;
    }
}

5.邮件工具类

import com.example.mailtest.bean.MailSendVo;
import com.example.mailtest.mail.MailServer;

public class EmailUtil {
    private EmailUtil() {
        throw new IllegalArgumentException("");
    }

    private static final MailServer SERVER = SpringBeanGetUtil.getBean(MailServer.class);


    public static boolean sendTextMail(MailSendVo vo) {
        return SERVER.sendEmailText(vo.getTo(), vo.getSubject(), vo.getContent());
    }

    public static boolean sendFileMail(MailSendVo vo) {
        return SERVER.sendFileEmail(vo.getTo(), vo.getSubject(),
                vo.getContent(), vo.getFile(), vo.getTemplateName(), vo.getParams());
    }

    public static boolean sendFilesMail(MailSendVo vo) {
        return SERVER.sendFileEmail(vo.getTo(), vo.getSubject(), vo.getContent(), vo.getFiles(),
                vo.getTemplateName(),vo.getParams());
    }

    public static boolean sendHtmlMail(MailSendVo vo) {
        return SERVER.sendHtmlEmail(vo.getTo(), vo.getSubject(), vo.getParams(), vo.getTemplateName());
    }
}

邮件工具类里的SpringBeanGetUtil


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

@Component
public class SpringBeanGetUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        SpringBeanGetUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        return (T) getApplicationContext().getBean(name);
    }

    private static ApplicationContext getApplicationContext() {
        return applicationContext;
    }


}

测试代码及结果

import com.example.mailtest.bean.MailSendVo;
import com.example.mailtest.util.EmailUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.FileUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/mail")
public class MailSenderController {


    @PostMapping("/sendSimple")
    public String sendMail(@RequestBody MailSendVo params) {
        boolean simpleMail = EmailUtil.sendTextMail(params);
        return String.valueOf(simpleMail);
    }

    @PostMapping("/sendHtmlMail")
    public String sendHtmlMail(@RequestBody MailSendVo params) {
        boolean simpleMail = EmailUtil.sendHtmlMail(params);
        return String.valueOf(simpleMail);
    }
    @PostMapping("/sendFile")
    public String sendFileMail(@RequestParam("params") String params,
                               @RequestParam("fileList") List<MultipartFile> fileList) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        MailSendVo sendVo = mapper.readValue(params, MailSendVo.class);

        File file1 ;
        List<File> files=new ArrayList<>();
        for (MultipartFile multipartFile : fileList) {
            file1= new File("E:\\logs\\"+multipartFile.getOriginalFilename());
            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file1);
            files.add(file1);
            file1.deleteOnExit();
        }
        sendVo.setFiles(files);
        boolean simpleMail = EmailUtil.sendFilesMail(sendVo);
        return String.valueOf(simpleMail);
    }
}

测试结果

在这里插入图片描述在这里插入图片描述

以上就是一个用Java发送邮件的简单示例,欢迎多多探讨。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值