springboot版本:3.0.13
效果:
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置yml
spring:
mail:
default-encoding: UTF-8 # 编码
host: smtp.qiye.aliyun.com # 服务器
port: 465 # 端口
username: 123@test.cn # 邮箱
password: 123456 # 阿里云企业邮箱是密码,QQ邮箱是授权码
protocol: smtps # 默认smtp,这里用的ssl端口所以加个s
properties:
mail:
debug: false #调试用的
主要代码:
import com.anxko.authorize.web.entity.dto.EmailDto;
import jakarta.mail.Address;
import jakarta.mail.SendFailedException;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailSendException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class MailServiceImpl {
@Autowired
private JavaMailSender javaMailSender;
@Value("${spring.mail.username}")
private String emailFrom;
public void send(EmailDto dto){
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = null;
log.info("开始发信...");
try {
helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(emailFrom);
helper.setTo(dto.getToArray());
helper.setSubject(dto.getSubject());
helper.setText(dto.getContent(), dto.isHtml());
if (StringUtils.hasText(dto.getAnnex())) {
File file = new File(dto.getAnnex());
if (file.exists() && file.isFile()) {
FileSystemResource resource = new FileSystemResource(file);
helper.addAttachment(file.getName(), resource);
}
}
javaMailSender.send(mimeMessage);
log.info("发信成功");
}catch (Throwable e){
log.info("发信失败,开始尝试去除无效地址再次发信");
List<String> addresses = getInvalidAddresses(e);
log.info("重试发信,去除的无效地址:{}", addresses);
if (addresses != null && !addresses.isEmpty()) {
String addressToRepeat = addressToRepeat(dto.getToArray(), addresses);
dto.setTo(addressToRepeat); //将字符串设置回去替换
send(dto); //递归调用
}
}
}
/**
* 从异常获取无效地址
* @param e 异常
* @return 过滤出的无效地址
*/
private List<String> getInvalidAddresses(Throwable e){
if (e instanceof MailSendException) {
Exception[] messageExceptions = ((MailSendException) e).getMessageExceptions();
for (Exception messageException : messageExceptions) {
if (messageException instanceof SendFailedException){
return getStringAddress(((SendFailedException)messageException).getInvalidAddresses());
}
}
}
if (e instanceof SendFailedException) {
return getStringAddress(((SendFailedException) e).getInvalidAddresses());
}
return null;
}
/**
* 将Address[]转成List
* @param address 地址
* @return 地址集合
*/
private static List<String> getStringAddress(Address[] address) {
return Arrays.stream(address)
.filter(addr -> addr instanceof InternetAddress)
.map(addr -> ((InternetAddress)addr).getAddress())
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
}
/**
* 根据无效的邮箱,将原邮箱中的无效地址去除掉
* @param source 原邮箱
* @param filter 无效邮箱
* @return 去除后的邮箱使用逗号分割
*/
private static String addressToRepeat(String[] source, List<String> filter){
return Arrays.stream(source)
.filter(s -> filter.stream().noneMatch(f->f.equals(s)))
.collect(Collectors.joining(","));
}
}