write less do more
相信使用過Spring的眾多開發者都知道Spring提供了非常好用的 JavaMailSender
介面實現郵件傳送。在Spring Boot的Starter模組中也為此提供了自動化配置。下面通過例項看看如何在Spring Boot中使用 JavaMailSender
傳送郵件。
快速入門
在Spring Boot的工程中的 pom.xml
中引入 spring-boot-starter-mail
依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
如其他自動化配置模組一樣,在完成了依賴引入之後,只需要在 application.properties
中配置相應的屬性內容。
下面我們以QQ郵箱為例,在 application.properties
中加入如下配置(注意替換自己的使用者名稱和密碼):
spring.mail.host=smtp.qq.com
spring.mail.username=使用者名稱 //傳送方的郵箱
spring.mail.password=密碼 //對於qq郵箱而言 密碼指的就是傳送方的授權碼
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
注意: 在spring.mail.password
處的值是需要在郵箱設定裡面生成的授權碼
,這個不是真實的密碼。
通過單元測試來實現一封簡單郵件的傳送:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTests {
@Autowired
private JavaMailSender mailSender;
@Test
public void sendSimpleMail() throws Exception {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(" [email protected]");
message.setTo("[email protected]");
message.setSubject("主題:簡單郵件");
message.setText("測試郵件內容");
mailSender.send(message);
}
}
到這裡,一個簡單的郵件傳送就完成了,執行一下該單元測試,看看效果如何?
由於Spring Boot的starter模組提供了自動化配置,所以在引入了 spring-boot-starter-mail
依賴之後,會根據配置檔案中的內容去建立 JavaMailSender
例項,因此我們可以直接在需要使用的地方直接 @Autowired
來引入郵件傳送物件。
對於qq郵箱這樣寫過後會報錯:
1、異常資訊:
org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.MessagingException: Could not convert socket to TLS; nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure. Failed messages: javax.mail.MessagingException: Could not convert socket to TLS; nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure; message exception details (1) are: Failed message 1: javax.mail.MessagingException: Could not convert socket to TLS; nested exception is: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at com.sun.mail.smtp.SMTPTransport.startTLS(SMTPTransport.java:2046) at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:711) at javax.mail.Service.connect(Service.java:366) at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:501) at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:421) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:307) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:296)
這種錯誤一般是因為jre的lib下C:\Program Files\Java\jdk1.8.0_51\jre\lib\security,替換2個jar包,參考文件
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
2、異常資訊
org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: 535 Error: ??ê1ó?êúè¨??μ????£?ê?é???′: http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:424) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:307) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:296) at com.vcredit.ddcash.monitor.controller.AppTest.testSendSimple(AppTest.java:36) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
傳送方必須要開啟smtp,獲取到的授權碼,介面如下:
3、異常資訊:
org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS. Failed messages: javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS; message exception details (1) are: Failed message 1: javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:721) at javax.mail.Service.connect(Service.java:366) at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:501) at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:421) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:307) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:296) at com.vcredit.ddcash.monitor.controller.AppTest.testSendSimple(AppTest.java:36) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
換成公司企業郵箱報錯,通過將properties檔案的內容修改就可以了,這裡的使用者密碼就是自己的郵箱密碼(這點不同於qq郵箱)
spring.mail.properties.mail.smtp.starttls.enable=false spring.mail.properties.mail.smtp.starttls.required=false
-
- 傳送HTML格式的郵件
@Test
public void testSendHtml() {
MimeMessage message = null;
try {
message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(username);
helper.setTo("[email protected]");
helper.setSubject("標題:傳送Html內容");
StringBuffer sb = new StringBuffer();
sb.append("<h1>大標題-h1</h1>")
.append("<p style='color:#F00'>紅色字</p>")
.append("<p style='text-align:right'>右對齊</p>");
helper.setText(sb.toString(), true);
} catch (MessagingException e) {
e.printStackTrace();
}
javaMailSender.send(message);
}
注意:這裡建立的是MimeMessageHelper
,且在呼叫setText
時需要在第二個引數傳入true
,這樣才會使用HTML格式傳送郵件
通過velocity模板傳送郵件:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-velocity</artifactId> </dependency>
@Autowired
private VelocityEngine velocityEngine;
@Test public void sendTemplateMail() throws Exception { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom("[email protected]"); helper.setTo("[email protected]"); helper.setSubject("主題:模板郵件"); Map<String, Object> model = new HashedMap(); model.put("username", "zjq"); String text = VelocityEngineUtils.mergeTemplateIntoString( velocityEngine, "template.vm", "UTF-8", model); helper.setText(text, true); javaMailSender.send(mimeMessage); }
在resources下建一個templates包 該包下建立一個檔案template.vm,內容以html格式隨便寫
<html> <body> <h3>你好, ${username}, 這是一封模板郵件!</h3> </body> </html>
測試結果:
不知道什麼原因我的qq郵箱需要設定
spring.mail.properties.mail.smtp.starttls.enable=false spring.mail.properties.mail.smtp.starttls.required=false
才能成功
不然會報錯
org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS. Failed messages: javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS ; message exception details (1) are: Failed message 1: javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:721) at javax.mail.Service.connect(Service.java:366) at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:501) at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:421) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:307) at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:296) at com.didispace.ApplicationTests.sendSimpleMail(ApplicationTests.java:39) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)