J'KYO
No pains,no gains.

 

springboot仍然在狂速发展,才五个多月没有关注,现在看官网已经到1.5.3.RELEASE版本了。准备慢慢在写写springboot相关的文章,本篇文章使用springboot最新版本1.5.3进行开发。

发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。最早期的时候我们会使用JavaMail相关api来写发送邮件的相关代码,后来spring推出了JavaMailSender更加简化了邮件发送的过程,在之后springboot对此进行了封装就有了现在的spring-boot-starter-mail,本章文章的介绍主要来自于此包。

简单使用

1、pom包配置

pom包里面添加spring-boot-starter-mail包引用

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

2、在application.properties中添加邮箱配置

spring.mail.host=smtp.qiye.163.com //邮箱服务器地址
spring.mail.username=xxx@oo.com //用户名
spring.mail.password=xxyyooo    //密码
spring.mail.default-encoding=UTF-8

mail.fromMail.addr=xxx@oo.com  //以谁来发送邮件

3、编写mailService,这里只提出实现类。

@Component
public class MailServiceImpl implements MailService{

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

    @Autowired
    private JavaMailSender mailSender;

    @Value("${mail.fromMail.addr}")
    private String from;

    @Override
    public void sendSimpleMail(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);

        try {
            mailSender.send(message);
            logger.info("简单邮件已经发送。");
        } catch (Exception e) {
            logger.error("发送简单邮件时发生异常!", e);
        }

    }
}

4、编写test类进行测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class MailServiceTest {

    @Autowired
    private MailService MailService;

    @Test
    public void testSimpleMail() throws Exception {
        MailService.sendSimpleMail("ityouknow@126.com","test simple mail"," hello this is simple mail");
    }
}

至此一个简单的文本发送就完成了。

加点料

但是在正常使用的过程中,我们通常在邮件中加入图片或者附件来丰富邮件的内容,下面讲介绍如何使用springboot来发送丰富的邮件。

发送html格式邮件

其它都不变在MailService添加sendHtmlMail方法.

public void sendHtmlMail(String to, String subject, String content) {
    MimeMessage message = mailSender.createMimeMessage();

    try {
        //true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);

        mailSender.send(message);
        logger.info("html邮件发送成功");
    } catch (MessagingException e) {
        logger.error("发送html邮件时发生异常!", e);
    }
}

在测试类中构建html内容,测试发送

@Test
public void testHtmlMail() throws Exception {
    String content="<html>\n" +
            "<body>\n" +
            "    <h3>hello world ! 这是一封Html邮件!</h3>\n" +
            "</body>\n" +
            "</html>";
    MailService.sendHtmlMail("ityouknow@126.com","test simple mail",content);
}

发送带附件的邮件

在MailService添加sendAttachmentsMail方法.

public void sendAttachmentsMail(String to, String subject, String content, String filePath){
    MimeMessage message = mailSender.createMimeMessage();

    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);

        FileSystemResource file = new FileSystemResource(new File(filePath));
        String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
        helper.addAttachment(fileName, file);

        mailSender.send(message);
        logger.info("带附件的邮件已经发送。");
    } catch (MessagingException e) {
        logger.error("发送带附件的邮件时发生异常!", e);
    }
}

添加多个附件可以使用多条 helper.addAttachment(fileName, file)

在测试类中添加测试方法

@Test
public void sendAttachmentsMail() {
    String filePath="e:\\tmp\\application.log";
    mailService.sendAttachmentsMail("ityouknow@126.com", "主题:带附件的邮件", "有附件,请查收!", filePath);
}

发送带静态资源的邮件

邮件中的静态资源一般就是指图片,在MailService添加sendAttachmentsMail方法.

public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId){
    MimeMessage message = mailSender.createMimeMessage();

    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);

        FileSystemResource res = new FileSystemResource(new File(rscPath));
        helper.addInline(rscId, res);

        mailSender.send(message);
        logger.info("嵌入静态资源的邮件已经发送。");
    } catch (MessagingException e) {
        logger.error("发送嵌入静态资源的邮件时发生异常!", e);
    }
}

在测试类中添加测试方法

@Test
public void sendInlineResourceMail() {
    String rscId = "neo006";
    String content="<html><body>这是有图片的邮件:<img src=\'cid:" + rscId + "\' ></body></html>";
    String imgPath = "C:\\Users\\summer\\Pictures\\favicon.png";

    mailService.sendInlineResourceMail("ityouknow@126.com", "主题:这是有图片的邮件", content, imgPath, rscId);
}

添加多个图片可以使用多条 <img src='cid:" + rscId + "' > 和 helper.addInline(rscId, res) 来实现

到此所有的邮件发送服务已经完成了。

邮件系统

上面发送邮件的基础服务就这些了,但是如果我们要做成一个邮件系统的话还需要考虑以下几个问题:

邮件模板

我们会经常收到这样的邮件:

尊敬的neo用户:
                  
              恭喜您注册成为xxx网的用户,,同时感谢您对xxx的关注与支持并欢迎您使用xx的产品与服务。
              ...

其中只有neo这个用户名在变化,其它邮件内容均不变,如果每次发送邮件都需要手动拼接的话会不够优雅,并且每次模板的修改都需要改动代码的话也很不方便,因此对于这类邮件需求,都建议做成邮件模板来处理。模板的本质很简单,就是在模板中替换变化的参数,转换为html字符串即可,这里以thymeleaf为例来演示。

1、pom中导入thymeleaf的包

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

2、在resorces/templates下创建emailTemplate.html

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8"/>
        <title>Title</title>
    </head>
    <body>
        您好,这是验证邮件,请点击下面的链接完成验证,<br/>
        <a href="#" th:href="@{ http://www.ityouknow.com/neo/{id}(id=${id}) }">激活账号</a>
    </body>
</html>

3、解析模板并发送

@Test
public void sendTemplateMail() {
    //创建邮件正文
    Context context = new Context();
    context.setVariable("id", "006");
    String emailContent = templateEngine.process("emailTemplate", context);

    mailService.sendHtmlMail("ityouknow@126.com","主题:这是模板邮件",emailContent);
}

发送失败

因为各种原因,总会有邮件发送失败的情况,比如:邮件发送过于频繁、网络异常等。在出现这种情况的时候,我们一般会考虑重新重试发送邮件,会分为以下几个步骤来实现:

  • 1、接收到发送邮件请求,首先记录请求并且入库。
  • 2、调用邮件发送接口发送邮件,并且将发送结果记录入库。
  • 3、启动定时系统扫描时间段内,未发送成功并且重试次数小于3次的邮件,进行再次发送

异步发送

很多时候邮件发送并不是我们主业务必须关注的结果,比如通知类、提醒类的业务可以允许延时或者失败。这个时候可以采用异步的方式来发送邮件,加快主交易执行速度,在实际项目中可以采用MQ发送邮件相关参数,监听到消息队列之后启动发送邮件。

可以参考前期文章:springboot(八):RabbitMQ详解 来实现。

示例代码-github

示例代码-码云

参考: spring boot 发送邮件

 

集成spring-boot-starter-mail发送邮件

 

 

项目GitHub地址 :

https://github.com/FrameReserve/TrainingBoot

 

Spring Boot(十二)集成spring-boot-starter-mail发送邮件,标记地址:

https://github.com/FrameReserve/TrainingBoot/releases/tag/0.0.12

 

 

pom.xml 

增加:

spring-boot-starter-mail

spring-boot-starter-velocity -- 模板

[html] view plain copy
 
  1. <!-- Email -->  
  2.         <dependency>  
  3.             <groupId>org.springframework.boot</groupId>  
  4.             <artifactId>spring-boot-starter-mail</artifactId>  
  5.         </dependency>  
  6.   
  7.         <dependency>  
  8.             <groupId>org.springframework.boot</groupId>  
  9.             <artifactId>spring-boot-starter-velocity</artifactId>  
  10.         </dependency>  

 

Spring Boot配置文件:

QQ邮箱权限需要在QQ邮箱里设置,163则不用,问题比较少。

src/main/resources/application.yml

 

[html] view plain copy
 
  1. mail:  
  2.     host: smtp.163.com  
  3.     username: 286352250@163.com  
  4.     password: 用户密码  
  5.     properties:  
  6.         mail:   
  7.             smtp:  
  8.                 auth: true  
  9.                 timeout: 25000  


 

Email配置类:

后期经常使用发件人邮箱,在这统一定义。

 src/main/java/com/training/core/email/EmailConfig.java 

[java] view plain copy
 
  1. package com.training.core.email;  
  2.   
  3. import org.springframework.beans.factory.annotation.Value;  
  4. import org.springframework.context.annotation.Configuration;  
  5. import org.springframework.stereotype.Component;  
  6.   
  7. @Component  
  8. public class EmailConfig {  
  9.   
  10.     /** 
  11.      * 发件邮箱 
  12.      */  
  13.     @Value("${spring.mail.username}")  
  14.     private String emailFrom;  
  15.   
  16.     public String getEmailFrom() {  
  17.         return emailFrom;  
  18.     }  
  19.   
  20.     public void setEmailFrom(String emailFrom) {  
  21.         this.emailFrom = emailFrom;  
  22.     }  
  23.       
  24. }  


 

定义Email Service,三种邮件风格:

1. 发送简单邮件。

2. 发送带附件简单邮件

3. 发送模板邮件。

src/main/java/com/training/core/email/EmailService.java

 

[java] view plain copy
 
  1. package com.training.core.email;  
  2.   
  3. import java.io.File;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. import com.training.core.dto.Pair;  
  8.   
  9. public interface EmailService {  
  10.   
  11.     /** 
  12.      * 发送简单邮件 
  13.      * @param sendTo 收件人地址 
  14.      * @param titel  邮件标题 
  15.      * @param content 邮件内容 
  16.      */  
  17.     public void sendSimpleMail(String sendTo, String titel, String content);  
  18.       
  19.     /** 
  20.      * 发送简单邮件 
  21.      * @param sendTo 收件人地址 
  22.      * @param titel  邮件标题 
  23.      * @param content 邮件内容 
  24.      * @param attachments<文件名,附件> 附件列表 
  25.      */  
  26.     public void sendAttachmentsMail(String sendTo, String titel, String content, List<Pair<String, File>> attachments);  
  27.       
  28.     /** 
  29.      * 发送模板邮件 
  30.      * @param sendTo 收件人地址 
  31.      * @param titel  邮件标题 
  32.      * @param content<key, 内容> 邮件内容 
  33.      * @param attachments<文件名,附件> 附件列表 
  34.      */  
  35.     public void sendTemplateMail(String sendTo, String titel, Map<String, Object> content, List<Pair<String, File>> attachments);  
  36.       
  37. }  


Email Service实现类:

src/main/java/com/training/core/email/EmailServiceImpl.java

 

[java] view plain copy
 
  1. package com.training.core.email;  
  2.   
  3. import java.io.File;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. import javax.mail.internet.MimeMessage;  
  8.   
  9. import org.apache.commons.collections.map.HashedMap;  
  10. import org.apache.velocity.app.VelocityEngine;  
  11. import org.springframework.beans.factory.annotation.Autowired;  
  12. import org.springframework.core.io.FileSystemResource;  
  13. import org.springframework.mail.SimpleMailMessage;  
  14. import org.springframework.mail.javamail.JavaMailSender;  
  15. import org.springframework.mail.javamail.MimeMessageHelper;  
  16. import org.springframework.stereotype.Service;  
  17. import org.springframework.ui.velocity.VelocityEngineUtils;  
  18.   
  19. import com.training.core.dto.Pair;  
  20. import com.training.core.exception.RuntimeServiceException;  
  21.   
  22. @Service  
  23. public class EmailServiceImpl implements EmailService {  
  24.   
  25.     @Autowired  
  26.     private EmailConfig emailConfig;  
  27.     @Autowired  
  28.     private JavaMailSender mailSender;  
  29.     @Autowired  
  30.     private VelocityEngine velocityEngine;  
  31.       
  32.     public void sendSimpleMail(String sendTo, String titel, String content) {  
  33.         SimpleMailMessage message = new SimpleMailMessage();  
  34.         message.setFrom(emailConfig.getEmailFrom());  
  35.         message.setTo(sendTo);  
  36.         message.setSubject(titel);  
  37.         message.setText(content);  
  38.         mailSender.send(message);  
  39.     }  
  40.   
  41.     public void sendAttachmentsMail(String sendTo, String titel, String content, List<Pair<String, File>> attachments) {  
  42.   
  43.         MimeMessage mimeMessage = mailSender.createMimeMessage();  
  44.   
  45.         try {  
  46.             MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);  
  47.             helper.setFrom(emailConfig.getEmailFrom());  
  48.             helper.setTo(sendTo);  
  49.             helper.setSubject(titel);  
  50.             helper.setText(content);  
  51.   
  52.             for (Pair<String, File> pair : attachments) {  
  53.                 helper.addAttachment(pair.getLeft(), new FileSystemResource(pair.getRight()));  
  54.             }  
  55.         } catch (Exception e) {  
  56.             throw new RuntimeServiceException(e);  
  57.         }  
  58.   
  59.         mailSender.send(mimeMessage);  
  60.     }  
  61.   
  62.     public void sendInlineMail() {  
  63.   
  64.         MimeMessage mimeMessage = mailSender.createMimeMessage();  
  65.   
  66.         try {  
  67.             MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);  
  68.             helper.setFrom(emailConfig.getEmailFrom());  
  69.             helper.setTo("286352250@163.com");  
  70.             helper.setSubject("主题:嵌入静态资源");  
  71.             helper.setText("<html><body><img src=\"cid:weixin\" ></body></html>", true);  
  72.   
  73.             FileSystemResource file = new FileSystemResource(new File("weixin.jpg"));  
  74.             helper.addInline("weixin", file);  
  75.         } catch (Exception e) {  
  76.             throw new RuntimeServiceException(e);  
  77.         }  
  78.   
  79.         mailSender.send(mimeMessage);  
  80.     }  
  81.   
  82.     public void sendTemplateMail(String sendTo, String titel, Map<String, Object> content, List<Pair<String, File>> attachments) {  
  83.   
  84.         MimeMessage mimeMessage = mailSender.createMimeMessage();  
  85.   
  86.         try {  
  87.             MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);  
  88.             helper.setFrom(emailConfig.getEmailFrom());  
  89.             helper.setTo(sendTo);  
  90.             helper.setSubject(titel);  
  91.   
  92.             String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "template.vm", "UTF-8", content);  
  93.             helper.setText(text, true);  
  94.               
  95.             for (Pair<String, File> pair : attachments) {  
  96.                 helper.addAttachment(pair.getLeft(), new FileSystemResource(pair.getRight()));  
  97.             }  
  98.         } catch (Exception e) {  
  99.             throw new RuntimeServiceException(e);  
  100.         }  
  101.   
  102.         mailSender.send(mimeMessage);  
  103.     }  
  104. }  


 

测试邮件发送:

src/main/java/com/training/email/controller/DemoEmailController.java 

[java] view plain copy
 
  1. package com.training.email.controller;  
  2.   
  3. import io.swagger.annotations.ApiOperation;  
  4.   
  5. import javax.annotation.Resource;  
  6.   
  7. import org.springframework.web.bind.annotation.RequestMapping;  
  8. import org.springframework.web.bind.annotation.RequestMethod;  
  9. import org.springframework.web.bind.annotation.ResponseBody;  
  10. import org.springframework.web.bind.annotation.RestController;  
  11.   
  12. import com.training.core.controller.BaseController;  
  13. import com.training.core.dto.ResultDataDto;  
  14. import com.training.core.email.EmailService;  
  15.   
  16. @RestController  
  17. @RequestMapping(value="/email")   
  18. public class DemoEmailController extends BaseController {  
  19.   
  20.     @Resource  
  21.     private EmailService emailService;  
  22.       
  23.     /** 
  24.      * 测试邮件发送 
  25.      */  
  26.     @ApiOperation(value="测试邮件发送", notes="getEntityById")  
  27.     @RequestMapping(value = "/getTestDemoEmail", method = RequestMethod.GET)  
  28.     public @ResponseBody ResultDataDto getEntityById() throws Exception {  
  29.         String sendTo = "1265400024@qq.com";  
  30.         String titel = "测试邮件标题";  
  31.         String content = "测试邮件内容";  
  32.         emailService.sendSimpleMail(sendTo, titel, content);  
  33.         return ResultDataDto.addSuccess();  
  34.     }  
  35. }  
 
关于使用Java Mail 发邮件,连接超时问题

异常信息

send mail err:Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn’t connect to host, port: smtp.qq.com, 25; timeout -1

在本地windows 是可以发送成功的

怀疑是端口问题,好吧,我用的是 25 端口,开了之后还是连接超时。

那么就很有可能是你的服务器的运营商将25端口封禁了!

换其他端口

我直接用springboot 的模板发邮件

发邮件具体代码看这里:http://www.lrshuai.top/atc/show/41

默认的配置如下:

spring.mail.host=smtp.qq.com
spring.mail.username=1006059906@qq.com
spring.mail.password=这个是你的授权码
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.default-encoding=UTF-8

修改端口为465

spring.mail.host=smtp.qq.com
spring.mail.username=1006059906@qq.com
spring.mail.password=这个是你的授权码
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.default-encoding=UTF-8
spring.mail.port=465
spring.mail.properties.mail.smtp.socketFactory.port = 465
spring.mail.properties.mail.smtp.socketFactory.class = javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.socketFactory.fallback = false

 

这样就ok了,springboot 发邮件的示例代码:https://github.com/rstyro/spring-boot/tree/master/springboot-mail

https://blog.csdn.net/vbirdbest/article/details/79836854

 

本文展示一下如何使用spring mail来发送html邮件。

maven

        <!-- email -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

发送图片

public void send(String from, String[] toMails, String subject, String text,
                     Map<String,Object> inlines) throws Exception{
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        helper.setFrom(from);
        helper.setTo(toMails);
        helper.setSubject(subject);
        //support html
        helper.setText(text, true); 

        // inline
        if(inlines != null){
            for(Map.Entry<String,Object> entry: inlines.entrySet()){
                if(entry.getValue() instanceof ClassPathResource){
                    helper.addInline(entry.getKey(), (Resource) entry.getValue());
                }

            }
        }

        mailSender.send(mimeMessage);
    }

测试

  • 发送实例
        ClassPathResource classPathResource = new ClassPathResource("image_2.png");
        Map<String,Object> att = new HashMap<>();
        att.put("image",classPathResource);
        String content = "<html>
                            <body>
                                <h4>spring mail发送实例</h4>
                                <img src='cid:image'/><br>
                            </body>
                         </html>";
        try{
            mailService.send(new String[]{"xxxxx@163.com"},"spring mail发送实例",content,att);
        }catch (Exception e){
            e.printStackTrace();
        }
  • 异常
org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM 126 smtp7,DsmowAB3U6X1_LdZjIz+Aw--.26008S3 1505230070,please see http://mail.163.com/help/help_spam_16.htm?ip=123.65.107.103&hostid=smtp7&time=1505230070
; message exception details (1) are:
Failed message 1:
com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM 126 smtp7,DsmowAB3U6X1_LdZjIz+Aw--.26008S3 1505230070,please see http://mail.163.com/help/help_spam_16.htm?ip=123.65.107.103&hostid=smtp7&time=1505230070

    at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2267)
    at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:2045)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1260)
    at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:448)
    at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:345)
    at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)

错误码554

554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;

被网易邮箱识别为垃圾邮件了,有个歪招,就是把发送邮箱添加到cc里头

helper.setCc(from);
posted on 2018-05-08 15:47  J'KYO  阅读(372)  评论(0编辑  收藏  举报