本文目录导读:

- 项目结构
- Maven依赖(pom.xml)
- 邮箱服务类(EmailService.java)
- 验证码服务类(EmailVerificationService.java)
- 配置文件(application.properties)
- 测试类(Main.java)
- 配置说明
- 安全性增强建议
- 使用Spring Boot后的接口版本
- 使用建议
我来为你提供一个完整的Java邮箱验证案例,包含发送验证码和验证功能。
项目结构
email-verification/
├── pom.xml
├── src/main/java/com/example/email/
│ ├── EmailService.java
│ ├── EmailVerificationService.java
│ └── Main.java
└── src/main/resources/
└── application.properties
Maven依赖(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>email-verification</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JavaMail -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<!-- Spring Boot Mail Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.7.0</version>
</dependency>
<!-- Redis (可选,用于存储验证码) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.0</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
</dependencies>
</project>
邮箱服务类(EmailService.java)
package com.example.email;
import org.springframework.beans.factory.annotation.Value;
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.internet.MimeMessage;
@Service
public class EmailService {
private final JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String fromEmail;
public EmailService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
/**
* 发送普通文本邮件
*/
public void sendSimpleEmail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(fromEmail);
message.setTo(to);
message.setSubject(subject);
message.setText(content);
mailSender.send(message);
}
/**
* 发送HTML邮件
*/
public void sendHtmlEmail(String to, String subject, String htmlContent) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setFrom(fromEmail);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true); // true表示HTML格式
mailSender.send(message);
} catch (Exception e) {
throw new RuntimeException("发送HTML邮件失败", e);
}
}
}
验证码服务类(EmailVerificationService.java)
package com.example.email;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;
@Service
public class EmailVerificationService {
private static final String VERIFICATION_CODE_PREFIX = "email:verification:";
private static final String LOCK_PREFIX = "email:lock:";
private static final long CODE_EXPIRE_MINUTES = 5; // 验证码有效期
private static final long LOCK_EXPIRE_MINUTES = 10; // 发送锁定时间
private static final int MAX_SEND_COUNT = 3; // 最大发送次数
@Autowired
private EmailService emailService;
@Autowired(required = false)
private StringRedisTemplate redisTemplate;
// 简单的内存缓存(不使用Redis时)
private Map<String, VerificationInfo> verificationCache = new ConcurrentHashMap<>();
/**
* 发送验证码
* @param email 邮箱地址
* @return 成功返回true,失败返回false
*/
public boolean sendVerificationCode(String email) {
// 1. 检查发送频率
if (isTooFrequent(email)) {
throw new RuntimeException("发送太频繁,请稍后再试");
}
// 2. 生成6位数字验证码
String code = generateCode();
// 3. 存储验证码
saveVerificationCode(email, code);
// 4. 发送邮件
try {
String content = buildEmailContent(code);
emailService.sendHtmlEmail(email, "邮箱验证码", content);
// 5. 更新发送记录
incrementSendCount(email);
return true;
} catch (Exception e) {
// 发送失败,清除验证码
deleteVerificationCode(email);
throw new RuntimeException("验证码发送失败", e);
}
}
/**
* 验证邮箱验证码
* @param email 邮箱地址
* @param code 验证码
* @return 是否验证成功
*/
public boolean verifyCode(String email, String code) {
if (email == null || code == null) {
return false;
}
// 获取存储的验证码
String storedCode = getVerificationCode(email);
// 验证码不存在或已过期
if (storedCode == null) {
return false;
}
// 验证码匹配
if (storedCode.equals(code)) {
// 验证成功后删除验证码
deleteVerificationCode(email);
return true;
}
return false;
}
/**
* 生成6位数字验证码
*/
private String generateCode() {
SecureRandom random = new SecureRandom();
int code = 100000 + random.nextInt(900000);
return String.valueOf(code);
}
/**
* 保存验证码
*/
private void saveVerificationCode(String email, String code) {
String key = VERIFICATION_CODE_PREFIX + email;
if (redisTemplate != null) {
redisTemplate.opsForValue().set(key, code, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
} else {
VerificationInfo info = new VerificationInfo(code,
System.currentTimeMillis() + CODE_EXPIRE_MINUTES * 60 * 1000);
verificationCache.put(email, info);
}
}
/**
* 获取验证码
*/
private String getVerificationCode(String email) {
String key = VERIFICATION_CODE_PREFIX + email;
if (redisTemplate != null) {
return redisTemplate.opsForValue().get(key);
} else {
VerificationInfo info = verificationCache.get(email);
if (info != null) {
if (System.currentTimeMillis() > info.expireTime) {
verificationCache.remove(email);
return null;
}
return info.code;
}
return null;
}
}
/**
* 删除验证码
*/
private void deleteVerificationCode(String email) {
String key = VERIFICATION_CODE_PREFIX + email;
if (redisTemplate != null) {
redisTemplate.delete(key);
} else {
verificationCache.remove(email);
}
}
/**
* 检查发送是否过于频繁
*/
private boolean isTooFrequent(String email) {
String key = LOCK_PREFIX + email;
if (redisTemplate != null) {
Boolean locked = redisTemplate.hasKey(key);
return Boolean.TRUE.equals(locked);
} else {
// 简单的内存检查
return false;
}
}
/**
* 增加发送计数
*/
private void incrementSendCount(String email) {
String key = LOCK_PREFIX + email;
if (redisTemplate != null) {
// 设置锁定时间,防止重复发送
redisTemplate.opsForValue().set(key, "1", LOCK_EXPIRE_MINUTES, TimeUnit.MINUTES);
}
}
/**
* 构建邮件HTML内容
*/
private String buildEmailContent(String code) {
return String.format("""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.header {
background-color: #4CAF50;
color: white;
padding: 20px;
text-align: center;
border-radius: 5px 5px 0 0;
}
.content {
padding: 20px;
background-color: #f9f9f9;
border: 1px solid #ddd;
}
.code {
font-size: 36px;
font-weight: bold;
color: #4CAF50;
text-align: center;
letter-spacing: 10px;
margin: 20px 0;
}
.warning {
color: #999;
font-size: 12px;
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>邮箱验证</h2>
</div>
<div class="content">
<p>亲爱的用户:</p>
<p>您正在请求操作验证,您的验证码为:</p>
<div class="code">%s</div>
<p><b>验证码有效期:</b>5分钟</p>
<p><b>请勿泄露给他人!</b></p>
<div class="warning">
如果您没有请求此操作,请忽略此邮件。
</div>
</div>
</div>
</body>
</html>
""", code);
}
/**
* 验证码信息类(内存缓存使用)
*/
private static class VerificationInfo {
String code;
long expireTime;
VerificationInfo(String code, long expireTime) {
this.code = code;
this.expireTime = expireTime;
}
}
}
配置文件(application.properties)
# 邮件配置 spring.mail.host=smtp.qq.com spring.mail.port=587 spring.mail.username=your-email@qq.com # 授权码(不是邮箱密码) spring.mail.password=your-authorization-code spring.mail.protocol=smtp spring.mail.default-encoding=UTF-8 # SSL/TLS配置 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.connectiontimeout=10000 spring.mail.properties.mail.smtp.timeout=10000 spring.mail.properties.mail.smtp.writetimeout=10000 # Redis配置(可选) spring.redis.host=localhost spring.redis.port=6379 spring.redis.database=0
测试类(Main.java)
package com.example.email;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import java.util.Scanner;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
@Bean
public CommandLineRunner demo(EmailVerificationService verificationService) {
return args -> {
Scanner scanner = new Scanner(System.in);
System.out.println("=== 邮箱验证码演示程序 ===");
System.out.println("请输入要验证的邮箱地址:");
String email = scanner.nextLine();
// 发送验证码
try {
verificationService.sendVerificationCode(email);
System.out.println("验证码已发送到 " + email);
System.out.println("请查看邮箱获取验证码");
// 输入验证
System.out.println("请输入验证码:");
String code = scanner.nextLine();
// 验证码验证
boolean result = verificationService.verifyCode(email, code);
if (result) {
System.out.println("✅ 验证码正确,邮箱验证成功!");
} else {
System.out.println("❌ 验证码错误或已过期,验证失败!");
}
} catch (Exception e) {
System.out.println("发送验证码失败:" + e.getMessage());
}
scanner.close();
};
}
}
配置说明
QQ邮箱配置
- 登录QQ邮箱设置
- 开启SMTP服务
- 获取授权码(16位)
163邮箱配置
spring.mail.host=smtp.163.com spring.mail.port=465 spring.mail.username=your-email@163.com spring.mail.password=your-authorization-code
Gmail配置
spring.mail.host=smtp.gmail.com spring.mail.port=587 spring.mail.username=your-email@gmail.com spring.mail.password=your-app-password
安全性增强建议
// 添加验证码防暴力破解
@Service
public class SecureVerificationService {
private static final int MAX_ATTEMPTS = 5;
/**
* 带尝试次数限制的验证
*/
public boolean verifyWithAttemptLimit(String email, String code) {
String attemptsKey = "email:attempts:" + email;
// 检查尝试次数
int attempts = getAttempts(attemptsKey);
if (attempts >= MAX_ATTEMPTS) {
throw new RuntimeException("验证次数过多,请重新获取验证码");
}
// 验证逻辑
boolean success = verifyCode(email, code);
if (!success) {
incrementAttempts(attemptsKey);
} else {
clearAttempts(attemptsKey);
}
return success;
}
}
使用Spring Boot后的接口版本
package com.example.email.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/email")
public class EmailVerificationController {
@Autowired
private EmailVerificationService verificationService;
@PostMapping("/send-code")
public ApiResult sendCode(@RequestParam String email) {
try {
verificationService.sendVerificationCode(email);
return ApiResult.success("验证码已发送");
} catch (Exception e) {
return ApiResult.error(e.getMessage());
}
}
@PostMapping("/verify")
public ApiResult verify(@RequestParam String email,
@RequestParam String code) {
boolean success = verificationService.verifyCode(email, code);
if (success) {
return ApiResult.success("验证成功");
}
return ApiResult.error("验证失败");
}
}
使用建议
- 验证码有效期:建议5-10分钟
- 发送频率限制:避免频繁发送
- 验证码长度:6位数字较为合适
- 使用HTTPS:传输安全
- 日志记录:记录发送和验证的日志
- 异常处理:做好各种异常情况的处理
这个案例提供了完整的邮箱验证功能,你可以根据实际需求调整配置和使用方式。