1. 程式人生 > >write less do more

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)