发送邮件和短信都需要做好准备工作,本文的邮件使用了QQ邮箱作为发送者,要开启SMTP;短信用的是阿里云,要有创建好的签名和审核通过的短信模板,本文的主要内容的代码模块,这两个服务的准备工作就不多介绍了。
本来邮箱用的是163,但是163邮箱发送邮件一直提示554,不管怎么修改都不行,只好改用qq。
导入Maven依赖
<!--发送邮件--> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-mail</artifactId> | |
</dependency> | |
<!--发送短信--> | |
<dependency> | |
<groupId>com.aliyun</groupId> | |
<artifactId>aliyun-java-sdk-core</artifactId> | |
<version>.5.1</version> | |
</dependency> | |
<dependency> | |
<groupId>com.aliyun</groupId> | |
<artifactId>aliyun-java-sdk-dysmsapi</artifactId> | |
<version>.1.0</version> | |
</dependency> |
然后是配置文件application:
server: | |
port: | |
spring: | |
mail: | |
host: smtp.qq.com # 邮件服务地址 | |
username: 自己填 # 发送者邮箱 | |
password: 自己填 # 授权码 | |
default-encoding: UTF- # 默认的邮件编码为UTF-8 | |
properties: | |
mail: | |
smtp: | |
auth: true | |
# 如果是用 SSL 方式,需要配置如下属性,使用qq邮箱的话需要开启 | |
starttls: | |
enable: true | |
required: true | |
sms: | |
accessKeyId: 自己填 | |
accessSecret: 自己填 | |
signName: 自己填 | |
templateCode: 自己填 |
发送邮件
邮件有多种类型:普通的纯文本、html格式、带附件、内容带图片。
package com.cc.service; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.core.io.FileSystemResource; | |
import org.springframework.mail.SimpleMailMessage; | |
import org.springframework.mail.javamail.JavaMailSender; | |
import org.springframework.mail.javamail.MimeMessageHelper; | |
import org.springframework.stereotype.Service; | |
import javax.mail.MessagingException; | |
import javax.mail.internet.MimeMessage; | |
import java.io.File; | |
import java.util.Map; | |
/** | |
* 邮件服务 | |
* @author cc | |
* @date-12-07 10:37 | |
*/ | |
public class MailService { | |
private final JavaMailSender mailSender; | |
private String SENDER; | |
public MailService(JavaMailSender mailSender) { | |
this.mailSender = mailSender; | |
} | |
// 发送普通邮件 | |
public void sendSimpleMailMessage(String to, String subject, String content) { | |
SimpleMailMessage message = new SimpleMailMessage(); | |
message.setFrom(SENDER); | |
message.setTo(to); | |
message.setSubject(subject); | |
message.setText(content); | |
mailSender.send(message); | |
} | |
// 发送html邮件 | |
public void sendMimeMessage(String to, String subject, String content) throws MessagingException { | |
MimeMessage message = mailSender.createMimeMessage();; | |
// true表示需要创建一个multipart message | |
MimeMessageHelper helper = new MimeMessageHelper(message, true); | |
helper.setFrom(SENDER); | |
helper.setTo(to); | |
helper.setSubject(subject); | |
helper.setText(content, true); | |
mailSender.send(message); | |
} | |
// 发送带附件的邮件 | |
public void sendMimeMessage(String to, String subject, String content, String filePath) throws MessagingException { | |
MimeMessage message = mailSender.createMimeMessage();; | |
// true表示需要创建一个multipart message | |
MimeMessageHelper helper = new MimeMessageHelper(message, true); | |
helper.setFrom(SENDER); | |
helper.setTo(to); | |
helper.setSubject(subject); | |
helper.setText(content, true); | |
FileSystemResource file = new FileSystemResource(new File(filePath)); | |
String fileName = file.getFilename(); | |
helper.addAttachment(fileName, file); | |
mailSender.send(message); | |
} | |
// 发送带静态文件的邮件 | |
public void sendMimeMessage(String to, String subject, String content, Map<String,String> rscIdMap) throws MessagingException { | |
MimeMessage message = mailSender.createMimeMessage(); | |
// true表示需要创建一个multipart message | |
MimeMessageHelper helper = new MimeMessageHelper(message, true); | |
helper.setFrom(SENDER); | |
helper.setTo(to); | |
helper.setSubject(subject); | |
helper.setText(content, true); | |
for (Map.Entry<String, String> entry : rscIdMap.entrySet()) { | |
FileSystemResource file = new FileSystemResource(new File(entry.getValue())); | |
helper.addInline(entry.getKey(), file); | |
} | |
mailSender.send(message); | |
} | |
} |
发送短信
package com.cc.service; | |
import com.aliyuncs.DefaultAcsClient; | |
import com.aliyuncs.IAcsClient; | |
import com.aliyuncs.dysmsapi.model.v.SendSmsRequest; | |
import com.aliyuncs.dysmsapi.model.v.SendSmsResponse; | |
import com.aliyuncs.exceptions.ClientException; | |
import com.aliyuncs.profile.DefaultProfile; | |
import com.aliyuncs.profile.IClientProfile; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.stereotype.Service; | |
import org.springframework.util.StringUtils; | |
/** | |
* 短信服务 | |
* | |
* @author cc | |
* @date-12-07 9:50 | |
*/ | |
public class SmsService { | |
private String accessKeyId; | |
private String accessSecret; | |
private String signName; | |
private String templateCode; | |
public void send(String phone, String code) throws ClientException { | |
if (StringUtils.isEmpty(phone)) { | |
throw new RuntimeException("手机号码不能为空"); | |
} | |
if (StringUtils.isEmpty(code)) { | |
throw new RuntimeException("验证码不能为空"); | |
} | |
// 初始化acsClient,暂不支持region化 | |
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", | |
accessKeyId, accessSecret); | |
IAcsClient acsClient = new DefaultAcsClient(profile); | |
// 组装请求对象-具体描述见控制台-文档部分内容 | |
SendSmsRequest request = new SendSmsRequest(); | |
// 必填:待发送手机号 | |
request.setPhoneNumbers(phone); | |
// 必填:短信签名-可在短信控制台中找到 | |
request.setSignName(signName); | |
// 必填:短信模板-可在短信控制台中找到 | |
request.setTemplateCode(templateCode); | |
request.setTemplateParam("{\"code\":\"" + code + "\"}"); | |
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); | |
if(sendSmsResponse.getCode()!= null && "OK".equals(sendSmsResponse.getCode())){ | |
System.out.println("短信发送成功!"); | |
}else { | |
throw new RuntimeException("短信发送失败:" + sendSmsResponse.getMessage()); | |
} | |
} | |
} |
生成验证码
package com.cc.utils; | |
import java.util.Random; | |
/** | |
* 验证码生成器 | |
* @author cc | |
* @date-12-07 10:32 | |
*/public class VerifyCodeGenerator { | |
public static String make(int length) { | |
if (length <=) { | |
throw new RuntimeException("验证码长度不能小于"); | |
} | |
StringBuilder sb = new StringBuilder(); | |
Random random = new Random(); | |
for (int i =; i < length; i++) { | |
sb.append(random.nextInt()); | |
} | |
return sb.toString(); | |
} | |
} |
测试一下
在使用邮件的附件功能时,要提前在resources中添加pic01.png、pic02.png和test.txt文件,方便测试
测试类:
package com.cc; | |
import com.aliyuncs.exceptions.ClientException; | |
import com.cc.service.MailService; | |
import com.cc.service.SmsService; | |
import com.cc.utils.VerifyCodeGenerator; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.boot.test.context.SpringBootTest; | |
import org.springframework.test.context.junit.SpringRunner; | |
import org.springframework.util.ResourceUtils; | |
import javax.mail.MessagingException; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.util.HashMap; | |
import java.util.Map; | |
public class ApplicationTest { | |
// test中不能有有参构造函数 | |
private MailService mailService; | |
private SmsService smsService; | |
private static final String TO = "xxx@qq.com"; | |
private static final String SUBJECT = "出师表"; | |
private static final String CONTENT = "先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。\n" + | |
"宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。"; | |
// 测试发送普通邮件 | |
public void sendSimpleMailMessage() { | |
mailService.sendSimpleMailMessage(TO, SUBJECT, CONTENT); | |
} | |
// 测试发送html邮件 | |
public void sendHtmlMessage() throws MessagingException { | |
String htmlStr = "<h>Test</h1>"; | |
mailService.sendMimeMessage(TO, SUBJECT, htmlStr); | |
} | |
// 测试发送带附件的邮件 | |
public void sendAttachmentMessage() throws FileNotFoundException, MessagingException { | |
File file = ResourceUtils.getFile("classpath:test.txt"); | |
System.out.println(file); | |
String filePath = file.getAbsolutePath(); | |
mailService.sendMimeMessage(TO, SUBJECT, CONTENT, filePath); | |
} | |
// 测试发送带静态文件的邮件 | |
public void sendStaticFileMessage() throws FileNotFoundException, MessagingException { | |
String htmlStr = "<html><body>测试:图片 <br> <img src=\'cid:pic1\'/><br>图片2 <br> <img src=\'cid:pic2\'/></body></html>"; | |
Map<String, String> rscIdMap = new HashMap<>(); | |
rscIdMap.put("pic", ResourceUtils.getFile("classpath:pic01.png").getAbsolutePath()); | |
rscIdMap.put("pic", ResourceUtils.getFile("classpath:pic02.png").getAbsolutePath()); | |
mailService.sendMimeMessage(TO, SUBJECT, htmlStr, rscIdMap); | |
} | |
// 测试发送短信 | |
public void sendSms() throws ClientException { | |
smsService.send("your phone", VerifyCodeGenerator.make()); | |
} | |
// 生成一段验证码 | |
public void generatorVerifyCode() { | |
System.out.println(VerifyCodeGenerator.make()); | |
} | |
} |
邮件和短信的发送还是很简单的,都是调调接口。
使用短信的话要留意是收费的,当前的价格是0.045分一条。