Sending e-mail should be one of the essential extensions to the website, such as registering for verification, forgetting your password, or sending marketing information to users.
1. Mail Agreement
In the process of sending and receiving mail, related agreements need to be complied with, including:
- Protocol for sending e-mail: SMTP;
- Protocol for receiving e-mail: POP3 and IMAP.
1.1 What is SMTP?
SMTP, known as Simple Mail Transfer Protocol (Simple Mail Transfer Protocol), is a set of specifications for transporting messages from source addresses to destination addresses through which to control how they are transported.SMTP authentication requires an account and password to log on to the server and is designed to avoid spam.
1.2 What is IMAP?
IMAP is fully known as the Internet Message Access Protocol (Internet Mail Access Protocol), which allows you to get information from mail servers, download mail, and so on.IMAP, like POP, is a mail acquisition protocol.
1.3 What is POP3?
POP3 is fully known as Post Office Protocol 3 (Post Office Protocol), which enables clients to remotely manage mail on the server side.POP3 is commonly used for offline mail processing, which allows clients to download server mail, which is then deleted from the server.At present, many POP3 mail servers only provide download mail function, the server itself does not delete mail, this is an improved version of the POP3 protocol.
What is the difference between the 1.4 IMAP and POP3 protocols?
The biggest difference between the two is that IMAP allows two-way communication, where the client's actions are fed back to the server, such as taking mail from the client, marking it read, and so on, and the server synchronizes them.While the POP protocol also allows clients to download server mail, client operations are not synchronized to the server, such as collecting or marking read mail on the client, and the server does not synchronize these operations.
2. Initialization Configuration
2.1 Open Mail Service
This article only takes QQ mailbox and 163 mailbox as examples.
2.2 pom.xml
Normally we use the JavaMail-related api to write code for sending mail, but now Spring Boot offers a simpler set of encapsulations to use.
- spring-boot-starter-mail:Spring Boot mail service;
- spring-boot-starter-thymeleaf: Use Thymeleaf to make mail templates.
<!-- test package--> <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> <!--Use Thymeleaf Making Mail Templates --> <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
The configuration of spring-boot-starter-mail is provided by the MailProperties configuration class.
There are slightly different configurations for different mailboxes. Below are the configurations for QQ and 163 mailboxes.
server: port: 8081 #spring: # mail: # # QQ mailbox https://service.mail.qq.com/cgi-bin/help?Subtype=1 &&no=1001256 &&id=28 # host: smtp.qq.com # # Mailbox account # username: van93@qq.com # # Mailbox Authorization Number (not Password) # password: password # default-encoding: UTF-8 # properties: # mail: # smtp: # auth: true # starttls: # enable: true # required: true spring: mail: # 163 Mailbox http://help.mail.163.com/faqDetail.do?Code=d7a5dc8471cd0c0e8b4f8e49998b374173cfe91305fa1ce630d7f67ac2cda80145a1742516 host: smtp.163.com # Mailbox account username: 17098705205@163.com # Mailbox Authorization Number (not Password) password: password default-encoding: UTF-8 properties: mail: smtp: auth: true starttls: enable: true required: true
2.4 Mail Information Class
To save the subject, content and other information of the message when it is sent
@Data public class Mail { /** * Mail id */ private String id; /** * Mail sender */ private String sender; /** * Mail recipient (multiple mailboxes are separated by a comma "." */ private String receiver; /** * Mail Subject */ private String subject; /** * Mail Content */ private String text; /** * Attachment/File Address */ private String filePath; /** * Attachment/File Name */ private String fileName; /** * Is there an attachment (not by default) */ private Boolean isTemplate = false; /** * Template Name */ private String emailTemplateName; /** * Template Content */ private Context emailTemplateContext; }
3. Realization of Sending Mail
3.1 Check incoming mail configuration
Verify the required entries for the recipient, subject, and content of the message
private void checkMail(Mail mail) { if (StringUtils.isEmpty(mail.getReceiver())) { throw new RuntimeException("Mail recipient cannot be empty"); } if (StringUtils.isEmpty(mail.getSubject())) { throw new RuntimeException("Mail subject cannot be empty"); } if (StringUtils.isEmpty(mail.getText()) && null == mail.getEmailTemplateContext()) { throw new RuntimeException("Message content cannot be empty"); } }
3.2 Save Mail to Database
Save the mail to the database after sending, to facilitate statistics and tracking of mail problems.
private Mail saveMail(Mail mail) { // todo Send Success/Failure Synchronize Mail Information to Database return mail; }
3.3 Send Mail
- Send plain text messages
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); }
- Send mail and carry attachments
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); }
- Send template mail
public void sendTemplateMail(Mail mail) throws MessagingException { checkMail(mail); // TempeEngine replaces the dynamic parameters and produces the final 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); }
IV. Testing and Optimization
4.1 Unit Test
- When testing attachment mail, attachments are placed in the static folder;
- When testing template mail, the template is placed in the file folder.
@RunWith(SpringRunner.class) @SpringBootTest public class MailServiceTest { @Resource MailService mailService; /** * Send plain text messages */ @Test public void sendSimpleMail() { Mail mail = new Mail(); // mail.setReceiver("17098705205@163.com"); mail.setReceiver("van93@qq.com"); mail.setSubject("Test Simple Mail"); mail.setText("Test Simple Content"); mailService.sendSimpleMail(mail); } /** * Send mail and carry attachments */ @Test public void sendAttachmentsMail() throws MessagingException { Mail mail = new Mail(); // mail.setReceiver("17098705205@163.com"); mail.setReceiver("van93@qq.com"); mail.setSubject("Test Attachment Mail"); mail.setText("Attachment Mail Content"); mail.setFilePath("file/dusty_blog.jpg"); mailService.sendAttachmentsMail(mail); } /** * Test Template Mail */ @Test public void sendTemplateMail() throws MessagingException { Mail mail = new Mail(); // mail.setReceiver("17098705205@163.com"); mail.setReceiver("van93@qq.com"); mail.setSubject("Test Template Mail"); //Create template body Context context = new Context(); // Set parameters for template to be replaced context.setVariable("verifyCode", "6666"); mail.setEmailTemplateContext(context); // Template name (Template location in templates directory) mail.setEmailTemplateName("emailTemplate"); mailService.sendTemplateMail(mail); } }
4.2 Optimization
Because there is also a need for Cc/Bcc for sending mail in general, here, an entity and a tool class are encapsulated to make it easy to call the mail service directly.
- Mail Information Class
@Data public class MailDomain { /** * Mail id */ private String id; /** * Mail sender */ private String sender; /** * Mail recipient (multiple mailboxes are separated by a comma "." */ private String receiver; /** * Mail Subject */ private String subject; /** * Mail Content */ private String text; /** * Cc (multiple mailboxes are separated by commas',' */ private String cc; /** * Bcc (multiple mailboxes are separated by commas',' */ private String bcc; /** * Attachment/File Address */ private String filePath; /** * Attachment/File Name */ private String fileName; /** * Is there an attachment (not by default) */ private Boolean isTemplate = false; /** * Template Name */ private String emailTemplateName; /** * Template Content */ private Context emailTemplateContext; /** * Send time (future send time can be specified) */ private Date sentDate; }
- Mail Tool Class
@Component public class EmailUtil { @Resource private JavaMailSender mailSender; @Resource TemplateEngine templateEngine; @Value("${spring.mail.username}") private String sender; /** * Building Complex Mail Information Classes * @param mail * @throws MessagingException */ public void sendMail(MailDomain mail) throws MessagingException { //true indicates support for complex types MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true); //Mail sender reads from configuration item mail.setSender(sender); //Mail sender messageHelper.setFrom(mail.getSender()); //Mail Recipient messageHelper.setTo(mail.getReceiver().split(",")); //Mail Subject messageHelper.setSubject(mail.getSubject()); //Mail Content if (mail.getIsTemplate()) { // TempeEngine replaces the dynamic parameters and produces the final html String emailContent = templateEngine.process(mail.getEmailTemplateName(), mail.getEmailTemplateContext()); messageHelper.setText(emailContent, true); }else { messageHelper.setText(mail.getText()); } //Cc if (!StringUtils.isEmpty(mail.getCc())) { messageHelper.setCc(mail.getCc().split(",")); } //bcc if (!StringUtils.isEmpty(mail.getBcc())) { messageHelper.setCc(mail.getBcc().split(",")); } //Add Mail Attachment if (mail.getFilePath() != null) { File file = new File(mail.getFilePath()); messageHelper.addAttachment(file.getName(), file); } //Send Time if (StringUtils.isEmpty(mail.getSentDate())) { messageHelper.setSentDate(mail.getSentDate()); } //Send mail officially mailSender.send(messageHelper.getMimeMessage()); } /** * Detect Mail Information Class * @param mail */ private void checkMail(MailDomain mail) { if (StringUtils.isEmpty(mail.getReceiver())) { throw new RuntimeException("Mail recipient cannot be empty"); } if (StringUtils.isEmpty(mail.getSubject())) { throw new RuntimeException("Mail subject cannot be empty"); } if (StringUtils.isEmpty(mail.getText()) && null == mail.getEmailTemplateContext()) { throw new RuntimeException("Message content cannot be empty"); } } /** * Save Mail to Database * @param mail * @return */ private MailDomain saveMail(MailDomain mail) { // todo Send Success/Failure Synchronize Mail Information to Database return mail; } }
Detailed testing can be found in Github sample code And it won't stick out here.
V. Summary and Extension
5.1 Asynchronous Send
Many times mail sending is not the result of our main business, such as notification class, reminder class business can allow delays or failures.At this time, mail can be sent asynchronously to speed up the execution of the main transaction. In practical projects, MQ can be used to send mail related parameters, and start sending mail after listening to the message queue.
5.2 Send Failure
For a variety of reasons, there will always be cases of mail delivery failure, such as: mail sent too frequently, network abnormalities, and so on.When this happens, we usually consider retrying to send the message, which can be accomplished in the following steps:
- Receive a request to send mail, first record the request and store it in the library;
- Call the mail sending interface to send mail, and record the results of sending into the library;
- During the startup timer system scan period, no mail was sent successfully and the number of retries was less than 3 times, and then sent again.
5.3 Other Issues
Mail port problem and attachment size problem.
5.4 Sample Code Address
-
Spring Boot Series Articles Welcome to Dust Blog!