Practical practice of sending emails with springboot (complete code)

Practical practice of sending emails with springboot

Preface: In our actual project, there are some requirements related to the function of sending emails using mailboxes. The Spring framework provides an abstraction for sending emails using the JavaMailSender interface, and Spring Boot provides automatic configuration and startup modules for it. Therefore, it is relatively simple for us to implement the email sending function. The email sending function on the spring official website: https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.email

1. Preparation

To send an email, you need to enable the email service (take 163 email as an example)

Enter the settings of the corresponding sending email address

You can enable either IMAP or POP3 service

At this point, the preparation work is over.

2. Enter the project code link
2.1 The project introduces mailbox dependencies
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.2 Basic configuration of email
#Attribute name: attribute type
    Property description
#mail.smtp.user:String
    Default username for SMTP.
# mail.smtp.host:String
    SMTP server to connect to.
# mail.smtp.port: int
    The SMTP server port to connect to, if the connect() method does not specify one explicitly. Default is 25.
# mail.smtp.connectiontimeout: int
    Socket connection timeout value in milliseconds. This timeout is implemented by java.net.Socket. Default is infinite timeout.
# mail.smtp.timeout: int
    Socket read timeout value in milliseconds. This timeout is implemented by java.net.Socket. Default is infinite timeout.
# mail.smtp.writetimeout: int
    Socket write timeout value in milliseconds. This timeout is implemented using java.util.concurrent.ScheduledExecutorService on each connection,
    The service schedules a thread to close the socket when the timeout expires. Therefore, the overhead of using this timeout is one thread per connection. Default is infinite timeout.
#mail.smtp.from:String
    Email address used for SMTP MAIL commands. This will set the envelope return address. Defaults to msg.getFrom() or InternetAddress.getLocalAddress().
    NOTE: mail.smtp.user was previously used for this purpose.
#mail.smtp.localhost:String
    The local host name used in SMTP HELO or EHLO commands. The default is InetAddress.getLocalHost().getHostName().
    If your JDK and name service are configured correctly, this usually doesn't need to be set up.
#mail.smtp.localaddress:String
    The local address (hostname) to bind to when creating the SMTP socket. Defaults to the address chosen by the Socket class. Normally no setting is required,
    But it is useful for multi-homed hosts where it is important to select a specific local address to bind to.
# mail.smtp.localport: int
    The local port number to bind to when creating the SMTP socket. Defaults to the port number chosen by the Socket class.
#mail.smtp.ehlo:boolean
    If false, do not attempt to log in using the EHLO command. Defaults to true. Usually if the EHLO command fails, it will fall back to the HELO command;
    This property only applies to servers that fail EHLO incorrectly or that do not implement EHLO correctly.
#mail.smtp.auth:boolean
    If true, attempts to authenticate the user using the AUTH command. Defaults to false.
# mail.smtp.auth.mechanisms: String
    If set, lists the authentication mechanisms to consider, and the order in which they are considered. Only mechanisms supported by the server and supported by the current implementation will be used.
    Defaults to "LOGIN PLAIN DIGEST-MD5 NTLM", which includes all authentication mechanisms supported by the current implementation except XOAUTH2.
# mail.smtp.auth.login.disable: boolean
    If true, prevents use of this AUTH LOGIN command. Defaults to false.
# mail.smtp.auth.plain.disable: boolean
    If true, prevents use of this AUTH PLAIN command. Defaults to false.
# mail.smtp.auth.digest-md5.disable: boolean
    If true, prevents use of the AUTH DIGEST-MD5 command. Defaults to false.
# mail.smtp.auth.ntlm.disable: boolean
    If true, prevents use of this AUTH NTLM command. Defaults to false.
# mail.smtp.auth.ntlm.domain:String
    NTLM authentication domain.
# mail.smtp.auth.ntlm.flags: int
    NTLM protocol specific flag. For more information, see http://curl.haxx.se/rfc/ntlm.html#theNtlmFlags.
# mail.smtp.auth.xoauth2.disable: boolean
    If true, prevents use of the AUTHENTICATE XOAUTH2 command. Since the OAuth 2.0 protocol requires a special access token instead of a password, by default
    Disable this mechanism. Enable it by explicitly setting this property to "false" or by setting the "mail.smtp.auth.mechanisms" property to "XOAUTH2".
# mail.smtp.submitter:String
    The submitter to be used in the AUTH tag of the MAIL FROM command. Typically used by mailbox relays to pass information about the original submitter of a mailbox.
    See also the setSubmitter method of SMTPMessage. Mailbox clients generally don't use it.
# mail.smtp.dsn.notify:String
    NOTIFY option for the RCPT command. NEVER or some combination of SUCCESS, FAILURE, and DELAY (separated by commas).
# mail.smtp.dsn.ret:String
    RET option for the MAIL command. FULL or HDRS.
#mail.smtp.allow8bitmime:boolean
    If set to true and the server supports the 8BITMIME extension, the text portion of the mailbox is encoded using "quoted-printable" or "base64"
    If the RFC2045 rules for 8bit text are followed, the conversion will be to use the "8bit" encoding.
# mail.smtp.sendpartial: boolean
    If set to true and the message has some valid addresses and some invalid addresses, the message is sent anyway and partial failure is reported with SendFailedException.
    If set to false (the default), the mailbox will not be sent to any recipient if the recipient address is invalid.
# mail.smtp.sasl.enable: boolean
    If set to true, attempts to use the javax.security.sasl package to select the authentication mechanism for login. Defaults to false.
# mail.smtp.sasl.mechanisms: String
    A space or comma separated list of SASL mechanism names to try.
# mail.smtp.sasl.authorizationid: String
    Authorization ID used in SASL authentication. If not set, the authentication ID (username) is used.
# mail.smtp.sasl.realm:String
    Realm used for DIGEST-MD5 authentication.
#mail.smtp.sasl.usecanonicalhostname:boolean
    If set to true, the canonical host name returned by InetAddress.getCanonicalHostName is passed to the SASL mechanism,
    instead of the hostname used to connect. Defaults to false.
#mail.smtp.quitwait:boolean
    If set to false, a QUIT command is sent and the connection is closed immediately. If set to true (the default), causes the transport to wait for a response to a QUIT command.
# mail.smtp.quitonsessionreject: boolean
    If set to false (the default), the QUIT command is not sent and the connection is closed immediately when session initiation is rejected.
    If set to true, causes the transport to send a QUIT command before closing the connection.
#mail.smtp.reportsuccess:boolean
    If set to true, causes the transmission of an SMTPAddressSucceededException containing one for each successful address. Also note that
    Even if all addresses are correct and the message is sent successfully, this will cause a SendFailedException to be thrown from the sendMessage method of a SMTPTransport.
# mail.smtp.socketFactory: SocketFactory
    If set to a class that implements the javax.net.SocketFactory interface, this class will be used to create SMTP sockets. Note that this is an instance of a class,
    instead of a name, and must be set using the put method rather than the setProperty method.
# mail.smtp.socketFactory.class: String
    If set, specifies the name of the class that implements the javax.net.SocketFactory interface. This class will be used to create SMTP sockets.
# mail.smtp.socketFactory.fallback: boolean
    If set to true, failure to create a socket using the specified socket factory class will result in the socket being created using the java.net.Socket class. Defaults to true.
# mail.smtp.socketFactory.port: int
    Specifies the port to connect to when using the specified socket factory. If not set, the default port will be used.
# mail.smtp.ssl.enable: boolean
    If set to true, the default is to connect using SSL and use the SSL port. The "smtp" protocol defaults to false, and the "smtps" protocol defaults to true.
#mail.smtp.ssl.checkserveridentity:boolean
    If set to true, checks the server ID specified by RFC 2595. These additional checks based on the contents of the server certificate are intended to prevent man-in-the-middle attacks. Defaults to false.
#mail.smtp.ssl.trust:String
    If set, and no socket factory is specified, MailSSLSocketFactory is enabled. If set to "*", all hosts are trusted. If set to
    A space-separated list of hosts that are trusted. Otherwise, trust depends on the certificate provided by the server.
# mail.smtp.ssl.socketFactory:SSLSocketFactory
    If set to a class that extends the javax.net.ssl.SSLSocketFactory class, this class will be used to create SMTP SSL sockets. Note that this is an instance of a class,
    instead of a name, and must be set using the put method rather than the setProperty method.
# mail.smtp.ssl.socketFactory.class: String
    If set, specifies the name of a class that extends the javax.net.ssl.SSLSocketFactory class. This class will be used to create SMTP SSL sockets.
# mail.smtp.ssl.socketFactory.port: int
    Specifies the port to connect to when using the specified socket factory. If not set, the default port will be used.
# mail.smtp.ssl.protocols: String
    Specifies the SSL protocol that will be enabled for SSL connections. The property value is the javax.net.ssl.SSLSocket.setEnabledProtocols method
    A space-separated list of acceptable tokens.
# mail.smtp.ssl.ciphersuites: String
    Specifies the SSL cipher suites that will be enabled for SSL connections. The property value is the javax.net.ssl.SSLSocket.setEnabledCipherSuites method
    A space-separated list of acceptable tokens.
# mail.smtp.starttls.enable: boolean
    If true, enables the STARTTLS command (if supported by the server) to switch the connection to a TLS-protected connection before issuing any login commands.
    If the server does not support STARTTLS, the connection continues without using TLS; mail.smtp.starttls.required If STARTTLS is not supported,
    Please review the failed properties. Note that the appropriate truststore must be configured so that the client trusts the server's certificate. Defaults to false.
# mail.smtp.starttls.required: boolean
    If true, the STARTTLS command is required. If the server does not support the STARTTLS command, or the command fails, the connect method will fail. Defaults to false.
#mail.smtp.proxy.host:String
    Specify the host name of the HTTP web proxy server that will be used to connect to the Mailbox server.
# mail.smtp.proxy.port: String
    Specify the port number of the HTTP web proxy server. Default is port 80.
# mail.smtp.proxy.user: String
    Specifies the username used to authenticate to the HTTP web proxy server. By default, no authentication occurs.
#mail.smtp.proxy.password:String
    Specifies the password used to authenticate to the HTTP web proxy server. By default, no authentication occurs.
# mail.smtp.socks.host:String
    Specify the host name of the SOCKS5 proxy server that will be used to connect to the Mailbox server.
# mail.smtp.socks.port: String
    Specify the port number of the SOCKS5 proxy server. This option is only required if the proxy server does not use the standard port number 1080.
# mail.smtp.mailextension: String
    Extension string appended to the MAIL command. Extension strings can be used to specify standard SMTP service extensions as well as vendor-specific extensions. usually,
    Applications should use the SMTPTransport method supportsExtension to verify that the server supports the required service extension.
    See RFC 1869 and other RFCs that define specific extensions.
#mail.smtp.userset:boolean
    If set to true, use the RSET command instead of the NOOP command in the isConnected method.
    In some cases, sendmail will respond slowly after multiple NOOP commands; use RSET to avoid this sendmail problem. Defaults to false.
# mail.smtp.noop.strict: boolean
    If set to true (the default), insist on a 250 response code from a NOOP command to indicate success. The isConnected method uses the NOOP command to determine
    Whether the connection is still valid. Some older servers return incorrect response codes on success, and some servers do not execute the NOOP command at all and therefore always return a failure code.
    Set this property to false to handle servers corrupted in this way. Typically, when a server times out a connection, it sends a 421 response code, which the client treats as
    in response to the next command issued to it. Some servers send incorrect failure response codes when the connection times out. When dealing with a server damaged in this way,
    Do not set this property to false.

The above is the extended configuration of mailbox properties, and the following is the basic configuration

spring:
  mail:
    host: smtp.163.com #smtp server host (163)
    port: 25 #Connect to the mail server port (default SMTP 25 POP 110)
    protocol: smtp #Connection protocol (default SMTP)
    username: [email protected] # Log in to the server email account
    password: xxxxxxxxxxxx # Log in to the server email authorization code (not the email password, this is the authorization code we got when we opened SMTP and POP)
    default-encoding: UTF-8 # encoding
    test-connection: false # Whether to test the connection
    properties:
      mail:
        smtp:
          from: [email protected] #Default sender’s email account (when the program does not specify the sender’s email address, this will be taken by default)
          auth: true # Turn on permission authentication
          timeout: 25000 # Email receiving time limit
          connectiontimeout: 25000 # Connection time limit
          writetimeout: 25000 # Email sending time limit (milliseconds)
        debug: true # Log printing, the log of the email sending process will be output
2.2 Implement the function of sending emails

JavaMailSender and JavaMailSenderImpl; they are a set of email function integration interfaces and implementations officially provided by Spring. We directly inject JavaMailSenderImpl into the business and call the send method. We can send simple emails through SimpleMailMessage, and for complex emails with attachments, we can use MimeMessageHelper to build MimeMessage to send emails.

There are three common ways to send emails:

1. Send simple text content

2. Send complex emails HTML + image resources + attachments

3. Use Thymeleaf templates to send complex emails

2.2.1 Send simple text content
 @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void sendSimpleMail(String from, String to, String subject, String text) {<!-- -->
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        // sender
        simpleMailMessage.setFrom(from);
        // recipient
        simpleMailMessage.setTo(to);
        // Email Subject
        simpleMailMessage.setSubject(subject);
        // content of email
        simpleMailMessage.setText(text);
        javaMailSender.send(simpleMailMessage);
    }
2.2.2 Send email with attachments
 @Override
    public Boolean sendMimeMail(String from, String to, String subject, String text) {<!-- -->
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        String url = "https://www.w3school.com.cn/example/xmle/note.xml";
        String filePath = "D:\workFile";
        try {<!-- -->
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(text);

            String fileName = XFileUtils.downLoadByUrl(url, filePath, null);
            String fullFilePath = filePath + File.separator + fileName;
            File file = new File(fullFilePath);
            if (!file.exists()) {<!-- -->
                return false;
            }
            FileSystemResource fileSystemResource = new FileSystemResource(file);
            helper.addAttachment(fileName, fileSystemResource);
            javaMailSender.send(mimeMessage);
            file.delete();
        } catch (Exception e) {<!-- -->
            log.error("Failed to send complex email",e);
            return false;
        }
        return true;
    }
2.2.3 Sending emails using templates

a. Introduce dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

b. Add a file named template.html to the resource/templates folder

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Email verification</title>
    <meta charset="utf-8">
</head>

<body>
<!-- Head -->
<div style="padding: 10px; background-color: #393D49;">
    <h2 style="color: #FFFFFF; margin: 0px;"></h2>
</div>
<!-- Content -->
<div style="padding-top: 10px; padding-bottom: 10px;">
    <div style="background-color: snow; padding: 20px;">
        <div>
            <h3>Dear user: Hello! </h3>
            <p>Note: You are currently performing a sensitive operation. To ensure the security of your account, we will authenticate you via email.</p>
            <p th:text="${message}"></p>
            <div>
                <h4>The verification code this time is:</h4>
                <div style="background-color: #EBEEF5; padding: 10px;">
                    <h3 th:text="${code}"></h3>
                </div>
                <h4>Validity period is 5 minutes</h4>
            </div>
        </div>
    </div>
</div>
<!-- Bottom of page -->
<div style="padding: 10px; text-align: center; background-color: #2F4056;">
    <p style="margin: 0px; color: #FFFFFF;"></p>
</div>

</body>
</html>

c. Send email code

 @RequestMapping("/sendTemplateMail")
    public Boolean sendTemplateMail(){
        String from = "[email protected]";
        String to = "[email protected]";
        String subject = "This is the subject of the template email";
        String message = "Details: You are trying to log in. If it is not your own behavior, please ignore it!";
        String code = "123456789";
        Context context = new Context();
        context.setVariable("message", message);
        context.setVariable("code", code);
        return emailService.sendTemplateMail(from, to, subject, context);
    }
 @Override
    public Boolean sendTemplateMail(String from, String to, String subject, Context context) {<!-- -->

        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {<!-- -->
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
            String mail = templateEngine.process("template.html", context);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(mail,true);
            javaMailSender.send(mimeMessage);
        } catch (Exception e) {<!-- -->
            log.error("Failed to send template email",e);
            return false;
        }
        return true;
    }