- 一个推荐的、实用的正则表达式
- 完整的 Java 代码示例
- 对正则表达式的详细解释
- 内置的
javax.mail方法(更简单) - 正则表达式验证的局限性
推荐的实用正则表达式
一个既不过于严格(会拒绝合法邮件),也不过于宽松(会接受非法邮件)的正则表达式是最佳选择,这个正则表达式基于 RFC 5322 标准,但做了一些简化,足以应对 99.9% 的日常场景。

^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$
为什么推荐这个?
- 它允许常见的特殊字符,如 ,
&, , ,_。 - 它允许 出现在用户名和域名部分(但不能是第一个或最后一个,也不能连续)。
- 它强制要求顶级域名(如
.com,.org,.io)的长度在 2 到 7 个字符之间,这涵盖了所有现有的国家代码(.cn,.uk)和通用顶级域名(.com,.info)。
完整的 Java 代码示例
下面是一个完整的 Java 类,展示了如何使用上面的正则表达式来验证电子邮件。
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class EmailValidator {
// 预编译正则表达式,提高性能(如果这个方法会被频繁调用)
private static final String EMAIL_REGEX = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
private static final Pattern pattern = Pattern.compile(EMAIL_REGEX);
/**
* 验证电子邮件地址是否有效
* @param email 要验证的电子邮件字符串
* @return 如果有效则返回 true,否则返回 false
*/
public static boolean isValid(String email) {
// 如果输入为 null 或空字符串,直接返回 false
if (email == null || email.isEmpty()) {
return false;
}
Matcher matcher = pattern.matcher(email);
return matcher.matches();
}
public static void main(String[] args) {
// --- 测试用例 ---
String[] validEmails = {
"user@example.com",
"user.name@example.com",
"user-name@example.com",
"user_name@example.com",
"user+name@example.com",
"user@sub.domain.co.uk",
"user123@example.io",
"test.email+alias@example.com"
};
String[] invalidEmails = {
"plainaddress", // 缺少 @ 和域名
"@missing-local.com", // 缺少本地部分
"user@.com", // 域名以点开头
"user@domain.", // 域名以点结尾
"user..name@example.com", // 本地部分有连续的点
"user@domain.c", // 顶级域名太短
"user@domain.com.", // 顶级域名后有多余的点
"user@-example.com", // 域名部分以连字符开头
"user@example..com", // 域名部分有连续的点
"user@domain.12" // 顶级域名不是字母
};
System.out.println("--- 测试有效的电子邮件 ---");
for (String email : validEmails) {
System.out.printf("%-30s -> %b%n", email, isValid(email));
}
System.out.println("\n--- 测试无效的电子邮件 ---");
for (String email : invalidEmails) {
System.out.printf("%-30s -> %b%n", email, isValid(email));
}
}
}
代码解释:
EMAIL_REGEX: 定义了我们上面推荐的正则表达式字符串。Pattern.compile(): 这是一个性能优化。Pattern类代表一个编译后的正则表达式,将它编译一次并重用,比每次验证时都重新编译要高效得多,尤其是在循环或高频调用的场景下。pattern.matcher(email): 创建一个Matcher对象,该对象将使用编译好的模式去匹配输入的email字符串。matcher.matches(): 尝试将整个输入字符串与模式进行匹配,如果整个字符串完全匹配模式,则返回true,否则返回false,注意它和matcher.find()的区别,后者只查找子串的匹配。
正则表达式详解
让我们来分解这个正则表达式 ^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$:

| 部分 | 解释 |
|---|---|
^ |
匹配字符串的开始,确保模式从头开始匹配。 |
[a-zA-Z0-9_+&*-]+ |
本地部分 (Local Part) [...]: 定义一个字符集。 a-zA-Z: 任意大小写字母。 0-9: 任意数字。 _+&*-: 下划线、加号、与号、星号、连字符。 : 匹配前一个字符集 一次或多次。 |
(?:\\.[a-zA-Z0-9_+&*-]+)* |
本地部分的点号和后续字符 : 一个非捕获分组,用于将多个部分组合在一起,但不创建反向引用。 \\.: 匹配一个字面量的点号,在 Java 字符串中,反斜杠 \ 是转义字符,所以需要写成 \\ 来表示一个 \。 [a-zA-Z0-9_+&*-]+: 和上面一样的字符集,匹配一次或多次。 : 匹配前面的分组 零次或多次。 整体:这部分允许用户名中出现 , first.last。 |
| 匹配 "@" 符号,这是电子邮件地址的必需部分。 | |
(?:[a-zA-Z0-9-]+\\.)+ |
域名部分 (Domain Part) [a-zA-Z0-9-]+: 匹配一个或多个字母、数字或连字符(域名的标签)。 \\.: 匹配一个点号。 : 匹配前面的 分组 一次或多次。 整体:这会匹配类似 sub.domain. 这样的结构,确保至少有一个点。 |
[a-zA-Z]{2,7} |
顶级域名 [a-zA-Z]: 只能是字母。 {2,7}: 匹配前面的字符集 2 到 7 次,这覆盖了 .com, .org, .cn, .info, .technology 等。 |
| 匹配字符串的结束,确保模式匹配到字符串的末尾。 |
内置的 javax.mail 方法(更简单)
如果你的项目已经引入了 JavaMail API(在 Spring Boot 项目中通常作为依赖),你可以使用它内置的 InternetAddress 类来验证电子邮件格式,这种方法更可靠,因为它是由 JavaMail 专家维护的。
Maven 依赖:
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version> <!-- 使用最新稳定版本 -->
</dependency>
Java 代码:
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;
public class EmailValidatorWithJavaMail {
public static boolean isValid(String email) {
if (email == null || email.isEmpty()) {
return false;
}
boolean result = true;
try {
InternetAddress emailAddr = new InternetAddress(email);
emailAddr.validate(); // 如果地址无效,会抛出 AddressException
} catch (AddressException ex) {
result = false;
}
return result;
}
public static void main(String[] args) {
String email = "test@example.com";
System.out.println("Is '" + email + "' valid? " + isValid(email)); // true
String invalidEmail = "test@example";
System.out.println("Is '" + invalidEmail + "' valid? " + isValid(invalidEmail)); // false
}
}
优点:

- 更权威: 基于成熟的邮件处理库。
- 代码简洁: 只需几行代码。
缺点:
- 增加依赖: 需要引入
javax.mail库,对于一个非常简单的验证功能来说可能有些“重”。
正则表达式验证的局限性
最重要的一点:正则表达式可以验证电子邮件的 格式,但不能验证它是否 真实存在且有效。
nonexistent-user@this-domain-does-not-exist.com 会被上面的正则表达式判定为“有效”,因为它格式正确,但实际上这个邮箱地址可能并不存在。
要真正验证一个邮箱地址是否存在,唯一可靠的方法是:
- 发送一封验证邮件,邮件中包含一个验证链接。
- 用户点击链接后,才确认邮箱地址有效。
这是所有注册流程的标准做法。
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 自定义正则表达式 | - 无需外部依赖 - 高度可控,可根据需求调整 |
- 可能不够严谨,会漏掉或误判一些边缘情况 - 维护正则表达式本身有成本 |
项目中需要一个轻量级的、客户端或服务端的格式校验。 |
javax.mail |
- 权威、可靠 - 代码非常简洁 |
- 引入了外部依赖 | 项目中已经使用了 JavaMail API,或者需要一个比自定义正则更可靠的格式校验。 |
| 发送验证邮件 | - 唯一能验证邮箱真实存在的方法 | - 实现复杂 - 用户体验差(需要用户操作) |
用户注册、重要通知等必须确保邮箱真实有效的核心业务流程。 |
对于大多数后端 API 的请求参数校验,推荐使用自定义正则表达式,因为它轻量且足够,对于注册流程,必须结合发送验证邮件的机制。
