📩
君はメールアドレスの正規表現を適当にググって使っていないか?
もう、そういうのは卒業しよう。
今日からメールアドレスのバリデーションの正規表現は
/^[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])?)*$/
だ。いいね?
なぜこの正規表現がいいのか
ちなみにこれの何がいいかというと
「HTMLの標準仕様を定めるWHATWGの正規表現をそのまま使っている」ところ。
つまり、各ブラウザのデフォルトの<input type="email" />
のバリデーションと一致するという大きなメリットを得られる。
これはMDNにも載っている列記とした「実用的な」正規表現だ。
ちなみにRFCオタクがRFC準拠のおおよそ実用に耐えないであろうメールアドレスの正規表現を推してくるかもしれないが無視して良い。
例えば、RFCに準拠している以下のようなメールアドレスを君のシステムで許容したいと思うだろうか?
"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com
ちなみにRubyだとURI::MailTo::EMAIL_REGEXP
で、WHATWGの正規表現とほぼ同じ正規表現にアクセスできる。
> ruby -r uri -e 'puts URI::MailTo::EMAIL_REGEXP'
(?-mix:\A[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])?)*\z)
言語側のライブラリーで用意されている正規表現を使うのが最も安全で楽だね。
まとめ
メールアドレスのバリデーションには、WHATWGの標準の正規表現を使うことをお勧めする。
/^[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])?)*$/
これを使うメリットは:
- ブラウザの
<input type="email" />
のバリデーションと一致する - 実用的な範囲でメールアドレスを検証できる
- 信頼できるHTMLの標準に基づいている
適当にググって見つけた情報を使うだけでは、いつまで経っても初心者から抜け出せない。
標準に基づいた実装を選ぶことで、より確信を持ってシステムを作ることができる。
とにかく、メールアドレスのバリデーションという枯れた分野で適当にググった正規表現を使うのは卒業しよう。
Discussion
私の見解としてメールアドレスは正規表現で検証するべきではないと考えています。
メールアドレスを最も確実に検証する方法は、実際にメールを送信することです。
メールアドレスの構文の問題よりも長さ制限のほうが重要ではないでしょうか?
RFCにはメールアドレスの長さ制限が記載されています。ローカル部は64オクテット、ドメイン部は255オクテットで、@を含めて320文字(ASCII文字)になるべきです。しかし、320文字のメールアドレスは送信できません。SMTP(RFC 2821)の仕様によれば、
とあり、ブラケットを含む関係上、実質的には254文字に制限されます。つまり長さ制約も検証する必要があるはずです。
これを超える以下のメールアドレスは、冒頭の正規表現を通過しますが、送信不可能な場合があります。少なくとも厳格なRFCに準拠していれば拒否されるはずです。
下に正規表現をバイパスするメールアドレスを示してみます。
264文字あります。SMTP仕様に合致しないもののRFC準拠で正規表現に合致します。
上のアドレスはGmailとOutlookで送信こそ可能なものの ProtonMail は受信をメールアドレスが無効として拒否しました。Tutaも送信を試みましたが拒みました。
この例から、メールアドレスの正規表現がどれほど信頼できないかがわかると思います。あなたの正規表現よりも厳しい制約を課すプロバイダーを利用している場合送信できないケースがありあります。
なのでメールアドレスの検証は送信しない限りわかりません。
なぜ無視して良いのでしょうか。RFC 準拠のメールアドレスの正規表現が実用的ではないからですか?
それは WHATWG 信者であれば、の話ですよね。
WHATWG が定める
<input type="email">
のバリデーションが気に食わない人は以前から一定数いるという認識です。https://github.com/whatwg/html/issues/1465HTML 仕様のメールアドレス正規表現に最小限の修正を加えるという記事もあるようです。
MDN に載っていれば実用的なのかというのも疑問があります。
確かに、「適当」にググった二次情報のブログ記事の正規表現を何の考えもなしに流用するような人は初心者から抜け出せないでしょうね。
ただし、WHATWG が定めたバリデーションが絶対的に良いかというのも疑問です。
私は
"><script>alert('or/**/1=1#')</script>"@example.jp
のようなメールアドレスも受け付けるサービスの方が望ましいと思っています。これを弾く理由が合理的でないからです。そのため、私はしばしば、次のような正規表現を用いてメールアドレスをバリデーションしています。
このシンプルな正規表現よりも、WHATWG の定める正規表現を使うべき理由が見当たりません。
そもそも、これってどのレイヤーでの話なのでしょうか。
JavaScript の文脈であれば、そもそも正規表現を使わずに
<input type="email">
に対する checkValidity メソッドでバリデーションすべきという話もある気がしています。総括として、独自のクソみたいな正規表現によるバリデーションを掛けるなという主張であれば同意です。
記事の正規表現だと
example@gmailcom
のようなドット漏れのメールアドレスも
true
判定になるので実用的なバリデーションではないですね。
以下のシンプルな正規表現ならドット漏れは
false
になるので私もこちらの正規表現をメールアドレスの判定によく使用しています。