maven
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
然后java
package com.metasoft.common.utils;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
public final class JavaMailUntil {
private JavaMailUntil() {}
public static Session createSession() {
// 账号信息
String username = "skin_2023@qq.com";// 邮箱发送账号
String password = "uncinojcclesurcdbb";// 邮箱授权码
// 创建一个配置文件,并保存
Properties props = new Properties();
// SMTP服务器连接信息
// 126——smtp.126.com
// 163——smtp.163.com
// qqsmtp.qq.com"
props.put("mail.smtp.host", "smtp.qq.com");// SMTP主机名
props.put("mail.smtp.ssl.enable", "true");
// 126——25
// 163——645
props.put("mail.smtp.port", "465");// 主机端口号
props.put("mail.smtp.auth", "true");// 是否需要用户认证
props.put("mail.smtp.starttls.enale", "true");// 启用TlS加密
Session session = Session.getInstance(props,new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// TODO Auto-generated method stub
return new PasswordAuthentication(username,password);
}
});
// 控制台打印调试信息
session.setDebug(true);
return session;
}
//正则验证
// 验证邮箱地址是否合法
public static boolean isValidEmailAddress(String email) {
String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
return email.matches(emailRegex);
}
}
然后就是业务层了,包含发送普通邮件,发送附件,发送图片邮件
/**
* 发送邮件
*/
@PostMapping("/sendEmail")
@ApiOperationSupport(order = 18)
@ApiOperation(value = "发送激活邮件", notes = "传入id")
public R sendEmail(String userIds) throws MessagingException {
if (StringUtil.isBlank(userIds)) {
return R.fail("请至少选择一个用户");
}
List<User> userList = userService.list(Wrappers.<User>lambdaQuery().in(User::getId, Func.toLongList(userIds)));
// 创建Session会话
Session session = JavaMailUntil.createSession();
for (User user : userList) {
String targetEmail = "";
//优先判断user的account是不是邮箱地址,如果不是判断user的email是不是邮箱地址,如果也不是,直接抛出异常
// 优先判断user的account是不是邮箱地址
if (JavaMailUntil.isValidEmailAddress(user.getAccount())) {
targetEmail = user.getAccount();
} else {
// 如果user的account不是邮箱地址,则判断user的email是不是邮箱地址
if (JavaMailUntil.isValidEmailAddress(user.getEmail())) {
targetEmail = user.getEmail();
} else {
// 如果都不是邮箱地址,直接跳过
log.info("用户{}的email和account都不是邮箱地址", user.getId());
continue;
}
}
MimeMessage message = new MimeMessage(session);
message.setSubject("邀请您激活账号");
String activationLink = "http://localhost:2888/register?activationCode=" + UUID.randomUUID().toString();
String emailContent = "" +
"\n" +
"感谢您的注册。\n" +
"\n" +
"您目前处于已完成临时注册的状态。\n" +
"\n" +
"如需完成注册,请点击以下URL。" + activationLink;//todo 后续改成线上地址
message.setText(emailContent);
message.setFrom(new InternetAddress("skins_2023@qq.com"));
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(targetEmail));
Transport.send(message);
}
return R.success("操作成功");
}
/**
* 发送邮件带附件
*/
@GetMapping("/sendEmailForFile")
@ApiOperationSupport(order = 18)
@ApiOperation(value = "发送邮件带附件", notes = "传入id")
public R sendEmailForFile(String userIds) throws MessagingException {
try {
// 创建会话
Session session = JavaMailUntil.createSession();
// 创建邮件
MimeMessage message = new MimeMessage(session);
message.setFrom("发送的邮箱");
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress("主要发送人邮箱"));
message.setRecipients(MimeMessage.RecipientType.CC, new InternetAddress[] {new InternetAddress("抄送人邮箱"),new InternetAddress("抄送人邮箱")});
message.setSubject("主题");
// 邮件主体
BodyPart textPart = new MimeBodyPart();
textPart.setContent("文件内容","text/html;charset=utf-8");
// 邮件附件
BodyPart filePart = new MimeBodyPart();
filePart.setFileName("附件显示名字.类型名");
// 提交附件文件
filePart.setDataHandler(new DataHandler(new ByteArrayDataSource(Files.readAllBytes(Paths.get("本地文件路径")),"application/octet-stream")));
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textPart);
multipart.addBodyPart(filePart);
// 将邮件装入信封
message.setContent(multipart);
Transport.send(message);
} catch (AddressException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return R.success("操作成功");
}/**
* 发送邮件带图片
*/
@GetMapping("/sendEmailForPhoto")
@ApiOperationSupport(order = 18)
@ApiOperation(value = "发送邮件带图片", notes = "传入id")
public R sendEmailForPhoto(String userIds) throws MessagingException {
try {
// 创建会话
Session session = JavaMailUntil.createSession();
// 创建邮件
MimeMessage message = new MimeMessage(session);
message.setFrom("发送的邮箱");
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress("主要发送人邮箱"));
message.setRecipients(MimeMessage.RecipientType.CC, new InternetAddress[] {new InternetAddress("抄送人邮箱"),new InternetAddress("抄送人邮箱")});
message.setSubject("主题");
// 邮件主体
BodyPart textPart = new MimeBodyPart();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("文字");
stringBuilder.append("文字");
stringBuilder.append("<img src=\"cid:自定义id\"/>");
textPart.setContent(stringBuilder.toString(),"text/html;charset=utf-8");
// 邮件附件
BodyPart filePart = new MimeBodyPart();
filePart.setFileName("图片名称.jpg");
// 提交附件文件
filePart.setDataHandler(
new DataHandler(
new ByteArrayDataSource(
Files.readAllBytes(
Paths.get("本地路径")),
"application/octet-stream")));
filePart.setHeader("Content-ID","自定义id");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textPart);
multipart.addBodyPart(filePart);
// 将邮件装入信封
message.setContent(multipart);
Transport.send(message);
} catch (AddressException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return R.success("操作成功");
}
/**
* 生成六位数随机验证码
*/
public String generateRandomCode() {
Random random = new Random();
int code = 100000 + random.nextInt(900000);
return String.valueOf(code);
}
/**
* 发送包含验证码的邮件
*/
@GetMapping("/sendVerificationCode")
public R sendVerificationCode(@RequestParam("emailAddress") String emailAddress) throws MessagingException {
//验证邮箱地址是否正确
boolean isValid = JavaMailUntil.isValidEmailAddress(emailAddress);
if (!isValid) {
return R.fail("邮箱地址不正确");
}
String verificationCode = generateRandomCode();
// 创建邮件内容
String emailContent = "您的验证码是:" + verificationCode+"。请在注册或登录时使用。有效期为10分钟。";
// 创建Session会话
Session session = JavaMailUntil.createSession();
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
message.setSubject("密码重置验证码");
message.setText(emailContent);
message.setFrom(new InternetAddress("skins_2023@qq.com"));
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(emailAddress));
// 发送
Transport.send(message);
//验证码存入redis中方便后续读取,有效期为十分钟
bladeRedis.getRedisTemplate().opsForValue().set("verificationCode:" + emailAddress, verificationCode, 10, TimeUnit.MINUTES);
return R.success("验证码已发送到您的邮箱,请查收!");
}
/**
* 账号激活
*/
@PostMapping("/activateAccount")
public R activateAccount(@RequestBody RegisterUserVO userVO) throws MessagingException {
log.info(userVO.toString());
return R.success("账号激活");
}
/**
* 忘记密码-修改密码
*/
@PostMapping("/changePassword")
public R changePassword(@RequestBody RegisterUserVO userVO) throws MessagingException {
log.info(userVO.toString());
//查询是否存在此邮箱的账号
User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getAccount, userVO.getUsername()));
//如果查询不到用户,则返回错误信息
if (user == null) {
return R.fail("用户不存在");
}
//判断两次输入的密码是否一致
if (!userVO.getPassword().equals(userVO.getPassword2())) {
return R.fail("两次输入的密码不一致");
}
//判断验证码是否正确
String verificationCode = (String)bladeRedis.getRedisTemplate().opsForValue().get("verificationCode:" + userVO.getUsername());
if (!verificationCode.equals(userVO.getEmailCode())) {
return R.fail("邮箱验证码错误");
}
// 修改密码
userService.update(Wrappers.<User>update().lambda().set(User::getPassword, DigestUtil.hex(userVO.getPassword())).eq(User::getId, user.getId()));
return R.success("密码修改成功");
}
}
顺便也发出我写的前端代码,vue
<template>
<div class="register-container" ref="register">
<p style="line-height:150%; margin:50pt 0pt 20pt 50pt; text-align:center;">
<span style="font-family:FZXiaoBiaoSong-B05S; font-size:26pt; display:inline-block;">重置密码</span>
</p>
<div class="register-form">
<el-form :model="form" ref="form" :rules="rules" label-width="100px">
<el-form-item label="登录邮箱" prop="username">
<el-input v-model="form.username" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item label="邮箱验证码" prop="emailCode">
<el-input v-model="form.emailCode" placeholder="请输入邮箱验证码"></el-input>
<el-button type="primary" @click="sendEmailCode" :disabled="countDown > 0">{{ countDown > 0 ? countDown + '秒后重新发送' : '发送验证码' }}</el-button>
</el-form-item>
<el-form-item label="新密码" prop="password">
<el-input type="password" v-model="form.password" placeholder="请输入新密码"></el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="password2">
<el-input type="password" v-model="form.password2" placeholder="请再次输入新密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import {changePassword, sendVerificationCode} from "@/api/register/register";
import md5 from 'js-md5';
export default {
data() {
return {
form: {
username: '',
emailCode: '',
password: '',
password2: '',
},
rules: {
username: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
],
emailCode: [
{ required: true, message: '请输入邮箱验证码', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
],
password2: [
{ required: true, message: '请再次输入密码', trigger: 'blur' },
],
},
countDown: 0,
};
},
methods: {
sendEmailCode() {
// 编写发送邮箱验证码的逻辑
if (this.countDown === 0) {
// 模拟发送验证码,实际开发中调用后端接口
console.log('发送验证码');
sendVerificationCode(this.form.username).then(res => {
//如果res的状态码为200,表示发送成功
if (res.status === 200) {
this.$message.success('验证码发送成功');
} else {
this.$message.error('验证码发送失败');
}
});
this.countDown = 60;
const timer = setInterval(() => {
if (this.countDown > 0) {
this.countDown--;
} else {
clearInterval(timer);
}
}, 1000);
}
},
submitForm() {
console.log("要发送的信息====", this.form);
//todo 后续对密码的安全性做处理
this.form.password = md5(this.form.password);
this.form.password2 = md5(this.form.password2);
changePassword(this.form).then(res => {
this.$message({ type: "success", message: "提交成功!" });
this.resetForm();
}, error => {
this.$message({ type: "error", message: "提交失败,请重试!" });
});
},
resetForm() {
this.form = {
username: '',
emailCode: '',
password: '',
password2: '',
};
},
},
};
</script>
<style scoped>
.register-container {
text-align: center;
}
.register-form {
width: 400px;
margin: 0 auto;
}
.el-button {
margin-left: 10px;
}
.el-form-item__content {
display: flex;
}
.el-input {
flex: 1;
}
</style>
这个就是重置密码 利用邮箱验证60秒的功能