C# Tips | 文字列処理:メールアドレス検証

C# C#
スポンサーリンク

はじめに 「メールアドレス検証」は“現実と割り切りのバランスを取る技”

業務システムでほぼ確実に出てくるのが「メールアドレス入力欄」です。
ここで悩ましいのが、

「どこまで厳密にチェックするか?」

です。

RFC に完全準拠しようとすると、正規表現は怪物みたいに長くなります。
一方で、あまりにゆるいと「明らかにおかしいアドレス」を通してしまいます。

実務では、

「現実的な範囲で“それっぽく正しい”ものだけ通す」

という割り切りがほぼ必須です。

ここでは、初心者向けに、

メールアドレス検証の考え方
System.Net.Mail.MailAddress を使う方法
正規表現での“現実的な”チェック
ユーティリティ化と、エラーメッセージ設計のポイント

を、例題付きでかみ砕いて説明していきます。


メールアドレス検証の全体像をざっくり整理する

「完全に正しいか?」ではなく「明らかにおかしくないか?」

まず前提として、メールアドレスにはかなり複雑な仕様があります。
理論上は、かなり変な文字も許されます。

ただ、業務システムでユーザーが実際に入力するアドレスは、ほぼ次のような形です。

local-part@domain
例:user.name+tag@example.com

なので、実務的には、

@ が 1 個だけあるか
@ の前後にちゃんと文字があるか
ドメインに . が含まれているか

くらいを押さえておけば、十分役に立ちます。

そのうえで、

ライブラリ(MailAddress)に任せる方法
自前の正規表現でざっくりチェックする方法

を組み合わせていくイメージです。


MailAddress を使った「構文チェック」

MailAddress で「とりあえず形として妥当か」を見る

C# には、System.Net.Mail.MailAddress というクラスがあります。
これを使うと、「文字列がメールアドレスとして構文的に妥当か」をある程度チェックできます。

using System;
using System.Net.Mail;

public static class EmailValidator
{
    public static bool IsValidByMailAddress(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        try
        {
            var addr = new MailAddress(value);
            // 入力文字列と addr.Address が一致しているかも確認しておく
            return addr.Address == value.Trim();
        }
        catch (FormatException)
        {
            return false;
        }
    }
}
C#

ここでのポイントは、

null や空白だけなら false
new MailAddress(value) で構文チェック
例外が出たら不正とみなす
addr.Address == value.Trim() で「余計な表示名などが付いていないか」も確認

という流れです。

動作例

Console.WriteLine(EmailValidator.IsValidByMailAddress("user@example.com"));        // true
Console.WriteLine(EmailValidator.IsValidByMailAddress("user.name+tag@example.com"));// true
Console.WriteLine(EmailValidator.IsValidByMailAddress("user@domain"));             // false の可能性が高い
Console.WriteLine(EmailValidator.IsValidByMailAddress("not-an-email"));            // false
Console.WriteLine(EmailValidator.IsValidByMailAddress(""));                        // false
C#

MailAddress は「RFC 的にかなり広い範囲」を許容するので、
これだけで「業務要件としての妥当性」をすべて満たせるとは限りませんが、
「明らかにおかしい文字列」を弾くには十分役に立ちます。


正規表現での“現実的な”メールアドレスチェック

シンプルで実務的なパターン例

「ライブラリに任せるだけだと不安」「もう少し自分でルールをコントロールしたい」
という場合は、正規表現を併用します。

完全な RFC 準拠ではなく、「現実的な範囲でよく使われる形」を想定したパターンの一例です。

using System.Text.RegularExpressions;

public static class EmailRegexValidator
{
    // かなり現実寄りの簡易パターン
    private static readonly Regex EmailRegex =
        new Regex(
            @"^[0-9A-Za-z._%+\-]+@[0-9A-Za-z.\-]+\.[A-Za-z]{2,}$",
            RegexOptions.Compiled);

    public static bool IsValidByRegex(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        return EmailRegex.IsMatch(value.Trim());
    }
}
C#

このパターンの意味をざっくり分解すると、

^[0-9A-Za-z._%+\-]+
ローカル部:英数字と ._%+- を 1 文字以上

@
区切り

[0-9A-Za-z.\-]+
ドメイン部:英数字と .- を 1 文字以上

\.[A-Za-z]{2,}$
最後に「.+2文字以上の英字」(トップレベルドメイン)

という感じです。

動作例

Console.WriteLine(EmailRegexValidator.IsValidByRegex("user@example.com"));        // true
Console.WriteLine(EmailRegexValidator.IsValidByRegex("user.name+tag@example.co.jp")); // true
Console.WriteLine(EmailRegexValidator.IsValidByRegex("user@domain"));             // false(. がない)
Console.WriteLine(EmailRegexValidator.IsValidByRegex("user@@example.com"));       // false
Console.WriteLine(EmailRegexValidator.IsValidByRegex("user example@example.com"));// false(空白)
C#

この正規表現は「完璧」ではありませんが、
業務システムの入力チェックとしては、かなり現実的なラインです。


MailAddress+正規表現を組み合わせたユーティリティ

「構文として妥当」かつ「自分たちのルールにも合うか」

実務では、

MailAddress で「構文としておかしくないか」を見る
正規表現で「自分たちの運用ルールに合っているか」を見る

という二段構えにするのもアリです。

using System;
using System.Net.Mail;
using System.Text.RegularExpressions;

public static class EmailValidationUtil
{
    private static readonly Regex EmailRegex =
        new Regex(
            @"^[0-9A-Za-z._%+\-]+@[0-9A-Za-z.\-]+\.[A-Za-z]{2,}$",
            RegexOptions.Compiled);

    public static bool IsValidEmail(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        string trimmed = value.Trim();

        // まず MailAddress で構文チェック
        try
        {
            var addr = new MailAddress(trimmed);
            if (addr.Address != trimmed)
            {
                return false;
            }
        }
        catch (FormatException)
        {
            return false;
        }

        // さらに自前のルール(正規表現)でもチェック
        return EmailRegex.IsMatch(trimmed);
    }
}
C#

こうしておくと、

明らかにメールアドレスでないものは MailAddress が弾く
構文的にはギリギリOKでも、運用上許可したくない形は正規表現で弾く

というバランスが取れます。


実務での設計ポイントとエラーメッセージの考え方

「なぜダメなのか」をユーザーに伝えすぎない

メールアドレス検証でやりがちなのが、

「ここがダメです」「この文字は使えません」と細かく教えすぎることです。

ユーザー体験としては親切に見えますが、
セキュリティの観点では「どこまで通るか」を攻撃者に教えてしまうことにもなります。

実務では、

「メールアドレスの形式が正しくありません」

くらいのメッセージにとどめておき、
詳細なルールは画面の説明やヘルプに書く、というバランスがよく取れています。

「空は許すか」「必須か」は別レイヤーで決める

メールアドレス検証ユーティリティは、
「値が入っている前提で、その形式が妥当か」を見る役割にしておき、

「必須かどうか(空を許すかどうか)」は、
画面やバリデーションレイヤー側で決める、という分離も大事です。

例えば、

IsValidEmail は「空なら false」
別のレイヤーで「必須なら空のときに“未入力エラー”」「任意なら空はOK」

というように役割を分けておくと、ユーティリティがシンプルに保てます。


まとめ 「メールアドレス検証ユーティリティ」は“完璧さより現実的な安全ラインを作る道具”

メールアドレス検証は、「完璧に正しいか?」を目指すと沼にハマります。
実務で大事なのは、

明らかにおかしいものを弾く
現実的な入力パターンをちゃんと通す
ルールをユーティリティとして一箇所に集約する

というバランスです。

押さえておきたいポイントは、

MailAddress で構文チェックをすると、かなりの“変な文字列”を弾ける
正規表現は「現実的な範囲」でシンプルに保つ(local@domain.tld を基本にする)
二段構え(MailAddress+自前正規表現)にすると、構文と運用ルールの両方を満たせる
必須チェックやエラーメッセージの詳細は、ユーティリティの外側で決める

ここまで理解できれば、「とりあえずそれっぽい正規表現を書いている」段階から一歩進んで、
“現実的で保守しやすいメールアドレス検証ユーティリティ”を、
自分の手で設計・実装できるようになっていきます。

タイトルとURLをコピーしました