定期的に繰り返される話題ですがまた盛り上がっているのできちんと書いておきます。
「通るべきメールアドレスが弾かれると激おこ」という前提で話を進めます。
問題点1. メールアドレスに関して、RFCなんてそもそも守られていない
2009年以前に登録されたDoCoMo携帯のメールアドレスなど、quoted-stringじゃないのにピリオド連続するものが実在している以上、彼らを許容するべきです。
今そこにある実装 >>(越えられない壁)>> RFC です。
問題点2. メールアドレスの国際化
@の左側(addr-spec)でUTF-8を利用できるようにするRFC5335が発行されています。これにより、通すべき文字が一気に増えます。
通常、電子メールアドレスは「ユーザー名@ドメイン名」という形式で表されます。そのうち、@の右側の「ドメイン名」の国際化については、国際化ドメイン名(IDN)として、既に標準規格が定められています。今回の国際化電子メールアドレスは、@の左側の「ローカルパート」と呼ばれる部分も含んだメールアドレス全体の国際化を行い、電子メールアドレスの任意の部分に、日本語を含むさまざまな言語の文字を使用可能にするための技術です。
また、そもそもドメイン部はとっくに国際化されています。こちらはPunycodeでデコードされた「xn--***.jp」というドメインを使えばいいわけですが、真にユーザーの利便性を考えるなら国際化ドメインを直接入力できるべきでしょうね。ははは。
結局のところ「メールアドレスのルール」というのが現実としてどんどん変わっていく以上、これを元にバリデーションを掛けるのは人類にはまだ早すぎます。
問題点3. そもそも役に立たない
で、そんな厳しくバリデーションしたところで、「メールアドレスのルール」を逸脱しない範囲での打ち間違えの方が多いです(例: foobar@example.jpo)。
TLDのホワイトリストなんて新gTLDがぽこぽこ量産される時代に持っちゃいけません。
解決策: じゃあどうすればいいの
推奨: 実際にメールを送る
これが一番早いです。余程偏った利用者層でない限り、メール内のURLクリックというインターフェースにユーザーも慣れています。
ちなみに本件とは別ですが、メールアドレスの打ち間違えで別の人に届くリスクがあるので、メール内のURLクリック後に無条件にログイン状態にしてしまうと危険だったりします。
消極策: いわゆる「普通に使えるべき記号」までを許容する
「"」でくるむquoted-stringなんて使っている人ほとんど居ないのでその部分は忘れ、普通に使う事ができる記号「!#$%&'*+-/=?^_`{|}~.」は受け取るようにします。
これでほとんどの人が救済される上、バリデーション部分の正規表現の変更のみと変更コストが最も低いです。ただ、当然ながらRFCに準拠して作られたマニアックなメールアドレスは受け取れません。
頑張って理想のバリデーションを実装する
上にも書いたとおり仕様や現実が変わっていく以上大変ですが、それに見あう効果があるかというと自分は見あわないと思います。
とはいえ、技術的トライアルとしては楽しそうなので、だれかやってください(他力本願)。
DNSを引く
メールは送りたくないが、せめてドメイン部は、という事であればDNSのMXレコードとAレコードを引きましょう。
当然ながら、@の左側の打ち間違えには無力ですし、フィッシング用の偽ドメインが存在してしまう場合もあります。
非推奨: SMTPで接続してRCPTまでやってみる
実際にDNSを引いて調べた相手先メールサーバにSMTPで接続し、RCPTコマンドを送るところまでやってみることで、存在しないユーザーであればエラーを返してくれる場合が多いです。
ですが、DNSを引くのに比べてずっと時間が掛かるのでウェブアプリの1リクエスト中では厳しくなります。
昨今では、エラーを返さず受け取るだけ受け取って迷惑メール事業者フラグを立てるという実装もありそうな気がしますし、そもそも相手のメールサーバにメールを送らないのに無駄に接続する以上、負荷を掛ける行為にもなりかねません。
というわけで、理論上はできそうと言うだけで、やらない方が良いでしょう。非推奨ということで敢えて入れました。
まとめ
メールアドレスの確認はそこにメールを送る事で確認を行いましょう。
入力フォーム段階でのバリデーションは、フィールドの入れ間違い等への対策として「@」や「.」を含むどうか程度に留めべきです。
補足: 重要なのは「その仕様で誰が得をするか」をよく考えましょうってことです。どうしてもバリデーションだけで頑張りたいのであれば、""なしで使える記号を許容すると、対応が楽な割に救済される人が一気に増えます。逆に、絶対に厳密な入力制限が必要な場合は、死ぬ気で頑張るしかないでしょう。