RFC 5322 完整郵箱規範極其複雜,實際項目常用簡化版平衡準確度與性能:
/**
* 簡易郵箱格式驗證
* 支援: user@domain.com, user.name@sub.domain.cn, user+tag@example.com
* 不支援: 引用字符串、IP 域名、註釋等極少見格式
*/
function isEmail(email) {
// 修正: 移除原文中過度複雜的 Unicode 正則,採用實用版
const pattern = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
return pattern.test(email);
}
// 使用
if (isEmail('user@example.com')) {
console.log('格式合法');
}
<form>
<input type="email" name="email" required>
<button type="submit">提交</button>
</form>
// 瀏覽器自動攔截非法格式,彈出本地化提示
<?php
/**
* 郵箱合法性驗證
* @param string $email
* @return bool
*/
function isEmail(string $email): bool {
// FILTER_VALIDATE_EMAIL 內置 RFC 兼容正則,支援國際化域名 (PHP 7.1+)
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
// 進階:同時檢查長度、域名 MX 記錄
function validateEmailDeep(string $email): array {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return ['valid' => false, 'reason' => 'format'];
}
if (strlen($email) > 254) { // RFC 5321 限制
return ['valid' => false, 'reason' => 'length'];
}
$domain = substr(strrchr($email, '@'), 1);
if (!checkdnsrr($domain, 'MX') && !checkdnsrr($domain, 'A')) {
return ['valid' => false, 'reason' => 'domain_not_exist'];
}
return ['valid' => true];
}
// 使用
var_dump(isEmail('test@example.com')); // true
var_dump(isEmail('invalid')); // false
var_dump(validateEmailDeep('test@fake.xyz')); // 可能 false (域名不存在)
| 維度 | JS 正則 | HTML5 type=email | PHP filter_var |
|---|---|---|---|
| 準確度 | 可控、可自定義 | 瀏覽器實現差異 | 高 (內置 RFC 正則) |
| 性能 | 極快 | 原生、極快 | 極快 (C 實現) |
| 國際化域名 | 需手動支援 | 現代瀏覽器支援 | PHP 7.1+ 原生支援 |
| 安全性 | 可繞過 (前端) | 可繞過 | 服務端、不可繞過 |
| 推薦策略 | 用戶體驗即時提示 | 基礎攔截 | 最終防線、必須執行 |
// 前端 (Vue 3 示例)
const email = ref('')
const emailError = computed(() => {
if (!email.value) return '請輸入郵箱'
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email.value)) return '格式不正確'
return ''
})
// 後端 (Laravel 驗證規則)
$request->validate([
'email' => 'required|email:rfc,dns|max:254|unique:users,email',
]);