【保存版】Emailのバリデーションを考える上でのまとめ資料【ゆるい順: RFC→FW→サービス→Emailプラットフォーム】


## 結論

以下順番で使える記号のバリデーションがゆるい順です。
RFCに準拠するなら18個の記号に対応させないといけませんが、
実際にその記号はGmailなどに対応していないケースもあって、「なにに合わせるかは自社のサービスで決めてください」が一定の答えかなと思いました。Twitterに合わせるのがよさそうと有名サービスに迎合するのもよさそうでした。

| サービス | 対応（記号） |
| --- | --- |
| RFC | 18 |
| フレームワーク | 何種類かあるので適切に組み合わせて使うのがよさそう |
| Webサービス | 6 |
| あなたのサービス！ | RFCに準拠したら記号含めて自分で考えてね |
| Webメールサービス | 4 |


このまとめが100%よいとは限りませんが、結局なにがいいの？は議論余地あると思うので
ぜひ自分の思う最強のバリデーション正規表現をコメント欄とか新しい記事とか書いていただけると見てみたいです！


--------------

## 検討方法の列挙

- RFCに準拠する: Emailの仕様を決めている組織に従うべき論
- Webメールサービスに準拠する: 世の中のすべてのサービスのドキュメントを参考にする
- 有名なWebサービスに準拠する: Twitterのサインアップのバリデーションを検証する
- フレームワークに準拠する: php/Laravelを見てみる

## RFCに準拠する


> Request for Comments（リクエスト フォー コメンツ、略称：RFC）はIETF（Internet Engineering Task Force）による技術仕様の保存、公開形式である。内容には特に制限はないが、プロトコルやファイルフォーマットが主に扱われる。RFCとは「コメント募集」を意味する英語の略語であり、もともとは技術仕様を公開し、それについての意見を広く募集してより良いものにしていく観点から始められたようである。全てのRFCはインターネット上で公開されており、誰でも閲覧することができる。
> 
> https://ja.wikipedia.org/wiki/Request_for_Comments


- ここが詳しい [RFC 5322 & 5321に沿ったメールアドレス（local-part）に使える文字まとめ
 in Qiita](https://qiita.com/yoshitake_1201/items/40268332cd23f67c504c)

原点確認したい人は[このあたり](https://www.rfc-editor.org/info/rfc6854)みてほしい。
- RFC 6854
- RFC 5322
- RFC 7504
- RFC 5321
- RFC 1846

使える文字

```
! # $ % & ' * + - / = ? ^ _ ` { | } ~
```

## Webメールサービスに準拠する

何種類かサービスを見てみたがこのあたりが使えたら問題なさそう。

```
.
-
_
+
```

|  | 使える記号（半角英数字以外） | その他 | 資料URL |
| --- | --- | --- | --- |
| softbank | 「－」（ハイフン）、「．」（ドット）、「＿ 」（アンダーバー） | 「＠」直前の「．」（ドット）や「．」（ドット）の連続使用などもできません。<br>文字数は、3文字以上30文字以内<br>ひとつ目の文字は、アルファベットまたは数字のみ | https://www.softbank.jp/support/faq/view/10544 |
| docomo | 「_」（アンダーバー）、「.」（ピリオド）、「-」（ハイフン）の記号 | 3字以上30字まで設定することができます。<br>また、2009年4月1日以降、「.」は「..」などのように連続で使用することや@マークの直前で使用することはできなくなりました。<br>アドレス内に「..」や「.@」が存在する場合、一部のメールサービスからのメールが正しく届かない可能性がございます。<br>「スペース（空白）」は使用できません。<br>英字を入力する場合、大文字小文字の区別はありません。すべて小文字で表示されます。<br>先頭文字は英文字にしてください。 | https://www.nttdocomo.co.jp/info/spam_mail/change_add/ |
| au | 「-（ハイフン）」、「.（ピリオド／ドット）」、「_ （アンダーバー）」 | メールネーム文字数が、30文字まで利用可能です。<br>「.」をアドレス内での連続使用や「.」をEメールネームの最初/最後に使用することはできません。また最初に数字の「0」を使用することもできません。 | https://www.au.com/support/service/mobile/trouble/mail/email/change// |
| Gmail | ユーザー名: ピリオド（.）<br>エイリアス: プラス（+） | ユーザー名にはアンパサンド（＆）、等号（=）、アンダースコア（_）、アポストロフィ（'）、ダッシュ（-）、プラス記号（+）、カンマ（,）、山括弧（<>）、連続するピリオド（.）を使用することはできません。 | https://support.google.com/mail/answer/9211434?hl=ja |
| Yahoo!メール | 半角で “.”（ピリオド）、“-”（ハイフン）、“_”（アンダーバー）の3種類 | 設定できるメールアドレスは、プログラムの誤動作等を防ぐ目的で、RFCというインターネットにかかわるルール(RFC2822)や、インターネット上の慣例をもとにしたYahoo!ウェブホスティングの独自ルールを適用しております。 メールアドレスに使用できる文字列は以下のとおりです。<br><br> <br>アルファベット : 半角小文字でa～zまでの26文字<br>数字 :半角で0～9までの10字<br>記号 :半角で “.”（ピリオド）、“-”（ハイフン）、“_”（アンダーバー）の3種類<br> <br>禁止されている文字や記号<br>メールアドレスは上記の文字と記号を組み合わせて1字以上32字以内でご設定ください。なお、弊社独自ルールで以下のように設定しています。<br><br> <br>記号で始まるアドレスは不可<br>「.」「-」の連続使用は不可 | https://support.yahoo-net.jp/PccHostingupper/s/article/H000004944 |
| Outlook | ピリオド (.)、ハイフン (-)、下線 (_) | メール アドレスに使うことができる文字は、アルファベット、数字、ピリオド (.)、ハイフン (-)、または下線 (_) のみです。特殊な文字やアクセント記号は使うことができません。また、ラテン アルファベット以外のアルファベットも使うことができません。 | https://account.live.com/AddAssocId<br>(ドキュメントなし、エラーメッセージの文言で判断) |
| iCloud Mail | 不明 |  | ドキュメントなし |


## 有名なWebサービスに準拠する

Twitterのサインアップ画面で検証した
https://twitter.com/i/flow/signup

| email | valid | 意図 |
| --- | --- | --- |
| test@example.com | TRUE | 簡単な例 |
| test+-.._1@example.com | FALSE | ..の連続が弾かれるか |
| 0test+-._1@example.com | TRUE | 先頭の文字が英数字のとき |
| 0test++--.__1@example.com | TRUE | yahooで-_の連続使用できないので確認 |
| x!&x@example.com | TRUE | RFC準拠でWebメールサービスで使えない文字の検証（!&のみ使えた）<br>! # $ % & ' * + - / = ? ^ _ ` { | } ~ |

!& を使える設定しているのは意外でした。

## フレームワークに準拠する

Laravelのバリデーション

```
rfc: RFCValidation
strict: NoRFCWarningsValidation
dns: DNSCheckValidation
spoof: SpoofCheckValidation
filter: FilterEmailValidation
```

いろいろ組み合わせて適切なバリデーションを作れるようなってます

```php
'email' => 'email:rfc,dns'
```

こんな感じでバリデーションかけれます。
https://readouble.com/laravel/8.x/ja/validation.html


## 最後に

...の連続がX年からできなくなったとか、最初の文字が数値じゃだめとか色々決まりはありますが、
サービサーによって異なっていたり、バリデーションってゆるいところに合わせるのが正とは限らない気がしているので
最適ってなんだろうって調べてみておもいました。