1. 程式人生 > >Java(SpringCloud) 使用Thymeleaf渲染模板,通過Mailgun傳送郵件

Java(SpringCloud) 使用Thymeleaf渲染模板,通過Mailgun傳送郵件

好久沒發部落格了,忙東忙西的,堅持!

本文介紹Java使用Mailgun搭建傳送郵件的服務。

我把這個郵件服務放在了我的springCloudApplication(微服務Demo)專案的utilservice服務模組中。
原始碼地址:springCloudApplication

  • jdk1.8
  • SpringBoot版本:2.0.4.RELEASE
  • SpringCloud版本:Finchley.RELEASE
  • Intellij IDEA :2018-2

本文涉及到基礎的SpringCloud 知識,對應到本專案中的服務名來說就是:服務註冊中心(eurekaserver),配置中心(configserver),路由(routeservice),負載均衡服務呼叫(uaaservice)。

一、Mailgun

其實程式碼沒多少,就是配置Mailgun需要花費些時間。

先用郵箱註冊好。
在這裡插入圖片描述

Settings,顯示的就是你的賬戶資訊。
Security,這裡的 Private API Key 就是等會要用到的身份認證key。
在這裡插入圖片描述
Authorized Recipients
在這裡插入圖片描述
Upgrade,升級賬戶,貌似是$1。繫結你的信用卡。
在這裡插入圖片描述
接下來跳轉到:https://app.mailgun.com/app/domains
domains,域名。上面個是我自己的域名(這裡本該解析個二級域名的,我直接用頂級域名搞了一次),下面個是當你註冊賬戶時Mailgun為你自動生成的一個二級域名。
在這裡插入圖片描述
剛開始進這個頁面是隻有下面個域名,自己的域名要通過Add New Aomain新增。
在這裡插入圖片描述


新增完之後你的域名會顯示:Unverified,點選自己的域名驗證,往下拉,看Domain Verification & DNS部分
在這裡插入圖片描述
要去自己的域名服務商控制檯配置,我這裡全都配置好了所以全綠。我的域名阿里雲買的,解析記錄如下:
在這裡插入圖片描述
看著這個GIF跟著配置就好了:https://help.mailgun.com/hc/en-us/articles/202052074-How-do-I-verify-my-domain-
我還添加了個SMTP Credentials:
在這裡插入圖片描述
在這裡插入圖片描述
好,現在Mailgun配置算是完成了。接下來上程式碼。還有啥問題就翻它的文件吧。

二、程式碼

我這裡寫了兩種方式的郵件內容,一種純文字內容的,一種thymeleaf模板引擎渲染的html內容的。就放在一起寫了。只上核心程式碼和配置。詳細瞭解看原始碼,文章開頭已給出地址。
專案結構:
在這裡插入圖片描述

  • eurekaserver,服務註冊中心
  • confiserver,配置中心,幾乎所有功能模組的配置都放在這裡的
  • routeserver,路由閘道器
  • utilservice,郵件服務所在模組
  • uaaservice,在這裡呼叫郵件服務

呼叫服務時傳入收件人郵箱List,郵件的主題,郵件的thymeleaf模板,模板的引數(Map<String,Object>)。然後在郵件服務中渲染模板,然後通過mailgun傳送郵件。

mailgun配置屬性:

mailgun:
  domain: mistra.wang
  apiKey: key-e9861fdc2c1a6f189528c9cf18c5dc1a
  from: 丶小王瑞
  fromAddress: [email protected]
  mailgunResource: https://api.mailgun.net/v3/mistra.wang/messages

注意:如果寫程式碼的時候把這個配置,就是你的mailgun的敏感資訊,如key等。push到了Github的公共倉庫的話你的郵件服務用不了,你的賬戶會被禁用。並且你會收到郵件提示,如何解決。記得測試完了程式碼再push。還挺嚴謹安全的,我測試完,剛push,馬上我的賬戶就用不了了。
在這裡插入圖片描述
配置屬性安全對映實體類

@Data
@Configuration
@ConfigurationProperties(prefix = "mailgun")
public class MailgunConfigProperties {
    private String domain;
    private String apiKey;
    private String from;
    private String fromAddress;
    private String mailgunResource;
}

MailgunConfig配置

@Configuration
public class MailgunConfig {
    /**
     * mailgun配置引數
     */
    @Autowired
    private MailgunConfigProperties mailgunConfigProperties;

    @Bean
    public net.sargue.mailgun.Configuration mailgunConfiguration(){
        net.sargue.mailgun.Configuration configuration = new net.sargue.mailgun.Configuration()
                .from(mailgunConfigProperties.getFrom(), mailgunConfigProperties.getFromAddress())
                .apiKey(mailgunConfigProperties.getApiKey())
                .domain(mailgunConfigProperties.getDomain());
        return configuration;
    }
}

thymeleaf模板引擎配置

@Configuration
public class SpringTemplateEngineConfig {

    @Bean(name = "stringTemplateEngine")
    public SpringTemplateEngine springTemplateEngine() {
        //字串模板引擎物件
        SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
        //內建方言
        IDialect springStandardDialect = new SpringStandardDialect();
        springTemplateEngine.setDialect(springStandardDialect);
        //字串解析器
        StringTemplateResolver stringTemplateResolver = new StringTemplateResolver();
        //使用快取
        stringTemplateResolver.setCacheable(true);
        stringTemplateResolver.setTemplateMode(TemplateMode.HTML);
        springTemplateEngine.setTemplateResolver(stringTemplateResolver);
        return springTemplateEngine;
    }
}

執行緒池Bean

@Component
public class ThreadPoolConfig extends ThreadPoolTaskExecutor {

}

郵件實體

@Data
public class MailDTO {
    /**
     * 傳送物件
     */
    @NotEmpty
    private List<String> sendToAddress;
    /**
     * 主題
     */
    @NotNull
    private String subject;
    /**
     * 模板
     */
    @NotNull
    private String template;
    /**
     * 模板引數
     */
    @NotNull
    private Map<String,Object> paramsMap;
}

service

package com.mistra.utilservice.service.impl;

import com.mistra.base.result.Result;
import com.mistra.utilservice.config.MailgunConfigProperties;
import com.mistra.utilservice.dto.MailDTO;
import com.mistra.utilservice.service.MailService;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import net.sargue.mailgun.*;
import net.sargue.mailgun.content.Body;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;

import javax.ws.rs.core.MediaType;
import java.util.regex.Pattern;

/**
 * @Author: WangRui
 * @Date: 2018/10/14
 * Time: 下午10:35
 * Description:
 */
@Service
public class MailServiceImpl implements MailService {

    private Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);

    /**
     * 郵箱驗證正則
     */
    public static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";

    /**
     * 字串模板解析引擎
     */
    @Qualifier("stringTemplateEngine")
    @Autowired
    private SpringTemplateEngine springTemplateEngine;

    @Autowired
    private Configuration mailgunConfiguration;

    @Autowired
    private MailgunConfigProperties mailgunConfigProperties;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public Result sendMail(MailDTO mailDTO) {
        return sendTwo(mailDTO);
    }

    public Result sendOne(MailDTO mailDTO) {
        Result result = new Result();
        if (mailDTO.getSendToAddress().size() == 0 || mailDTO.getParamsMap().size() == 0 || StringUtils.isEmpty(mailDTO.getSubject()) || StringUtils.isEmpty(mailDTO.getTemplate())) {
            result.setSuccess(false);
            result.setMessage("MailDTO引數不正確!");
            return result;
        }
        for (String to : mailDTO.getSendToAddress()) {
            if (!Pattern.matches(REGEX_EMAIL, to)) {
                result.setSuccess(false);
                result.setMessage("郵箱格式錯誤!");
                return result;
            }
        }
        //編譯thymeleaf模板 渲染資料
        Context context = new Context();
        context.setVariables(mailDTO.getParamsMap());
        String mailContent = springTemplateEngine.process(mailDTO.getTemplate(), context);
        Body mailBody = new Body(mailContent, "");

        MailBuilder mailBuilder = Mail.using(mailgunConfiguration);
        mailBuilder.subject(mailDTO.getSubject());
        mailBuilder.content(mailBody);
        for (String sendTo : mailDTO.getSendToAddress()) {
            mailBuilder.to(sendTo);
        }
        result.setSuccess(false);
        result.setMessage("郵件傳送成功!");
        threadPoolTaskExecutor.submit(() -> {
            Response response = mailBuilder.build().send();
            logger.info("Send mail complete. Code: {}, Response Type: {}. Message: {}", response.responseCode(), response.responseType(), response.responseMessage());
            if (response.responseCode() != 200) {
                result.setSuccess(false);
                result.setMessage("郵件傳送失敗!" + response.responseMessage());
            }
        });
        return result;
    }

    /**
     * 第二種 傳送純文字郵件
     *
     * @param mailDTO
     * @return
     */
    public Result sendTwo(MailDTO mailDTO) {
        Result result = new Result();
        Client client = Client.create();
        client.addFilter(new HTTPBasicAuthFilter("api", mailgunConfigProperties.getApiKey()));
        WebResource webResource = client.resource(mailgunConfigProperties.getMailgunResource());
        MultivaluedMapImpl formData = new MultivaluedMapImpl();
        formData.add("from", mailgunConfigProperties.getFrom() + "" + mailgunConfigProperties.getFromAddress());
        mailDTO.getSendToAddress().stream().forEach(temp -> formData.add("to", temp));
        formData.add("subject", mailDTO.getSubject());
        formData.add("text", "純文字郵件測試!");
        webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, formData);
        return result;
    }
}

三、檢視Mailgun日誌

你可以看到每一次傳送郵件的日誌,報錯原因。
在這裡插入圖片描述
這個錯誤就是我的賬戶被禁用了,暴露了賬戶憑證,就是我把我的賬戶資訊push到了Github公共倉庫引起的。覆蓋提交Commit是不管用的了,它提示你刪庫0-0,麻蛋。

"reject": {
        "reason": "exposed account credentials",
        "description": ""
    },

在這裡插入圖片描述

全文完。另外我是馬自達粉。嘿嘿。

在這裡插入圖片描述