Отправка электронных писем должна быть одним из необходимых расширений веб-сайта, таких как проверка регистрации, забвение паролей или отправка маркетинговых сообщений пользователям.
1. Почтовое соглашение
В процессе отправки и получения электронных писем вам необходимо соблюдать соответствующие протоколы, которые в основном включают:
- Протокол отправки писем:
SMTP
; - Согласие на получение писем:
POP3
а такжеIMAP
.
1.1 Что такоеSMTP
?
SMTP
полное имяSimple Mail Transfer Protocol
(Простой протокол передачи почты), который представляет собой набор спецификаций для передачи почты с адреса источника на адрес назначения, с помощью которых он контролирует ретрансляцию почты.SMTP
Аутентификация требует учетную запись и пароль для входа на сервер и предназначена для защиты пользователей от спама.
1.2 Что такоеIMAP
?
IMAP
полное имяInternet Message Access Protocol
(протокол доступа к электронной почте в Интернете),IMAP
Позволяет получать информацию о почте, загружать почту и т. д. с почтового сервера.IMAP
а такжеPOP
Аналогично, это протокол получения почты.
1.3 Что такоеPOP3
?
POP3
полное имяPost Office Protocol 3
(Договор почтового отделения),POP3
Поддержка удаленного управления почтой на стороне клиента на стороне сервера.POP3
обычно используетсяне в сетиОбработка почты, которая позволяет клиенту загружать почту сервера, после чего почта на сервере будет удалена. В настоящее время многиеPOP3
Почтовый сервер предоставляет только функцию скачивания почты, сам сервер не удаляет почту, это улучшенная версияPOP3
протокол.
1.4 IMAP
а такжеPOP3
Чем отличается договор?
Самая большая разница между ними заключается в том, чтоIMAP
Допускается двусторонняя связь, то есть операции на стороне клиента будут передаваться обратно на сервер, например, получение писем на стороне клиента, пометка как прочитанные и т. д., и сервер будет синхронизировать эти операции. И дляPOP
Хотя протокол также позволяет клиенту загружать почту сервера, операции на клиенте не будут синхронизированы с сервером, такие как получение или пометка прочитанной почты на клиенте, сервер не будет синхронизировать эти операции.
2. Начальная конфигурация
2.1 Откройте почтовый сервис
В этой статье используется только
163
Возьмите электронную почту в качестве примера.
2.2 pom.xml
Обычно мы будем использовать
JavaMail
Связанныйapi
написать соответствующий код для отправки почты, но сейчасSpring Boot
Предоставляет набор более простых в использовании пакетов.
-
spring-boot-starter-mail
:Spring Boot
почтовая служба; -
spring-boot-starter-thymeleaf
:использоватьThymeleaf
Создание шаблонов электронной почты.
<!-- test 包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--使用 Thymeleaf 制作邮件模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>1.8.4</scope>
</dependency>
2.3 application.yml
spring-boot-starter-mail
настраиваетсяMailProperties
Предусмотрены классы конфигурации.
Конфигурация для разных почтовых ящиков немного отличается, следующиеQQ
почтовый ящик и163
Конфигурация почтового ящика.
server:
port: 8081
#spring:
# mail:
# # QQ 邮箱 https://service.mail.qq.com/cgi-bin/help?subtype=1&&no=1001256&&id=28
# host: smtp.qq.com
# # 邮箱账号
# username: van93@qq.com
# # 邮箱授权码(不是密码)
# password: password
# default-encoding: UTF-8
# properties:
# mail:
# smtp:
# auth: true
# starttls:
# enable: true
# required: true
spring:
mail:
# 163 邮箱 http://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac2cda80145a1742516
host: smtp.163.com
# 邮箱账号
username: 17098705205@163.com
# 邮箱授权码(不是密码)
password: password
default-encoding: UTF-8
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
2.4 Класс почтовой информации
Чтобы сохранить тему электронной почты, содержимое электронной почты и другую информацию при отправке электронной почты
@Data
public class Mail {
/**
* 邮件id
*/
private String id;
/**
* 邮件发送人
*/
private String sender;
/**
* 邮件接收人 (多个邮箱则用逗号","隔开)
*/
private String receiver;
/**
* 邮件主题
*/
private String subject;
/**
* 邮件内容
*/
private String text;
/**
* 附件/文件地址
*/
private String filePath;
/**
* 附件/文件名称
*/
private String fileName;
/**
* 是否有附件(默认没有)
*/
private Boolean isTemplate = false;
/**
* 模版名称
*/
private String emailTemplateName;
/**
* 模版内容
*/
private Context emailTemplateContext;
}
В-третьих, реализация отправки почты
3.1 Проверьте введенную конфигурацию почты
Проверьте обязательные поля получателя электронной почты, темы электронной почты и содержимого электронной почты.
private void checkMail(Mail mail) {
if (StringUtils.isEmpty(mail.getReceiver())) {
throw new RuntimeException("邮件收信人不能为空");
}
if (StringUtils.isEmpty(mail.getSubject())) {
throw new RuntimeException("邮件主题不能为空");
}
if (StringUtils.isEmpty(mail.getText()) && null == mail.getEmailTemplateContext()) {
throw new RuntimeException("邮件内容不能为空");
}
}
3.2 Сохранение электронной почты в базе данных
После отправки почта будет сохранена в базе данных, что удобно для статистики и отслеживания проблем с почтой.
private Mail saveMail(Mail mail) {
// todo 发送成功/失败将邮件信息同步到数据库
return mail;
}
3.3 Отправить письмо
- Отправить текстовое письмо
public void sendSimpleMail(Mail mail){
checkMail(mail);
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(sender);
mailMessage.setTo(mail.getReceiver());
mailMessage.setSubject(mail.getSubject());
mailMessage.setText(mail.getText());
mailSender.send(mailMessage);
saveMail(mail);
}
- Отправить письмо с вложениями
public void sendAttachmentsMail(Mail mail) throws MessagingException {
checkMail(mail);
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(sender);
helper.setTo(mail.getReceiver());
helper.setSubject(mail.getSubject());
helper.setText(mail.getText());
File file = new File(mail.getFilePath());
helper.addAttachment(file.getName(), file);
mailSender.send(mimeMessage);
saveMail(mail);
}
- Отправить шаблон электронной почты
public void sendTemplateMail(Mail mail) throws MessagingException {
checkMail(mail);
// templateEngine 替换掉动态参数,生产出最后的html
String emailContent = templateEngine.process(mail.getEmailTemplateName(), mail.getEmailTemplateContext());
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(sender);
helper.setTo(mail.getReceiver());
helper.setSubject(mail.getSubject());
helper.setText(emailContent, true);
mailSender.send(mimeMessage);
saveMail(mail);
}
В-четвертых, тестирование и оптимизация
4.1 Модульное тестирование
- При тестировании электронных писем с вложениями вложения помещаются в
static
под папку; - При тестировании шаблонных писем шаблон помещается в
file
под папку.
@RunWith(SpringRunner.class)
@SpringBootTest
public class MailServiceTest {
@Resource
MailService mailService;
/**
* 发送纯文本邮件
*/
@Test
public void sendSimpleMail() {
Mail mail = new Mail();
// mail.setReceiver("17098705205@163.com");
mail.setReceiver("van93@qq.com");
mail.setSubject("测试简单邮件");
mail.setText("测试简单内容");
mailService.sendSimpleMail(mail);
}
/**
* 发送邮件并携带附件
*/
@Test
public void sendAttachmentsMail() throws MessagingException {
Mail mail = new Mail();
// mail.setReceiver("17098705205@163.com");
mail.setReceiver("van93@qq.com");
mail.setSubject("测试附件邮件");
mail.setText("附件邮件内容");
mail.setFilePath("file/dusty_blog.jpg");
mailService.sendAttachmentsMail(mail);
}
/**
* 测试模版邮件邮件
*/
@Test
public void sendTemplateMail() throws MessagingException {
Mail mail = new Mail();
// mail.setReceiver("17098705205@163.com");
mail.setReceiver("van93@qq.com");
mail.setSubject("测试模版邮件邮件");
//创建模版正文
Context context = new Context();
// 设置模版需要更换的参数
context.setVariable("verifyCode", "6666");
mail.setEmailTemplateContext(context);
// 模版名称(模版位置位于templates目录下)
mail.setEmailTemplateName("emailTemplate");
mailService.sendTemplateMail(mail);
}
}
4.2 Оптимизация
Поскольку обычно существуют требования CC/BCC для отправки электронных писем, здесь сущность и класс инструмента инкапсулированы для облегчения прямых вызовов службы электронной почты.
- Информация об электронной почте
@Data
public class MailDomain {
/**
* 邮件id
*/
private String id;
/**
* 邮件发送人
*/
private String sender;
/**
* 邮件接收人 (多个邮箱则用逗号","隔开)
*/
private String receiver;
/**
* 邮件主题
*/
private String subject;
/**
* 邮件内容
*/
private String text;
/**
* 抄送(多个邮箱则用逗号","隔开)
*/
private String cc;
/**
* 密送(多个邮箱则用逗号","隔开)
*/
private String bcc;
/**
* 附件/文件地址
*/
private String filePath;
/**
* 附件/文件名称
*/
private String fileName;
/**
* 是否有附件(默认没有)
*/
private Boolean isTemplate = false;
/**
* 模版名称
*/
private String emailTemplateName;
/**
* 模版内容
*/
private Context emailTemplateContext;
/**
* 发送时间(可指定未来发送时间)
*/
private Date sentDate;
}
- почтовый инструмент
@Component
public class EmailUtil {
@Resource
private JavaMailSender mailSender;
@Resource
TemplateEngine templateEngine;
@Value("${spring.mail.username}")
private String sender;
/**
* 构建复杂邮件信息类
* @param mail
* @throws MessagingException
*/
public void sendMail(MailDomain mail) throws MessagingException {
//true表示支持复杂类型
MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
//邮件发信人从配置项读取
mail.setSender(sender);
//邮件发信人
messageHelper.setFrom(mail.getSender());
//邮件收信人
messageHelper.setTo(mail.getReceiver().split(","));
//邮件主题
messageHelper.setSubject(mail.getSubject());
//邮件内容
if (mail.getIsTemplate()) {
// templateEngine 替换掉动态参数,生产出最后的html
String emailContent = templateEngine.process(mail.getEmailTemplateName(), mail.getEmailTemplateContext());
messageHelper.setText(emailContent, true);
}else {
messageHelper.setText(mail.getText());
}
//抄送
if (!StringUtils.isEmpty(mail.getCc())) {
messageHelper.setCc(mail.getCc().split(","));
}
//密送
if (!StringUtils.isEmpty(mail.getBcc())) {
messageHelper.setCc(mail.getBcc().split(","));
}
//添加邮件附件
if (mail.getFilePath() != null) {
File file = new File(mail.getFilePath());
messageHelper.addAttachment(file.getName(), file);
}
//发送时间
if (StringUtils.isEmpty(mail.getSentDate())) {
messageHelper.setSentDate(mail.getSentDate());
}
//正式发送邮件
mailSender.send(messageHelper.getMimeMessage());
}
/**
* 检测邮件信息类
* @param mail
*/
private void checkMail(MailDomain mail) {
if (StringUtils.isEmpty(mail.getReceiver())) {
throw new RuntimeException("邮件收信人不能为空");
}
if (StringUtils.isEmpty(mail.getSubject())) {
throw new RuntimeException("邮件主题不能为空");
}
if (StringUtils.isEmpty(mail.getText()) && null == mail.getEmailTemplateContext()) {
throw new RuntimeException("邮件内容不能为空");
}
}
/**
* 将邮件保存到数据库
* @param mail
* @return
*/
private MailDomain saveMail(MailDomain mail) {
// todo 发送成功/失败将邮件信息同步到数据库
return mail;
}
}
Специальные тесты см.Пример кода на гитхабе, здесь не публикуется.
V. Резюме и дополнение
5.1 Асинхронная отправка
Во многих случаях отправка электронной почты не является тем результатом, на который должен обращать внимание наш основной бизнес. Например, уведомления и напоминания могут допускать задержки или сбои. В настоящее время для отправки электронных писем можно использовать асинхронный метод, чтобы ускорить выполнение основной транзакции.В реальных проектах его можно использоватьMQ
Отправить параметры, связанные с почтой, начать отправку почты после прослушивания очереди сообщений.
5.2 Ошибка отправки
По разным причинам всегда будут сбои при отправке электронных писем, например: электронные письма отправляются слишком часто, сбои в сети и т. д. Когда это происходит, мы обычно рассматриваем повторную попытку отправки электронной почты, которая будет реализована в следующих шагах:
- Получив запрос на отправку письма, сначала запишите запрос и поместите его в хранилище;
- Вызвать интерфейс отправки почты для отправки почты и записать результат отправки в базу данных;
- В течение периода сканирования системы синхронизации запуска передача не удалась, а количество попыток меньше
3
раз, и отправить его снова.
5.3 Другие вопросы
Проблемы с почтовым портом и размер вложения.
5.4 Образец кода адреса
-
Серия статей Spring Boot, добро пожаловать, чтобы следоватьПыль Блог!