Gmail 点号和加号别名:如何识别重复注册
j.doe+7@gmail.com 和 jdoe@gmail.com 是同一个收件箱。Gmail 地址规则如何运作、JavaScript 和 Python 版的规范化函数,以及容易踩坑的边界情况。
一个收件箱,无数个地址
Gmail 有两条地址规则,让人能轻而易举地用一个收件箱注册很多账号:
- 点号会被忽略。对于
@gmail.com地址,jane.doe、janedoe和j.a.n.e.d.o.e是同一个收件箱。一个十个字母的名字就有数百种带点号的变体。 - 加号后面的内容会被忽略。
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 去掉点号;其他匹配视为信号。
- 匹配时引导用户登录,不要再给第二次试用。