我把这个邮件服务放在了我的springCloudApplication(微服务Demo)项目的utilservice服务模块中。
源码地址:springCloudApplication
本文涉及到基础的SpringCloud 知识,对应到本项目中的服务名来说就是:服务注册中心(eurekaserver),配置中心(configserver),路由(routeservice),负载均衡服务调用(uaaservice)。
Mailgun是国外的一个邮件服务器。主页:https://app.mailgun.com/
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内容的。就放在一起写了。只上核心代码和配置。详细了解看源码,文章开头已给出地址。
项目结构:
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 sendToAddress;
/**
* 主题
*/
@NotNull
private String subject;
/**
* 模板
*/
@NotNull
private String template;
/**
* 模板参数
*/
@NotNull
private Map 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;
}
}
你可以看到每一次发送邮件的日志,报错原因。
这个错误就是我的账户被禁用了,暴露了账户凭证,就是我把我的账户信息push到了Github公共仓库引起的。覆盖提交Commit是不管用的了,它提示你删库0-0,麻蛋。
"reject": {
"reason": "exposed account credentials",
"description": ""
},
全文完。另外我是马自达粉。嘿嘿。
我的: