Gmailのドットとプラスエイリアス:重複登録を見つける方法
j.doe+7@gmail.com と jdoe@gmail.com は同じ受信箱です。Gmailのアドレスの仕組み、JavaScriptとPythonの正規化関数、そしてつまずきやすい境界ケース。
1つの受信箱、無限のアドレス
Gmailには、1つの受信箱から大量のアカウントを簡単に作れてしまうアドレスのルールが2つあります。
- ドットは無視される。
@gmail.comのアドレスでは、jane.doe、janedoe、j.a.n.e.d.o.eは同じ受信箱です。10文字の名前ならドットの付け方は数百通りあります。 - プラス記号以降は無視される。
janedoe+test1@gmail.com、janedoe+test2@gmail.comなどはすべてjanedoe@gmail.comに届きます。バリエーションは無制限です。
さらに @googlemail.com は @gmail.com と同じサービスです。確認メールは実際に届くので、どのバリエーションもメール確認を通過します。登録フォームから見れば、すべて別々の新しいユーザーです。
プラスアドレスはGmailだけのものではありません。FastmailやProton Mail、多くの企業メールサーバーも対応しています。一方、ドットを無視するのは個人向けGmail特有の仕様です。
正規化してから比較する
解決策は、元のアドレスの隣に正規化した形を保存し、新規登録をそれと照合することです。元のアドレスはメール送信用に残しましょう。ユーザーが入力したものであり、プラスタグでメールを振り分けている人もいます。
// JavaScript function normalizeEmail(input) { const raw = input.trim().toLowerCase(); const at = raw.lastIndexOf("@"); if (at < 1) return null; let local = raw.slice(0, at); let domain = raw.slice(at + 1).replace(/\.$/, ""); if (domain === "googlemail.com") domain = "gmail.com"; const plus = local.indexOf("+"); if (plus > 0) local = local.slice(0, plus); if (domain === "gmail.com") local = local.replaceAll(".", ""); return `${local}@${domain}`; } normalizeEmail("J.Doe+trial7@GoogleMail.com"); // "jdoe@gmail.com"
# Python def normalize_email(value: str) -> str | None: raw = value.strip().lower() local, sep, domain = raw.rpartition("@") if not sep or not local: return None domain = domain.rstrip(".") if domain == "googlemail.com": domain = "gmail.com" base = local.split("+", 1)[0] or local if domain == "gmail.com": base = base.replace(".", "") return f"{base}@{domain}"
あとは列とインデックスを追加し、登録時に照会します。
ALTER TABLE users ADD COLUMN email_normalized text; CREATE INDEX users_email_normalized ON users (email_normalized); -- 登録時 SELECT count(*) FROM users WHERE email_normalized = $1;
つまずきやすい境界ケース
- 個人向けGmail以外ではドットを取り除かない。多くのプロバイダーやGoogle Workspaceの企業ドメインでは、
jane.doe@とjanedoe@は別人です。そこでドットを消すと他人同士をまとめてしまいます。 - 他のサービスでのプラス除去は推定にすぎない。ほとんどの場合プラスタグはエイリアスですが、メールサーバーが
+を普通の文字として扱うこともあります。Gmail以外での一致は証拠ではなくシグナルとして扱いましょう。 - プラスタグそのものを拒否しない。慎重な人の多くは、サイトごとに
name+service@gmail.comを使います。新しい受信箱にプラスタグがあるのは普通のこと。すでにアカウントのある受信箱にプラスタグが付いていることがシグナルです。 - 比較の前に小文字に揃え、空白と末尾のドットを取り除きます。実際には、プロバイダーはローカル部の大文字・小文字を区別しません。
- 他のプロバイダーには独自のエイリアス方式があります(Yahooの使い捨てアドレス、同一アカウント内のOutlookエイリアスなど)。これらは正規化では捕まえられないので、デバイスやネットワークのシグナルの出番です。
一致したときの対応
正規化後に一致したということは、新しいアカウントが、すでにアカウントのある受信箱でメールを受け取っているということです。たいていの場合、正しい対応はエラーではなく案内です。「このメールアドレスのアカウントがすでにあります。ログインしますか?」。トライアルや無料クレジットについては、トライアルを付与しない、または登録を確認に回す強い理由にもなります。判定フロー全体は無料トライアルの悪用を防ぐ方法をご覧ください。
Attrelixの対応
すべてのチェックでアドレスを正規化し(Gmailのドット、プラスタグ、googlemail.com、Protonのドメイン)、同じ受信箱を持つ既存アカウントを探し、見つかれば理由に alias_of_existing を加えます。お客様のデータ内の元のアドレスは決して変更されず、リンクされたアカウントはレスポンスに含まれるので、グループ全体を確認できます。
まとめ
- Gmailはドットとプラスタグを無視し、多くのプロバイダーはプラスタグを無視します。
- 元のアドレスの隣に正規化済みアドレスを保存し、インデックスを張ります。
- ドットを取り除くのは個人向けGmailだけにし、それ以外の一致はシグナルとして扱います。
- 一致したらログインを促し、2回目のトライアルは与えません。