Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

メールアドレスのバリデーション方法

じゃぁメールアドレスのバリデーションってどうやったらいいのさ、という話。

satob.hatenablog.com

もちろんバリデーションをした後には、メールアドレスの実在性確認のために実際にメールを送信します*1。その前段で、画面に表示したときにセキュリティ的にもレイアウト的に問題ない(ように見える)メールアドレスだけ使えるようにしておきたい。

JavaMailだけではガバガバで、Outlookのアドレス帳から取ってきたような "John Due" <john.doe@example.com> みたいなアドレスも通してしまう。これをそのまま画面表示用に使うのはさすがにマズそうなので(rtlとかltrとか入れ放題になると思う)、 john.doe@example.com の部分だけ使いたいわけです。

じゃぁJavaMailで InternetAddress#getAddress() すればアドレス部分だけ取れるからそれでよいのでは、と考えてしまうのだけれど、それもマズい。JavaMailはdomain-literal(john.doe@[203.0.113.1] みたいなやつ)を通してしまいます。domain-literalは、扱えないMUAやMTAが多いので避けたい。

こう考えると、JavaMailだけでバリデーションするのは筋が悪そうです。

一方、HTML Living Standardの正規表現は「RFC 5322にあえて準拠していないところがあるよ」と言っていますが、上記の観点から見るとそれほど悪くありません。HTML Living Standardをパスするアドレスで、JavaMailがエラーとなるものは、ローカルアドレス部分のlocal-partの先頭・末尾にドットがある場合と、連続するドットがある場合だけ *2 です。

なので、以下のようにするのがよいのではないでしょうか。

  • (A) メールを送信するMTAまで自前で制御可能で、携帯電話のキャリアメールのアドレスを利用可能にしておきたい場合はHTML Living Standardの正規表現でチェックする
  • (B) メール送信に外部のサービスを使うなどの理由で、不正なメールアドレスはトラブルの元になるから利用できなくしておきたい場合は、HTML Living Standardの正規表現とJavaMailの両方でチェックする
  • (A)(B)いずれの場合も InternetAddress#getAddress() を使う必要はなく、入力された文字列をそのままメールアドレスとして使う

*1:それ以外にアドレスの打ち間違いを検知する方法はないため

*2:MTAやMUAによっては不正なアドレスと判定される。昔の携帯電話のキャリアメールだと該当する場合がある。 https://www.rbbtoday.com/article/2009/04/03/59059.html