メールアドレスの入力チェックには、「@の前に使える文字が1文字以上、@の後にドットで区切られたドメイン」という形を確かめる、ほどほどに緩い正規表現を使うのが実務の定番です。メールアドレスの仕様(RFC)は非常に複雑で、それを完全に再現する正規表現は現実的ではないうえ、厳しくしすぎると実在するアドレスを拒否してしまうからです。

そして、正規表現で確認できるのは「形式」だけです。そのアドレスが実在し、本人が受け取れるかは、確認メールを送らなければわかりません。この記事では、実用的な正規表現のパターンと、言語別の書き方、文字数の上限、日本特有の古い携帯のアドレス、処理が止まる危険な正規表現まで、実際に動かした結果とあわせて解説します。

まずは結論:実用パターン

パターン1:実用的なチェック(おすすめ)

^[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,}$
部分 意味
^[A-Za-z0-9._%+-]+ @の前(ローカル部):英数字と . _ % + - が1文字以上
@ @がちょうど1つ
(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+ ドメインの各部分:英数字で始まり英数字で終わる(途中はハイフン可)、最大63文字、後ろにドット
[A-Za-z]{2,}$ 最後の部分(.com、.jp など):英字2文字以上

パターン2:HTML5の入力欄と同じ基準

<input type="email"> がブラウザで使っている基準(HTMLの仕様で定められたもの)と同じパターンです。

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

画面側(HTML5の入力欄)とサーバー側で、同じ基準でチェックしたい場合に使います。ただし、user@localhost のようにドット(.com など)のないアドレスも通す点に注意します。

2つのパターンの判定結果

Pythonで実際に判定した結果です。

入力 パターン1(実用) パターン2(HTML5)
user@example.com ○ ○
user+tag@example.co.jp ○ ○
abc..def@docomo.ne.jp ○ ○
abc.@docomo.ne.jp ○ ○
user@localhost × ○
user@example × ○
user@-example.com × ×
user@@example.com × ×
user @example.com(空白) × ×
ユーザー@example.com × ×
user@例え.jp(日本語ドメイン) × ×

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「メールアドレスの正規表現|実用パターンとチェックの注意点」

言語別の書き方

どの言語でも、文字列全体が一致することを確かめる書き方を使います(後述の「末尾の改行」の問題を避けるため)。

JavaScript

const EMAIL = /^[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,}$/;

EMAIL.test("user@example.com");     // true
EMAIL.test("user@-example.com");    // false

ブラウザの入力欄なら、<input type="email" required> だけでも、HTML5の基準でのチェックができます。

Python

import re

EMAIL = re.compile(r"[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,}")

bool(EMAIL.fullmatch("user@example.com"))     # True
bool(EMAIL.fullmatch("user@example.com\n"))   # False

Pythonでは re.match と ^...$ の組み合わせだと、末尾に改行があっても一致してしまいます。実際に試すと、re.match(r"^...$", "user@example.com\n") は一致しました。re.fullmatch を使うのが確実です。

Java

private static final Pattern EMAIL = Pattern.compile(
    "[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,}");

EMAIL.matcher("user@example.com").matches();   // true(matchesは全体一致)

Javaの文字列の中では、\. を \\. と書く必要があります。Bean Validationを使っている場合は、@Email アノテーションも利用できます。

PHP

$pattern = '/\A[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,}\z/';
preg_match($pattern, 'user@example.com');   // 1

PHPでは、標準の filter_var($email, FILTER_VALIDATE_EMAIL) も使えます。ただし、実際に試すと、abc..def@docomo.ne.jp のような古い携帯のアドレスは不合格になりました。日本の利用者を想定する場合は、この点を考慮して選びます。

日本で特に注意すること:古い携帯のアドレス

かつてdocomoやauでは、ドットが連続する(abc..def@)、@の直前がドット(abc.@)といった、メールの仕様(RFC)に厳密には合わないアドレスが作れました。現在は新しく作れませんが、今も使い続けている人がいます。

チェックの方法 古い携帯のアドレス
この記事のパターン1・2 受け付ける
PHPの filter_var 拒否する
RFCに厳密なチェック 拒否する

厳しいチェックで拒否すると、その人は会員登録ができなくなります。登録を受け付けたうえで、確認メールで届くかを確かめる方が、利用者にとって親切です。

一方、こうしたアドレスは、送信するメールサーバーの設定によっては送れないこともあります。受け付けるかどうかは、送信の仕組みとあわせて判断します。

文字数の上限もチェックする

正規表現とは別に、文字数の上限も確認します。

部分 上限 根拠
メールアドレス全体 254文字 メール送信の仕様(RFC 5321)から導かれる実質的な上限
@の前(ローカル部) 64文字 RFC 5321
ドメインの各部分(ドットの間) 63文字 DNSの仕様
function isValidEmail(s) {
  return s.length <= 254 && EMAIL.test(s) && s.split("@")[0].length <= 64;
}

データベースの列の長さも、254文字以上にしておくと、長いアドレスで保存に失敗することを防げます。

+を含むアドレスを拒否しない

user+shop@example.com のように、@の前に「+」を付けて用途を分ける使い方(サブアドレス)は、Gmailなどで広く使われています。+を使えない入力チェックは、利用者にとって不便なだけでなく、よくある改善要望の1つです。この記事のパターンは、+を受け付けます。

日本語ドメインや、国際化されたアドレス

user@例え.jp のような日本語ドメインは、内部では xn-- で始まる英数字(Punycode)に変換して扱われます。受け付ける必要がある場合は、入力された日本語ドメインをPunycodeに変換してから正規表現でチェックします。

"例え.jp".encode("idna").decode()   # 'xn--r8jz45g.jp'

@の前に日本語を使うアドレスも仕様上は定義されていますが、対応しているメールサービスは限られています。多くのサービスでは、@の前は英数字と記号に限るのが現実的な判断です。

危険な正規表現:ReDoS

正規表現の書き方によっては、特定の入力で処理に極端に時間がかかり、サーバーが止まることがあります。これをReDoS(正規表現によるサービス妨害)と呼びます。

# 危険な例:繰り返しの中に、さらに繰り返しがある
bad = r"^([a-zA-Z0-9]+)*@example\.com$"
re.match(bad, "a" * 26 + "!")

実際に計測すると、次のように、入力が2文字増えるごとに処理時間が約4倍になりました。

入力の長さ 処理時間
16文字 ほぼ0秒
20文字 約0.06秒
24文字 約0.8秒
26文字 約3.4秒

30文字を超えると数十秒〜数分かかり、1回の入力でサーバーの処理を占有できてしまいます。

避けるべき書き方は、(a+)+ や (a|a)* のように、同じ文字に一致する繰り返しが入れ子になっているものです。この記事のパターン1は、ドメインの各部分がドットで区切られているため、5万文字の入力でも一瞬で判定が終わることを確認しています。

インターネットで見つけた正規表現を使う場合は、入れ子の繰り返しがないかを確認し、入力の長さの上限(254文字)を先にチェックしておくと安全です。

正規表現でできること・できないこと

確認したいこと 正規表現で確認できるか 方法
形式が正しいか ○ 正規表現
ドメインが存在し、メールを受け取れるか × DNSのMXレコードの確認
そのアドレスが実在するか × 確認メールを送る
本人が受け取れるか × 確認メールのリンクを押してもらう
打ち間違い(gmial.com など)か × よくある間違いの候補を表示する

会員登録では、確認メールで本人確認をするのが確実な方法です。正規表現のチェックは、明らかな入力ミス(@の抜け、空白の混入など)をその場で知らせるための補助と考えます。

入力のしやすさも考える

  • 前後の空白は、チェックの前に取り除く(コピー&ペーストで混ざりやすい)
  • 全角で入力された英数字は、半角に変換してからチェックする
  • 大文字・小文字は、@の後(ドメイン)は区別されない。重複登録のチェックでは、少なくともドメイン部分を小文字に揃える
  • 確認用にもう一度入力させるより、確認メールで確かめる方が、利用者の負担は小さい

よくある質問

Q. RFCに完全に準拠した正規表現はありますか? A. 理論上は作れますが、数千文字に及ぶ非常に複雑なものになり、実在しないような形式まで受け付けます。実務では、この記事のような実用的なパターンと、確認メールを組み合わせるのが一般的です。

Q. フロントエンドでチェックすれば、サーバー側のチェックは不要ですか? A. 必要です。ブラウザでのチェックは、開発者ツールなどで簡単に回避できます。画面側は利用者への案内、サーバー側は最終的な防御として、両方でチェックします。

Q. 「.co.jp」のような2段のドメインにも対応していますか? A. 対応しています。ドメインの部分は、ドットで区切られた部分をいくつでも受け付けます。

Q. ライブラリを使った方がいいですか? A. 使えるなら、実績のあるライブラリ(Pythonのemail-validator、JavaのBean Validationなど)を使うのがおすすめです。ただし、ライブラリによって判定の基準が違うため、古い携帯のアドレスや+を含むアドレスなど、自分のサービスで受け付けたいアドレスが通るかを確認してから使います。

まとめ

  • メールアドレスのチェックは、ほどほどに緩い実用パターンを使う。厳しすぎると実在するアドレスを拒否する
  • 画面とサーバーで基準を揃えるなら、HTML5の仕様と同じパターンも使える
  • Pythonは fullmatch、Javaは matches、PHPは \A と \z で、全体一致を確実にする
  • 全体254文字・@の前64文字の上限も確認する
  • 古い携帯のアドレスや+を含むアドレスを拒否しない
  • 入れ子の繰り返しがある正規表現は、ReDoSで処理が止まる危険がある
  • 実在の確認は確認メールで。正規表現は、入力ミスをその場で知らせる補助

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「メールアドレスの正規表現|実用パターンとチェックの注意点」

株式会社RJCでは、入力チェックのような小さな部分にも、利用者の立場で考える姿勢を大切にしています。こうした知識を仲間と共有しながら、一緒に成長を楽しんでいます。

株式会社RJC ― SI事業・SES事業・AI駆動開発。未経験からエンジニアに育てるのが得意な会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?