Spring Boot email and attachments, super practical!

Keywords: Programming Spring Java Thymeleaf JQuery

Author: yizhiwazi www.jianshu.com/p/5eb000544dd7

Spring Boot integrated e-mail service is so simple that it can quickly grasp the core logic of e-mail business class and the daily service of enterprise e-mail.

What is SMTP?

The full name of SMTP is Simple Mail Transfer Protocol, which is a set of specifications used to transfer mail from the source address to the destination address, through which the transfer mode of mail can be controlled. SMTP authentication requires an account and password to log in to the server. Its design aims to avoid users being harassed by spam.

What is IMAP?

The full name of IMAP is Internet Message Access Protocol (Internet Mail Access Protocol). IMAP allows you to obtain the information of mail, Download mail, etc. from the mail server. Similar to POP, IMAP is a mail acquisition protocol.

What is POP3?

POP3 is called Post Office Protocol 3 (post office protocol). POP3 supports the client to remotely manage the mail on the server. POP3 is often used for "offline" mail processing, which allows clients to download server mail, and then the mail on the server will be deleted. At present, many POP3 e-mail servers only provide the function of downloading e-mail, and the server itself does not delete e-mail, which belongs to the improved version of POP3 protocol.

What's the difference between IMAP and POP3?

The biggest difference between the two is that IMAP allows two-way communication, that is, the operations on the client will be fed back to the server, such as receiving mail on the client, marking read and other operations, and the server will synchronize these operations. While the POP protocol also allows clients to download server mail, but the operations on the client will not be synchronized to the server. For example, if the client receives or marks the read mail, the server will not synchronize these operations.

What are JavaMailSender and JavaMailSenderImpl?

JavaMailSender and JavaMailSenderImpl are the interfaces and implementation classes of integrated mail service officially provided by Spring. They are famous for their simple and efficient design. At present, they are the mainstream tools for Java back-end mail sending and integrated mail service.

How do I send mail through JavaMailSenderImpl?

It's very simple to inject JavaMailSenderImpl directly into the business class and call the send method to send mail. Simple mail can send mail through SimpleMailMessage, while complex mail (such as adding attachments) can build a MimeMessage to send mail through MimeMessageHelper. For example:

@Autowired
private JavaMailSenderImpl mailSender;

public void sendMail() throws MessagingException {

    SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
    simpleMailMessage.setFrom("admin@163.com");
    simpleMailMessage.setTo("socks@qq.com");
    simpleMailMessage.setSubject("Happy New Year");
    simpleMailMessage.setText("Happy New Year!");
    mailSender.send(simpleMailMessage);

    MimeMessage mimeMessage = mailSender.createMimeMessage();
    MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
    messageHelper.setFrom("admin@163.com");
    messageHelper.setTo("socks@qq.com");
    messageHelper.setSubject("Happy New Year");
    messageHelper.setText("Happy New Year!");
    messageHelper.addInline("doge.gif", new File("xx/xx/doge.gif"));
    messageHelper.addAttachment("work.docx", new File("xx/xx/work.docx"));
    mailSender.send(mimeMessage);
}

Why can 'JavaMailSenderImpl' be used out of the box?

The so-called out of the box use is actually based on the official built-in automatic configuration. Looking at the source code, you can see that the mailsenderpropertiesconfiguration class provides a javamailsenderimpl for the context. The specific source code is as follows:

@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {
    private final MailProperties properties;
    MailSenderPropertiesConfiguration(MailProperties properties) {
        this.properties = properties;
    }
    @Bean
    @ConditionalOnMissingBean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        applyProperties(sender);
        return sender;
    }
}

MailProperties is the configuration information about the mail server. The specific source code is as follows:

@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private String host;
    private Integer port;
    private String username;
    private String password;
    private String protocol = "smtp";
    private Charset defaultEncoding = DEFAULT_CHARSET;
    private Map<String, String> properties = new HashMap<>();
}

1, Open mail service

Log in to Netease mailbox 163, open and check POP3/SMTP/IMAP service in the settings, and then you will get an authorization code, which will be used as login authentication.

2, Configure mail service

First, let's create the project springboot send mail through Spring Initializr, as shown in the figure: Recommended: Young people's first Spring Boot application.

Then we introduce web, thmeleaf and spring boot starter mail dependency into pom.xml. For example:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

Fill in the relevant configuration information according to the above-mentioned configuration item (mail properties). spring.mail.username means the login account authenticated when connecting to the mail server, which can be a normal mobile phone number or login account, not necessarily a mailbox. To solve this problem, it is recommended that you fill in the email sender, i.e. the real mailbox, in spring.mail. properties.from.

Then add the following configuration in application.yml:

spring:
  mail:
    host: smtp.163.com #SMTP server address
    username: socks #Login account
    password: 123456 #Login password (or authorization code)
    properties:
      from: socks@163.com #Email sender (i.e. real email)
  thymeleaf:
    cache: false
    prefix: classpath:/views/
  servlet:
    multipart:
      max-file-size: 10MB #Limit single file size
      max-request-size: 50MB #Limit total requests

Through the previous advanced knowledge, we know that before sending an e-mail, we need to build a SimpleMailMessage or MimeMessage e-mail information class to fill in the e-mail title, e-mail content and other information, and finally submit it to JavaMailSenderImpl to send an e-mail, which seems to have no problem and can achieve the established goal, but in actual use, there will be a lot of scattered and repeated code, It's not easy to save messages to the database yet.

So how about sending emails gracefully? You should block the details of building information and sending mail. No matter simple or complex mail, you can send mail through a unified API. For example: mailService.send(mailVo).

For example, through the mail information class (MailVo), you can save the message subject, message content and other information when sending the message:

package com.hehe.vo;

public class MailVo {
    private String id;
    private String from;
    private String to;
    private String subject;
    private String text;
    private Date sentDate;
    private String cc;
    private String bcc;
    private String status;
    private String error;

    @JsonIgnore
    private MultipartFile[] multipartFiles;

}

3, Send mail and attachments

In addition to sending mail, it also includes checking mail and saving mail, for example:

  • Check mail (); first check the required items such as the recipient, subject and content of the mail. If it is blank, it will be rejected.

  • Send the message sendMimeMail(); then parse the MailVo and build the MimeMessage to transmit the message through MimeMessageHelper.

  • Save the mail sendMimeMail(); finally, save the mail to the database for easy statistics and tracking of mail problems.

The specific source code of MailService in this case is as follows:

package com.hehe.service;

@Service
public class MailService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private JavaMailSenderImpl mailSender;

    public MailVo sendMail(MailVo mailVo) {
        try {
            checkMail(mailVo);
            sendMimeMail(mailVo);
            return saveMail(mailVo);
        } catch (Exception e) {
            logger.error("Failed to send mail:", e);
            mailVo.setStatus("fail");
            mailVo.setError(e.getMessage());
            return mailVo;
        }

    }

    private void checkMail(MailVo mailVo) {
        if (StringUtils.isEmpty(mailVo.getTo())) {
            throw new RuntimeException("Mail recipient cannot be empty");
        }
        if (StringUtils.isEmpty(mailVo.getSubject())) {
            throw new RuntimeException("Message subject cannot be empty");
        }
        if (StringUtils.isEmpty(mailVo.getText())) {
            throw new RuntimeException("Message content cannot be empty");
        }
    }

    private void sendMimeMail(MailVo mailVo) {
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
            mailVo.setFrom(getMailSendFrom());
            messageHelper.setFrom(mailVo.getFrom());
            messageHelper.setTo(mailVo.getTo().split(","));
            messageHelper.setSubject(mailVo.getSubject());
            messageHelper.setText(mailVo.getText());
            if (!StringUtils.isEmpty(mailVo.getCc())) {
                messageHelper.setCc(mailVo.getCc().split(","));
            }
            if (!StringUtils.isEmpty(mailVo.getBcc())) {
                messageHelper.setCc(mailVo.getBcc().split(","));
            }
            if (mailVo.getMultipartFiles() != null) {
                for (MultipartFile multipartFile : mailVo.getMultipartFiles()) {
                    messageHelper.addAttachment(multipartFile.getOriginalFilename(), multipartFile);
                }
            }
            if (StringUtils.isEmpty(mailVo.getSentDate())) {
                mailVo.setSentDate(new Date());
                messageHelper.setSentDate(mailVo.getSentDate());
            }
            mailSender.send(messageHelper.getMimeMessage());
            mailVo.setStatus("ok");
            logger.info("Message sent successfully:{}->{}", mailVo.getFrom(), mailVo.getTo());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private MailVo saveMail(MailVo mailVo) {

        return mailVo;
    }

    public String getMailSendFrom() {
        return mailSender.getJavaMailProperties().getProperty("from");
    }
}

After finishing the core business logic of sending email, let's write a simple page to send email. How can Spring Boot transform old projects quickly? Recommend it.

First, write the controller MailController that interacts with the page. The specific source code is as follows:

@RestController
public class MailController {
    @Autowired
    private MailService mailService;

    @GetMapping("/")
    public ModelAndView index() {
        ModelAndView mv = new ModelAndView("mail/sendMail");
        mv.addObject("from", mailService.getMailSendFrom());
        return mv;
    }

    @PostMapping("/mail/send")
    public MailVo sendMail(MailVo mailVo, MultipartFile[] files) {
        mailVo.setMultipartFiles(files);
        return mailService.sendMail(mailVo);
    }
}

Then create sendMail.html in the / resources/views/mail directory. The specific source code is as follows:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8"/>
    <title>Send mail</title>
    <link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" rel="stylesheet" type="text/css"/>
    <script th:src="@{/webjars/jquery/jquery.min.js}"></script>
    <script th:href="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>

</head>

<body>
<div class="col-md-6" style="margin:20px;padding:20px;border: #E0E0E0 1px solid;">
    <marquee behavior="alternate" onfinish="alert(12)" id="mq"
             onMouseOut="this.start();$('#Eg '). Text ('well, that's good! ""; "
             onMouseOver="this.stop();$('#Eg '). Text ('Let me go if you have the ability! > >
        <h5 id="egg">Happy New Year!</h5><img id="doge" src="http://pics.sc.chinaz.com/Files/pic/faces/3709/7.gif" alt="">
    </marquee>

    <form class="form-horizontal" id="mailForm">
        <div class="form-group">
            <label class="col-md-2 control-label">Mail sender:</label>
            <div class="col-md-6">
                <input class="form-control" id="from" name="from" th:value="${from}" readonly="readonly">
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label">Mail recipient:</label>
            <div class="col-md-6">
                <input class="form-control" id="to" name="to" title="Multiple mailbox usage,Separate">
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label">Message subject:</label>
            <div class="col-md-6">
                <input class="form-control" id="subject" name="subject">
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label">Message content:</label>
            <div class="col-md-6">
                <textarea class="form-control" id="text" name="text" rows="5"></textarea>
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label">Mail attachment:</label>
            <div class="col-md-6">
                <input class="form-control" id="files" name="files" type="file" multiple="multiple">
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label">Mail operation:</label>
            <div class="col-md-3">
                <a class="form-control btn btn-primary" onclick="sendMail()">Send mail</a>
            </div>
            <div class="col-md-3">
                <a class="form-control btn btn-default" onclick="clearForm()">empty</a>
            </div>
        </div>
    </form>

    <script th:inline="javascript">
        var appCtx = [[${#request.getContextPath()}]];

        function sendMail() {

            var formData = new FormData($('#mailForm')[0]);
            $.ajax({
                url: appCtx + '/mail/send',
                type: "POST",
                data: formData,
                contentType: false,
                processData: false,
                success: function (result) {
                    alert(result.status === 'ok' ? "Sending succeeded!" : "You are Doge Ridiculed:" + result.error);
                },
                error: function () {
                    alert("Sending failed!");
                }
            });
        }

        function clearForm() {
            $('#mailForm')[0].reset();
        }

        setInterval(function () {
            var total = $('#mq').width();
            var width = $('#doge').width();
            var left = $('#doge').offset().left;
            if (left <= width / 2 + 20) {
                $('#doge').css('transform', 'rotateY(180deg)')
            }
            if (left >= total - width / 2 - 40) {
                $('#doge').css('transform', 'rotateY(-360deg)')
            }
        });
    </script>
</div>
</body>
</html>

4, Test sending mail

If you are a beginner, it is recommended that you download the source code first, modify the configuration and run the project, and then write the code again after success, which will help deepen your memory. Pay attention to the official account: Java technology stack, reply: boot, get Spring Boot series tutorial.

Start the project and visit: http://localhost:8080 Then you can see the main interface of sending mail as follows:

Then fill in your small email and click send email. If you succeed, you can log in the small email to check the email and the attachment you just uploaded.

5, Common failure codes

If the enterprise has customized the mail server, it will naturally record the mail log. Storing the log according to the error code is conducive to daily maintenance. One minute to teach you to email with Spring Boot , recommended.

For example, these error code identifiers provided by Netease mailbox:

421

421 HL:REP the IP sending behavior is abnormal. There are a large number of receivers that do not exist, and the connection is temporarily forbidden. Please check whether users send viruses or spam, and check the validity of the sending list; 421 HL: the number of concurrent connections of this IP in ICC is too large, which exceeds the limit of Netease. Therefore, the connection is temporarily forbidden. Please check whether users send viruses or spam, and reduce the number of IP concurrent connections; 421 HL:IFC sent a large number of letters within a short period of time, which exceeded the limit of Netease and was temporarily prohibited from connecting. Please check whether users send viruses or spam, and reduce the frequency of sending; 421 HL:MEP's IP sending behavior is abnormal, there are a lot of behaviors of forging domain name of sending domain, and connection is temporarily forbidden. Please check whether users send viruses or spam, and use the real and effective domain name to send;

450

450 MI:CEL sender has too many wrong instructions. Please check the sending procedure; 450 Mi: the number of messages sent by the DMC's current connection exceeds the limit. Please reduce the number of mails delivered in each connection; 450 MI:CCL sender sends more than normal instructions. Please check the sending procedure; 450 RP: the number of recipients sent by DRC's current connection exceeds the limit. Please control the number of mail delivered per connection; 450 RP:CCL sender sent more than normal instructions. Please check the sending procedure; 450 DT:RBL sending IP is located in one or more rbls. Please refer to http://www.rbls.org/ information about RBL; 450 WM:BLI the IP address is not in the list of allowed sending addresses of Netease; 450 WM:BLU this user is not in the list of sending users allowed by Netease;

451

451 DT: SPM, please try again. The body of the e-mail has spam characteristics or the sending environment is not standardized, so it is temporarily rejected. Please keep the message queue and resend the message in two minutes. Need to adjust email content or optimize sending environment; 451 Requested mail action not taken: too much fail authentication failed to log in, which is temporarily prohibited. Please check the password and account verification settings; 451 RP:CEL sender has too many wrong instructions. Please check the sending procedure; 451 Mi: the number of messages sent by the DMC's current connection exceeds the limit. Please control the number of mails delivered in each connection; 451 Mi: if the number of SFQ senders exceeds the limit within 15 minutes, please control the sending frequency; 451 RP: the total number of recipients of QRC sender in a short period of time exceeds the limit, and the sender is temporarily prohibited from sending. Please reduce the sending frequency of the user; 451 Requested action aborted: local error in processing system is temporarily faulty, please try sending again later;

500

500 Error: the syntax of the smtp command sent by bad syntaxU is wrong; 550 MI:NHD HELO command is not allowed to be empty; 550 Mi: the email address of the IMF sender is out of specification. Please refer to http://www.rfc-editor.org/ definition of e-mail specification; 550 MI:SPF sending IP is not licensed by SPF of sending domain. Please refer to http://www.openspf.org/ on the definition of SPF specification; 550 MI:DMA this message is not licensed by DMARC of the sending domain. Please refer to http://dmarc.org/ on the definition of DMARC specification; 550 Mi: the number of connections of STC sender on that day exceeds the limit, and the sender's mail will not be accepted on that day. Please control the number of connections; 550 RP:FRL Netease mailbox is not open for anonymous forwarding (Open relay); 550 RP: the number of RCL group recipients exceeds the limit, please reduce the number of recipients per email; 550 RP: the cumulative number of recipients of TRC sender in the same day exceeds the limit, and the sender's mail will not be accepted in the same day. Please reduce the sending frequency of the user; 550 DT:SPM message body has many spam features or the sending environment is lack of standardization. Need to adjust email content or optimize sending environment; The user requested by 550 Invalid User does not exist; 550 User in blacklist this user is not allowed to send messages to Netease users; The user requested by 550 User suspended is disabled or frozen; 550 Requested mail action not taken: too much recipient group sending quantity exceeds the limit;

552

552 Illegal Attachment is not allowed to send attachments of this type, including attachments ending with. UU. PIF. SCR. MIM. HQX. BHX. CMD. VBS. Bat. Com. VBE. VB. JS. WSH, etc; 552 Requested mail action aborted: exceeded mailsize limit the size of the mail sent exceeds the maximum allowed to be received by e-mail;

553

553 Requested action not taken: NULL sender is not allowed. Please use the true sender to send; 553 Requested action not taken: Local user only SMTP type machine only allows the sender to be the local user; 553 Requested action not taken: no smtp MX only MX type machine does not allow the sender to be the local user; 553 authentication is required SMTP requires authentication, please check the client settings;

554

554 DT: the message sent by SPM contains unauthorized information or is recognized as spam by the system. Please check whether users send viruses or spam; 554 DT: the sender of sum envelope does not match the sender of letter; 554 IP is rejected, SMTP auth error limit exceeded the number of IP verification failures is too many, and the connection is temporarily forbidden. Please check the verification information settings; 554 HL:IHU sending IP is temporarily suspended due to spam or abnormal connection behavior. Please check the history of sending IP and whether the sending program is abnormal; 554 HL: the IP address of IPB is not in the list of allowed sending addresses of Netease; 554 MI:STC sender's cumulative mail quantity in the same day exceeds the limit, and the sender's mail will not be accepted on the same day. Please reduce the sending frequency; 554 MI:SPB this user is not in the list of sending users allowed by Netease; 554 IP in blacklist this IP is not in Netease's allowed send address list.

Recommend to my blog to read more:

1.Java JVM, collection, multithreading, new features series

2.Spring MVC, Spring Boot, Spring Cloud series tutorials

3.Maven, Git, Eclipse, Intellij IDEA series tools tutorial

4.Latest interview questions of Java, backend, architecture, Alibaba and other large factories

Feel good, don't forget to like + forward!

Posted by ThinkGeekness on Tue, 21 Apr 2020 02:58:08 -0700