「表示用マスク(メール)」で何を守りたいのか
メールアドレスは、個人情報のど真ん中です。
でも業務では、ログや画面に「誰のことかは分かりたい」場面も多いですよね。
ログに「ユーザーのメールアドレス」をそのまま出したくない。
サポート画面で「完全なアドレスは見せたくないが、誰かは分かりたい」。
CSV やエラーメッセージに「一部だけ見せたい」。
そこで使うのが「表示用マスク」です。
本物のメールアドレスを、こんな感じに変形します。
user@example.com → u***@example.comtanaka.taro@example.com → t*********@example.com
「本人や運用者には誰か分かるけど、丸見えではない」状態を作るのが目的です。
基本方針:ローカル部だけを部分的に見せる
メールアドレスは大きく 2 つに分かれます。
ローカル部@ドメイン部
user@example.com なら、user がローカル部、example.com がドメイン部です。
実務では、次のような方針にしておくとバランスが良いです。
ローカル部:先頭だけ少し見せて、残りを * にする。
ドメイン部:そのまま見せる(もしくは一部だけマスクする運用もあり)。
まずは「ローカル部だけマスク、ドメインはそのまま」というシンプルな形でいきます。
コアとなるマスク関数を作る
ざっくり仕様を決める
ローカル部のマスクルールを、こう決めてみます。
文字数が 1 文字なら:そのまま表示(a@example.com → a@example.com)。
文字数が 2〜3 文字なら:先頭 1 文字だけ残して、残りを *。
文字数が 4 文字以上なら:先頭 2 文字だけ残して、残りを *。
これで、「誰かは分かる」「でも全部は見えない」というバランスになります。
実装例
function mask_email_for_display(string $email): string
{
// 形式が怪しい場合は、そのまま返す(お好みで)
if (!str_contains($email, '@')) {
return $email;
}
[$local, $domain] = explode('@', $email, 2);
$len = mb_strlen($local, 'UTF-8');
if ($len <= 1) {
// 1 文字ならそのまま
$maskedLocal = $local;
} elseif ($len <= 3) {
// 2〜3 文字なら先頭 1 文字だけ残す
$head = mb_substr($local, 0, 1, 'UTF-8');
$maskedLocal = $head . str_repeat('*', $len - 1);
} else {
// 4 文字以上なら先頭 2 文字だけ残す
$head = mb_substr($local, 0, 2, 'UTF-8');
$maskedLocal = $head . str_repeat('*', $len - 2);
}
return $maskedLocal . '@' . $domain;
}
PHP例題で挙動を確認する
シンプルな英数字の例
echo mask_email_for_display('a@example.com');
// a@example.com
echo mask_email_for_display('ab@example.com');
// a*@example.com
echo mask_email_for_display('abc@example.com');
// a**@example.com
echo mask_email_for_display('abcd@example.com');
// ab**@example.com
echo mask_email_for_display('tanaka.taro@example.com');
// ta*********@example.com
PHPローカル部の長さに応じて、見せる範囲が変わっているのが分かります。
日本語(マルチバイト)を含む例
echo mask_email_for_display('太郎@example.com');
// 太*@example.com
echo mask_email_for_display('山田太郎@example.com');
// 山田**@example.com
PHPmb_strlen / mb_substr を使っているので、
日本語を含むローカル部でも「文字数ベース」でマスクできます。
実務での使いどころ
ログ出力時のマスク
エラーログやアクセスログにメールアドレスを出したいとき、
そのまま書くのではなく、マスクしてから出力します。
$email = $_POST['email'] ?? '';
$masked = mask_email_for_display($email);
error_log('Login failed for email=' . $masked);
PHPこれで、「誰のログか」は追えるけれど、
ログファイルが丸ごと漏洩してもダメージを少し抑えられます。
管理画面の一覧表示
ユーザー一覧画面などで、
「メールアドレスを全部見せるのは避けたいが、サポート担当には誰か分かってほしい」
というときに、そのまま使えます。
<td><?= htmlspecialchars(mask_email_for_display($user['email']), ENT_QUOTES, 'UTF-8') ?></td>
PHPどこまでマスクするかは「運用ポリシー」で決める
ここまでの実装は、あくまで「一例」です。
実務では、会社やシステムごとにポリシーが違います。
ドメインも一部マスクする(example.com → exa****.com)。
ローカル部は先頭 1 文字だけにする。
そもそもメールアドレスはログに出さない。
大事なのは、「ポリシーを決めて、それをコードに落とし込む」ことです。
今回のようなユーティリティ関数にマスクルールを閉じ込めておけば、
ポリシー変更があっても、その関数だけ直せば全体に反映できます。
まとめ:今日からの「表示用マスク(メール)」ユーティリティ
表示用マスク(メール)の目的は、「誰かは分かるが、丸見えではない」状態を作ることです。
そのために、
メールアドレスをローカル部とドメイン部に分ける。
ローカル部だけ、長さに応じて一部を * に置き換える。
ログや画面表示では、必ずこの関数を通した値だけを使う。
というルールを徹底します。
もう一度、コア関数を載せておきます。
function mask_email_for_display(string $email): string
{
if (!str_contains($email, '@')) {
return $email;
}
[$local, $domain] = explode('@', $email, 2);
$len = mb_strlen($local, 'UTF-8');
if ($len <= 1) {
$maskedLocal = $local;
} elseif ($len <= 3) {
$head = mb_substr($local, 0, 1, 'UTF-8');
$maskedLocal = $head . str_repeat('*', $len - 1);
} else {
$head = mb_substr($local, 0, 2, 'UTF-8');
$maskedLocal = $head . str_repeat('*', $len - 2);
}
return $maskedLocal . '@' . $domain;
}
PHPもし、あなたのプロジェクトで「ログに生のメールアドレスを出している」「一覧画面にフルのアドレスを出している」箇所があれば、そこがこの関数を差し込むべき場所です。
たった 1 行の差し替えで、「情報の見せ方」のレベルが一段上がります。

