alltools.one
Development
2025-06-15
7 min
alltools.one Team
RegexEmailValidationJavaScriptDevelopment

用 Regex 驗證電子郵件:真正有效的模式

電子郵件驗證是最常見的 regex 使用案例之一——也是最被誤解的之一。RFC 5321 對電子郵件地址的規範出人意料地複雜,沒有任何單一 regex 能完全驗證它。但能涵蓋 99.9% 真實電子郵件地址的實用模式既可行又實用。

簡單模式(夠用了)

對大多數應用來說,以下模式就能勝任:

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

它匹配什麼:一個或多個允許的字元,接著 @,再接著至少有一個點號和 2 個以上字母 TLD 的網域。

JavaScript:

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
emailRegex.test('user@example.com');  // true
emailRegex.test('user@.com');          // false

使用我們的 Regex 測試器來測試這個模式。

為什麼完美的 Regex 驗證不可能

電子郵件規範(RFC 5321/5322)允許一些在技術上有效但幾乎不會在實務中使用的結構:

"john..doe"@example.com           // Quoted local part with consecutive dots
user@[192.168.1.1]                // IP address as domain
"very.(),:;<>[]".VERY."very@\ "very".unusual"@strange.example.com

能處理所有 RFC 有效地址的 regex 長達數千個字元,而且仍可能無法涵蓋每種邊緣情況。實用的做法是:使用簡單的 regex 進行基本格式驗證,然後透過發送確認信來驗證電子郵件地址是否真正存在。

模式分解

本地部分(@ 之前)

[a-zA-Z0-9._%+-]+
  • 字母(大小寫)
  • 數字
  • 點號、底線、百分號、加號、連字號
  • 一個或多個字元

常見錯誤

  • 允許點號出現在開頭或結尾(技術上無效)
  • 允許連續的點號(未加引號時技術上無效)
  • 過於嚴格(阻擋了 Gmail 別名使用的 + 等有效字元)

網域部分(@ 之後)

[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
  • 英數字元、點號、連字號
  • 至少一個點號
  • 2 個以上字母的 TLD

常見錯誤

  • 將 TLD 長度限制為 3-4 個字元(.museum.photography 是存在的)
  • 不允許網域名稱中的連字號
  • 無法處理子網域(user@mail.example.co.uk

更好的模式

HTML5 標準

HTML5 規範為 <input type="email"> 定義了以下模式:

^[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])?)*$

這個模式在本地部分較為寬鬆,但對網域標籤長度更為嚴格。

實用推薦模式

^[^\s@]+@[^\s@]+\.[^\s@]{2,}$

這個最精簡的模式只確保:沒有空格、一個 @@ 之後至少一個點號、2 個以上字元的 TLD。它故意設計得較為寬鬆——攔截明顯錯誤的輸入,而不會拒絕不常見但有效的地址。

各語言實作

JavaScript

function isValidEmail(email) {
  // Basic regex check
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
  if (!regex.test(email)) return false;
  
  // Additional checks
  if (email.length > 254) return false;  // RFC 5321 limit
  const [local] = email.split('@');
  if (local.length > 64) return false;   // RFC 5321 limit
  
  return true;
}

Python

import re

def is_valid_email(email: str) -> bool:
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(pattern, email):
        return False
    if len(email) > 254:
        return False
    local, domain = email.rsplit('@', 1)
    if len(local) > 64:
        return False
    return True

超越 Regex:正確的電子郵件驗證

Regex 只是第一道防線。完整的驗證策略:

  1. 格式檢查(regex):拒絕明顯無效的格式
  2. 長度檢查:本地部分 ≤ 64 字元,總長度 ≤ 254 字元
  3. DNS 檢查:驗證網域是否有 MX 記錄
  4. 拋棄式信箱偵測:如需要,阻擋臨時電子郵件服務
  5. 確認信:真正驗證電子郵件的唯一方法——寄出一封信並確認使用者收到了
// DNS MX record check (Node.js)
const dns = require('dns');
const [, domain] = email.split('@');
dns.resolveMx(domain, (err, addresses) => {
  if (err || !addresses.length) {
    console.log('Domain has no email server');
  }
});

應避免的常見錯誤

  1. 過於嚴格的模式:阻擋 user+tag@gmail.com(加號定址)或 user@subdomain.example.com
  2. 大小寫敏感性:根據 RFC,電子郵件本地部分可以區分大小寫,但實務上應視為不區分大小寫
  3. 去除空白:驗證前務必去除空白——" user@example.com " 應該通過驗證
  4. 國際化網域.münchen用户@例え.jp 在國際化電子郵件中是有效的

更多 regex 模式,請參閱我們的 Regex 速查表

常見問題

應該在客戶端還是伺服器端用 regex 驗證電子郵件?

兩者都要。客戶端驗證提供即時回饋(更好的使用者體驗)。伺服器端驗證是安全性的必要措施(客戶端檢查可以被繞過)。永遠不要只依賴客戶端驗證。

為什麼有些網站會拒絕我有效的電子郵件地址?

通常是過於嚴格的 regex 模式造成的。含有 +(Gmail 別名)、長 TLD(.technology)或子網域的地址經常被拙劣的驗證所拒絕。如果你維護一個網站,請使用寬鬆的 regex,並透過確認信來驗證。

相關資源

Published on 2025-06-15
Regex for Email Validation: Patterns That Actually Work | alltools.one