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; }