用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发送邮件的简单示例,欢迎多多探讨。。