📨

メールアドレスの混沌 FILTER_VALIDATE_EMAILには気をつけろ!

2022/07/23に公開

今日は、メールに異常な執着のあるmipsparcより、メールアドレスバリデーションは一筋縄には行かないという話をしたいと思います。今回は特に私が業務で使っていて知見のあるPHPを主題にして解説していきますが、他の言語でも有用な知見かと思います。

rfc_fully_compat.php
if (filter_var($mail_address, FILTER_VALIDATE_EMAIL)) {
     return true
} else {
     return false
}

上のPHPコード「のみ」で判定しているサービスは、いますぐそれをやめましょう。

理由

時代はさかのぼり、牧歌的インターネットの時代。なりすましメールなど考えることもなく、インターネットに接続できる限られた研究者同士がメールを送り合っていた時代です。そんなときに策定されたのが、 RFC724[1] です。これは現在(執筆時点)最新のメールアドレスなどについて定めたRFC5322(Internet Message Format)の遠い祖先で、1977年に制定されています。端的に言うと、これの「負債」が今に残っていると考えるとわかりやすいです。

その結果、以下のようなメールアドレスはRFC上有効ということになっています。

"very.(),:;<>[]".VERY."very@\ "very".unusual"@[IPv6:::1][2]

これはquoted-string(クオート内はかなり自由度が高く、@を内包することすらできる)とIPアドレスの直接指定(もちろんIPv4/IPv6に対応しています)の合わせ技のゲテモノですが、FILTER_VALIDATE_EMAILでは有効とみなされます。

php.netによると、

In general, this validates e-mail addresses against the addr-specsyntax in » RFC 822, with the exceptions that comments and whitespace folding and dotless domain names are not supported.

とのことなので、RFC822にほぼ準拠した判定をしているということです。

実際には、普通の人は上記文字列をメールアドレスだとは思いませんし、扱えるSMTP-senderも受領できるSMTP-receiverもほとんどないでしょう。

具体的リスク

実際には送信できない(bounceする)メールアドレスをメールデータベースに保持することは、リスクです。正しくバウンス管理していればいいのですが、何度もbounceするようなメールを送ってくるドメインは、メールリストの管理ができていないとみなされ、受信者のレピュテーション(迷惑メール送信者であるかの評価値)が低下していきます。

また、最近ではメール配信代行サービス(SendGrid, MailGun, MailChimpなど)を使うことも多いかと思いますが、そこで実際には送れないメールアドレスであるとエラーが返されることもあるので、エラーハンドリングなどに注意が必要です。

結論

2017年のStack Over Flowの 回答[3] によると、WebKitでinput type="email"した場合の正規表現はこちらです
[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*
これは現実的なメールアドレスのみが許容されます。
実際のところ、FILTER_VALIDATE_EMAILでRFC違反の厳しいチェック(ドットが連続しないなど)をしたうえで、上記やMDNに記載された正規表現により検証するのが無難かと思われます。メールアドレスと正規表現は相性が悪いとよく言われますが、こればかりは仕方がないのではないでしょうか。

ちなみに

あまり知られていないですが、
RFC5321 2.4によると、
The local-part of a mailbox MUST BE treated as case sensitive.
だそうなので、メールアドレスのlocal-partは大文字と小文字を厳密に区別しなければなりません。
なので、strtolower($mail_address)なんて 絶対に してはいけませんよ!

最後に

メールはGmailやGWSでポチ―と押せば送れるし、SendGridやSESを使えば何千万通も一気に送れますが、「メールをナメるな!」と大声で叫びたいです。(私怨)

以上、知見になれば幸いです。メールはSimpleなんかじゃありませんよ!!!!

脚注
  1. https://www.rfc-editor.org/rfc/rfc724.txt ↩︎

  2. https://en.wikipedia.org/wiki/Email_address#Examples ↩︎

  3. https://stackoverflow.com/questions/7786058/find-the-regex-used-by-html5-forms-for-validation ↩︎

Discussion