在项目中。实现邮箱发送的方式有很多种。
最经典的就是用javaMailSender的方式实现。
先在邮箱中申请了smtp,接着配置application.properties里面的参数
spring.mail.protocol=smtp
spring.mail.host=smtp.qq.com
spring.mail.username=隐藏
spring.mail.password=隐藏
spring.mail.defaultEncoding=UTF-8
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
实现方法
@Service
public class EmailServiceImpl implements EmailService {
//发送邮件的用户名
@Value("${spring.mail.username}")
private String sender;
@Override
public void sendEmail(String to, String subject, StringBuffer content) {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper =null;
try {
helper = new MimeMessageHelper(message,true);
helper.setFrom(sender);
helper.setSubject(subject);
helper.setTo(to);
helper.setText(content.toString(),true);
javaMailSender.send(message);
logger.info("邮件已经发送");
}catch (MessagingException e){
logger.error("邮件发送异常",e);
}
}
然后嵌套在controller中。
注入改该方法。直接使用sendEmail
String code = users.getActiCode();
String subject = "激活邮件";
StringBuffer context = new StringBuffer();
context.append("<h1>你好:"+users.getUserName()+"</h1>")
.append("<h1>激活请点击:</h1><br/><h3><a href='"+sendUrl+"checkCode?code="+code+"'>Click Me</a></h3>");
emailService.sendEmail(users.getUserEmail(),subject,context);
但是会遇到一种情况。就是必须等待它发送完邮件才能进行下一个动作。
容易造成假卡死的状况。如果。与此同时多个用户都在点击这个发送邮件的动作。可能服务器会崩溃。
ActiveMQ使用
消息中间件。具体使用消息队列(MQ)的优点还有概念就不解释了。网上很多。
但是我们需要的业务要求是
- 让发送邮件这个事情丢到消息中间件中,也就是将其作为生产者。
- 消费者收到生产者的消息后,就会开始执行发送邮件这个动作。
- 用户就不用等待了。让消息中间件处理。我们只需要等待consumer发送邮件。
有很多种MQ,我用的是ActiveMQ
下载ActiveMQ
- 官网下载。解压。找到bin–>win64–>activemq.bat运行
- 访问http://localhost:8161,账号密码都默认admin
添加maven依赖
<!-- 记得添加mail依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
添加properties
我这里多创建了一个properties。为了方便区别
application.properties
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
#下面这些不是太必要
#处理序列化对象需要用到的配置
#如果需要这里需要针对queue和topics的选择添加,我没写
spring.activemq.packages.trusted=true
spring.activemq.packages.trust-all=true
spring.activemq.pool.enabled=false
spring.activemq.pool.max-connections=50
spring.activemq.pool.idle-timeout=30000
email.properties
spring.mail.protocol=smtp
spring.mail.host=smtp.qq.com
spring.mail.username=隐藏
spring.mail.password=隐藏
spring.mail.defaultEncoding=UTF-8
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
#这里是一个业务需要用得的地址,不需要跟着我添加
com.mailUrl=http://localhost:8081/
创建生产者
记得创建相应的接口
@Slf4j
@Service
public class ActiveMQServiceImpl implements ActiveMQService {
@Autowired
JmsTemplate template;
/**
*@Auther kiwi
*@Data 2019/9/8
* 发送邮件
*/
@Override
public void sendEmail(String to, String subject, String content) throws IOException {
template.send("registerBySystem", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("content", content);
mapMessage.setString("address", to);
mapMessage.setString("subject", subject);
return mapMessage;
}
});
log.info("发送给消费者");
}
}
to是发送过去的邮箱,subject是标题,content是邮件的内容
这里使用了JmsTemplate的send方法。第一个参数是生产者发布的名称。后面是传入Message的值,通过这里的Message作为中间值。
消费者
注意,消费者必须加上@Service或者@Component
消费者才能检测到
@Slf4j
@Service
public class ConsumerService {
@Autowired
private EmailUtil emailUtil;
/**
* 通过监听目标队列实现功能
*/
@JmsListener(destination = "registerBySystem")
public void sendMail(Message message) throws Exception {
MapMessage mapMessage = (MapMessage) message;
String content = mapMessage.getString("content");
String address = mapMessage.getString("address");
String subject = mapMessage.getString("subject");
emailUtil.sendEmail(address,subject,content);
}
}
通过注解@JmsListener里面对生产者名称“registerBySystem”的监听。
然后通过message的值,传入sendEmail。
也就是这里,我们开始出现发送邮件的动作。
发送邮件
@Slf4j
@Component
@PropertySource(value = {"classpath:email.properties"})
public class EmailUtil {
@Value("${spring.mail.username}")
private String sender;
@Value("${spring.mail.host}")
private String host;
@Value("${spring.mail.password}")
private String pwd;
public void sendEmail(String to, String subject, String content) throws Exception {
Properties props = new Properties();
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.smtp.host", host);
props.setProperty("mail.smtp.auth", "true");
Session session = Session.getDefaultInstance(props);
// 开启debug模式,可以看到更多详细的输入日志
MimeMessage message = this.addEmail(session,to,subject, content);
//获取传输通道
Transport transport = session.getTransport();
transport.connect(host, sender, pwd);
//连接,并发送邮件
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
/**
* 创建邮件
*/
public MimeMessage addEmail(Session session,String to, String subject, String content) throws Exception {
// 根据会话创建邮件
MimeMessage msg = new MimeMessage(session);
// 设置发送邮件方
msg.setFrom(new InternetAddress(sender));
// 设置邮件接收方
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
// 设置邮件标题
msg.setSubject(subject, "utf-8");
msg.setContent(content,"text/html;charset=utf-8");
// 设置显示的发件时间
msg.setSentDate(new Date());
// 保存设置
msg.saveChanges();
return msg;
}
}
具体实现注册很详细了。
注意。在刚刚的ConsumerService中。一定要Autowired该方法。
才能在这里通过@Value获取email.properties的值
邮件模板
也就是content参数
public class EmailTemplate {
/**
*@Auther kiwi
*@Data 2019/9/8
@param * @param
* 注册模板
*@reutn java.lang.String
*/
public static String registerTemplate(String sendUrl,String code) throws IOException {
String fileName = "pod-scale-alarm.html";
InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName);
BufferedReader fileReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer buffer = new StringBuffer();
String line = "";
try {
while ((line = fileReader.readLine()) != null) {
buffer.append(line);
}
} catch (Exception e) {
log.error("读取文件失败,fileName:{}", fileName, e);
} finally {
inputStream.close();
fileReader.close();
}
String contentText = "以下是需要点击的链接, 进入便可完成注册.<a href='"+sendUrl+"checkCode?code="+code+"'>Click Me</a>";
//邮件表格header
String header = "<td>商品管理(itemManagement)</td><td>订单管理(orderManagement)</td><td>用户管理(userManagement)</td><td>系统管理(systemManagement)</td><td>调度任务(Scheduled Tasks)</td>";
StringBuilder linesBuffer = new StringBuilder();
linesBuffer.append("<tr><td>" + "four menu" + "</td><td>" + "four menu" + "</td><td>" + "three menu" + "</td>" +
"<td>" + "two menu" + "</td><td>" + "two menu" + "</td></tr>");
String emailHeadColor = "#8A2BE2";
String date = DateFormatUtils.format(new Date(), "yyyy/MM/dd HH:mm:ss");
//填充html模板中的五个参数
String htmlText = MessageFormat.format(buffer.toString(), emailHeadColor, contentText, date, header, linesBuffer.toString());
//改变表格样式
htmlText = htmlText.replaceAll("<td>", "<td style=\"padding:6px 10px; line-height: 150%;\">");
htmlText = htmlText.replaceAll("<tr>", "<tr style=\"border-bottom: 1px solid #eee; color:#666;\">");
return htmlText;
}
}
pod-scale-alarm.html
<body style="color: #666; font-size: 14px; font-family: 'Open Sans',Helvetica,Arial,sans-serif;">
<div class="box-content" style="width: 80%; margin: 20px auto; max-width: 800px; min-width: 600px;">
<div class="header-tip" style="font-size: 12px;
color: #aaa;
text-align: right;
padding-right: 25px;
padding-bottom: 10px;">
<a href="http://www.kiwi1.cn" >Welcome to my Blog</a>
</div>
<div class="info-top" style="padding: 15px 25px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
background: {0};
color: #fff;
overflow: hidden;
line-height: 32px;">
<img alt="Hello" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1567918888673&di=882438e088da517bca429a3eb88a9034&imgtype=0&src=http%3A%2F%2Fgss0.baidu.com%2F94o3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2F6a600c338744ebf8225842acd9f9d72a6059a773.jpg"
style="float: left; margin: 0 10px 0 0; width: 32px;" /><div style="color:#010e07"><strong>欢迎注册网站 b2b_mall</strong></div>
</div>
<div class="info-wrap" style="border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
border:1px solid #ddd;
overflow: hidden;
padding: 15px 15px 20px;">
<div class="tips" style="padding:15px;">
<p style=" list-style: 160%; margin: 10px 0;">Hi,</p>
<p style=" list-style: 160%; margin: 10px 0;">{1}</p>
</div>
<div class="time" style="text-align: right; color: #999; padding: 0 15px 15px;">{2}</div>
<br>
<table class="list" style="width: 100%; border-collapse: collapse; border-top:1px solid #eee; font-size:12px;">
<thead>
<tr style=" background: #fafafa; color: #333; border-bottom: 1px solid #eee;">
{3}
</tr>
</thead>
<tbody>
{4}
</tbody>
</table>
</div>
</div>
</body>
使用activeMQService
//注入,记得加上@PropertySource("email.properties")
@Resource
private ActiveMQService activeMQService;
@Value("${com.mailUrl}")
private String sendUrl;
//实现
activeMQService.sendEmail("????@qq.com","欢迎注册", EmailTemplate.registerTemplate(sendUrl,"参数地址")));
可根据自己的代码修改