メール形式チェックは「“それっぽい文字列”を早めにはじく」ための技
業務システムでは、ユーザーにメールアドレスを入力してもらう場面が山ほどあります。
ログインID、問い合わせフォーム、会員登録、通知先設定…。
ここでまったくチェックをしないと、
「あきらかにメールじゃない文字列」がDBに入り、
後でメール送信に失敗したり、バッチがコケたりします。
そこで使うのが「メール形式チェック」です。
これは「この文字列が“メールアドレスとしてあり得る形かどうか”をざっくり判定する」ためのユーティリティです。
完璧な判定ではなく、「明らかにおかしいものを早めにはじく」くらいのイメージで捉えるとちょうどいいです。
まずは「メールアドレスのざっくりルール」を知る
完璧を目指さず“実務で困らないライン”を決める
メールアドレスの正式な仕様(RFC)は、正直かなり複雑です。"name"@example.com のようにダブルクォートが使えたり、+ や . や _ など、いろんな記号が許されていたりします。
でも、実務でそこまで完璧に対応しようとすると、
正規表現が怪物みたいになって、誰も読めなくなります。
だから現場では、だいたい次のような「ざっくりルール」でチェックすることが多いです。
「@ が 1つだけ含まれている」
「@ の前後に 1文字以上ある」
「ドメイン部分に . が含まれていて、最後の . の後に 2文字以上ある」
これくらいでも、「明らかにおかしいもの」はかなり弾けます。
そして、これを正規表現に落とし込んだものが、よくある“実務用メール形式チェック”です。
シンプルなメール形式チェックユーティリティ
正規表現で「それっぽい形か」を判定する
まずは、実務でよく使うレベルのシンプルなチェックを書いてみます。
import java.util.regex.Pattern;
public final class EmailValidator {
private EmailValidator() {}
// かなりシンプルな「それっぽいメールアドレス」判定用パターン
private static final Pattern SIMPLE_EMAIL =
Pattern.compile("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$");
public static boolean isValid(String email) {
if (email == null) {
return false;
}
return SIMPLE_EMAIL.matcher(email).matches();
}
}
Java使い方はこうなります。
System.out.println(EmailValidator.isValid("taro@example.com")); // true
System.out.println(EmailValidator.isValid("taro.suzuki@example.co.jp")); // true
System.out.println(EmailValidator.isValid("taro@localhost")); // false(このルールではNG)
System.out.println(EmailValidator.isValid("taro@@example.com")); // false
System.out.println(EmailValidator.isValid("taro example@example.com")); // false(空白があるのでNG)
System.out.println(EmailValidator.isValid("taro@example")); // false
Javaここで重要なのは、正規表現の意味をちゃんと理解しておくことです。
^ と $ は「文字列の先頭」と「文字列の末尾」を表します。
これで「全体がこのパターンに一致していること」を保証します。
[^@\\s]+ は「@ と空白以外の文字が 1文字以上」という意味です。
これが @ の前と後にそれぞれ置かれているので、
「@ の前後に 1文字以上ある」「空白は含まない」という条件になります。
\\. は「ドットそのもの」です。
正規表現では . は「任意の1文字」という意味なので、
「ドットという文字」を表したいときは \\. とエスケープします。
つまりこのパターンは、
「空白なし」「@ は1つ」「@ の前後に1文字以上」「ドメイン部分に少なくとも1つドットがある」
という、かなり素直な条件を表しています。
もう少しだけ厳しめにするバージョン
ローカル部とドメイン部に“使える文字”を制限する
さっきのパターンは「@ と空白以外なら何でもOK」でした。
もう少しだけ厳しくして、「よくある文字だけ許可する」こともできます。
例えば、ローカル部(@ の前)は英数字と ._%+-、
ドメイン部(@ の後)は英数字と .-、
最後のドットの後は英字2文字以上、というルールにしてみます。
import java.util.regex.Pattern;
public final class EmailValidator {
private EmailValidator() {}
// よく見る「実務用」メールアドレスチェック
private static final Pattern COMMON_EMAIL =
Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
public static boolean isCommonValid(String email) {
if (email == null) {
return false;
}
return COMMON_EMAIL.matcher(email).matches();
}
}
Java使い方はこうです。
System.out.println(EmailValidator.isCommonValid("taro@example.com")); // true
System.out.println(EmailValidator.isCommonValid("taro.suzuki+test@example.co.jp")); // true
System.out.println(EmailValidator.isCommonValid("taro@sub-domain.example.com")); // true
System.out.println(EmailValidator.isCommonValid("taro@localhost")); // false
System.out.println(EmailValidator.isCommonValid("taro@例え.テスト")); // false(日本語ドメインはこのルールではNG)
System.out.println(EmailValidator.isCommonValid("taro@@example.com")); // false
System.out.println(EmailValidator.isCommonValid("taro example@example.com"));// false
Javaここで深掘りしたいポイントは二つです。
一つ目は、「この正規表現は“仕様的に完全ではない”が、“現場でよく使われる妥協ライン”」だということです。
日本語ドメインや、RFC的にはOKな特殊なアドレスは弾いてしまいますが、
その代わり、パターンがまだギリギリ読めるレベルに収まっています。
二つ目は、「用途によってパターンを使い分ける」という発想です。
社内システムで、ほぼ英数字だけのメールアドレスしか使わないなら、このくらいで十分です。
一方で、グローバル向けサービスで、あらゆる形式のメールアドレスを受け入れたいなら、
もっと柔軟なライブラリやバリデーションを検討する必要があります。
「形式チェック」と「実在チェック」は別物だと理解する
メール形式チェックユーティリティがやっているのは、
あくまで「文字列の形がそれっぽいかどうか」の判定だけです。
taro@example.com が「本当に存在するアドレスかどうか」は、
形式チェックだけでは絶対に分かりません。
実在チェックをしたいなら、
実際にメールを送って、ユーザーに確認リンクを踏んでもらう、
いわゆる「メールアドレス認証」の仕組みが必要になります。
ここで大事なのは、
「形式チェックは“明らかにおかしいものを弾くフィルタ”であって、
“正しいことの保証”ではない」
という感覚を持っておくことです。
例題:入力フォームでのメール形式チェック
ユーザー登録フォームで、メールアドレスを入力してもらう場面を考えます。
サーバ側では、こんな感じで使えます。
String email = request.getParameter("email");
if (email == null || email.isBlank()) {
errors.add("メールアドレスを入力してください。");
} else if (!EmailValidator.isCommonValid(email)) {
errors.add("メールアドレスの形式が正しくありません。");
}
Javaここでのポイントは二つです。
一つ目は、「null や空文字のチェック」と「形式チェック」を分けていることです。
「未入力」と「形式が変」は、ユーザーに伝えるメッセージも違うので、
条件も別々に書いたほうが親切です。
二つ目は、「形式チェックは“サーバ側で必ずやる”」ということです。
フロント側でJavaScriptバリデーションをしていても、
悪意あるユーザーはそれを無効化してリクエストを送ってきます。
サーバ側のチェックが最終防衛ラインだと考えてください。
まとめ:メール形式チェックユーティリティで身につけたい感覚
メール形式チェックは、「完璧な判定」を目指すものではなく、
「明らかにおかしいものを早めにはじくためのフィルタ」です。
まずは、^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$ のようなシンプルなパターンから始めて、
「@ が1つ」「前後に文字がある」「ドメインにドットがある」といった最低限のルールをコードに落とし込んでみてください。
そのうえで、必要に応じて
「使える文字を絞ったパターン(COMMON_EMAIL)」にするのか、
「ライブラリ(Apache Commons Validator など)に任せる」のかを選んでいく。
もしあなたのコードのどこかに、
メールアドレスを「文字列としてそのまま受け取って、そのままDBに入れている」箇所があれば、
そこを題材にして、ここで作った EmailValidator.isValid や isCommonValid を一度挟んでみてください。
それだけで、「明らかにおかしいメールアドレスがシステムに入り込む」リスクを、かなり減らすことができます。
