「メールアドレス判定」はどこまでやるべきか
最初に一番大事なことを言います。
メールアドレス判定は「完璧」を目指さないほうがいいです。
RFC に完全準拠しようとすると、正規表現が怪物みたいになりますし、
現場で本当に欲しいのは「明らかにおかしいものを弾く」くらいの精度です。
なので、業務ユーティリティとしては、
「パッと見てメールアドレスっぽいか」
「致命的におかしい形式を弾けるか」
このあたりを狙うのがちょうどいいラインです。
まずは「メールアドレスのざっくり構造」を押さえる
メールアドレスは、ざっくりこういう形をしています。
ユーザー名部分 @ ドメイン部分
例としては、
taro@example.comhanako.sato+news@gmail.com
などですね。
ざっくりチェックしたいポイントはこのあたりです。
@ が1個だけあること。@ の前後に、最低1文字ずつあること。
ドメイン部分に . が含まれていること(example.com など)。
これだけでも、「明らかにおかしいもの」はかなり弾けます。
シンプルなメールアドレス判定ユーティリティ
実務でよく使うレベルの正規表現
まずは、業務で使いやすい「ほどよい」正規表現からいきます。
function isEmail(value) {
if (value == null) return false;
const s = String(value).trim();
if (s === "") return false;
const re =
/^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(s);
}
JavaScript一つずつ噛み砕きます。
null / undefined が来ても落ちないようにしている。String(value).trim() で文字列化+前後の空白を削っている。
空文字は false(メールアドレスではない)にしている。
正規表現は /^[^\s@]+@[^\s@]+\.[^\s@]+$/ という、かなりシンプルなものにしている。
この正規表現の意味はこうです。
^ … 文字列の先頭[^\s@]+ … 空白と @ 以外の文字が1文字以上(ユーザー名部分)@ … @ が1個[^\s@]+ … 空白と @ 以外の文字が1文字以上(ドメインの前半)\. … ドット1個[^\s@]+ … 空白と @ 以外の文字が1文字以上(ドメインの後半)$ … 文字列の末尾
つまり、「@ が1個あって、その前後にそれなりの文字があって、ドメインに . が含まれている」ものだけを許可します。
動きの確認
isEmail("taro@example.com"); // true
isEmail("hanako.sato+news@gmail.com"); // true
isEmail("invalid@@example.com"); // false
isEmail("no-at-mark.example.com"); // false
isEmail("taro@localhost"); // false(ドメインに . がない)
isEmail(" taro@example.com "); // true(前後の空白は無視)
JavaScript「完璧ではないけれど、明らかにおかしいものは弾けている」感じがつかめると思います。
どこまで厳しくするかを決める
ローカル用途か、外部ユーザー向けか
例えば、社内ツールで「社内メールアドレスだけ」を扱うなら、
もっと絞った判定にしても構いません。
function isCompanyEmail(value) {
if (!isEmail(value)) return false;
return String(value).trim().toLowerCase().endsWith("@example.co.jp");
}
JavaScriptこれなら、
taro@example.co.jp は OKtaro@gmail.com は NG
といった判定ができます。
逆に、一般ユーザー向けサービスなら、
「とりあえず形式だけざっくり見て、あとは確認メールを送って検証する」
という設計にするのが現実的です。
「正規表現だけで完璧に判定しようとしない」
メールアドレスが本当に存在するかどうかは、
正規表現では絶対に分かりません。
最終的には、
そのアドレスにメールを送る。
ユーザーに確認リンクを踏んでもらう。
といった「実際の通信」を伴う確認が必要です。
だからこそ、ユーティリティの役割は
「明らかにおかしい形式を弾く」
「入力ミスっぽいものを早めに気づかせる」
くらいにとどめておくのが、バランスの良い落としどころです。
業務での具体的な使いどころ
フロントエンドの入力チェック
フォームの入力チェックで、
「送信ボタンを押す前に、明らかにおかしいメールアドレスを教えてあげる」用途です。
const email = emailInput.value;
if (!isEmail(email)) {
showError("メールアドレスの形式が正しくありません。");
}
JavaScriptここでのポイントは、
「形式が正しいからといって、必ず存在するとは限らない」
「形式が少し変でも、実際には有効なアドレスの可能性もある」
ということを理解したうえで、
「ユーザーの入力ミスを減らすためのガイド」として使うことです。
バックエンド側の軽いバリデーション
API でメールアドレスを受け取るときにも、
最低限の形式チェックをしておくと、
明らかにおかしいデータが DB に入るのを防げます。
function validateEmailOrThrow(email) {
if (!isEmail(email)) {
throw new Error("Invalid email format");
}
}
JavaScriptただし、ここでも「存在確認」は別のレイヤー(確認メールなど)でやる、という意識が大事です。
設計として意識してほしいこと
「メールアドレス判定ユーティリティ」を一箇所にまとめる
プロジェクトのあちこちで、
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
JavaScriptのような正規表現がコピペされ始めると、
どこか一箇所だけ微妙に違うルールになったり、
後から仕様変更するときに地獄を見ます。
なので、
export function isEmail(value) { ... }
export function isCompanyEmail(value) { ... }
JavaScriptのように、「メールアドレス判定は必ずここを通す」というユーティリティを一つ決めておくと、
コードの一貫性と保守性が一気に上がります。
「判定の責任範囲」を決める
このユーティリティは、
「形式が“それっぽい”かどうか」を見るだけなのか。
「自社ドメインかどうか」まで見るのか。
など、「どこまで責任を持つか」を決めておくと、
関数名や使い方もブレなくなります。
例えば、
isEmail … 形式だけざっくりチェックisCompanyEmail … 形式+ドメインチェック
のように分けておくと、
呼び出し側も意図を読み取りやすくなります。
ちょっとだけ手を動かしてみる
コンソールで、次のあたりを試してみてください。
isEmail("taro@example.com");
isEmail("hanako.sato+news@gmail.com");
isEmail("invalid@@example.com");
isEmail("no-at-mark.example.com");
isEmail("taro@localhost");
JavaScript「どこからが true で、どこからが false になるか」を体で感じてみてください。
そのうえで、自分のプロジェクトに
export function isEmail(value) { ... }
JavaScriptを一つ置いて、
「メールアドレスっぽいかどうかを見たいときは、必ずここを通す」
というルールにしてみてください。
それができた瞬間、あなたのバリデーションは
「その場しのぎの正規表現の寄せ集め」から
「意図を持って設計された検証ユーティリティ」に、一段レベルアップします。

