文章

无限GMAIL邮箱原理

无限GMAIL邮箱原理

author: claude

tempgbox.net 一个可以生成主流邮箱后缀的网站,可以长时间激活使用。 截图

可以看到这里可以随意生成 GMAIL邮箱, 这里是我生成的一个GMAIL邮箱:

1
m.arryje.m.s12421+hm7aiz9467@gmail.com

可以看到,这个邮箱的格式和我们日常所看到的格式非常不一样,有各种符号: . + 等,看起来很奇怪 这个就涉及到了电子邮箱的 subaddress(子地址,也叫 plus addressing、detailed addressing,常见形式是 user+tag@example.com) 本质上是在用户名部分加一个分隔符和标签,邮件系统在投递时把标签部分忽略掉,仍然送到 user@example.com 的邮箱里。 实现思路主要分两层: 邮件服务器(MTA/MDA)层面的地址解析,以及上层应用对标签的利用。

邮箱子地址(Subaddressing)技术详解:原理、标准与实现

1. 概念与背景

子地址(Subaddressing),也称 Plus Addressing、Detailed Addressing、Tagged Addressing,是指在邮箱本地部分(local-part,即 @ 前面的用户名)中插入一个分隔符与附加标签,例如:

1
user+tag@example.com

邮件系统在投递时会识别分隔符,将地址拆分为”基础账户名”(user)和”详情/标签”(tag)两部分。投递逻辑只依据基础账户名匹配真实邮箱,标签部分会被忽略或单独传递给后续处理环节(如过滤规则)。最终结果是:无论标签是什么,邮件都会进入同一个收件箱。

这个特性最初是为了解决一个实际需求:同一个用户希望用同一个邮箱账户,针对不同的注册场景、不同的通讯对象生成”看似不同”的地址,以便后续追踪邮件来源、做自动分类,或在某个变体地址被滥用(如被垃圾邮件盯上)时单独屏蔽。

2. 标准依据:RFC 5233

子地址机制并非某个厂商私有发明,而是由 IETF 在 RFC 5233(Sieve Email Filtering: Subaddress Extension)中正式定义,作为 Sieve 邮件过滤语言的一个扩展。RFC 5233 规定:

  • 本地部分被拆分为 user、分隔符、detail 三部分。
  • 分隔符通常是 +,但具体由实现决定,常见的还有 -=
  • Sieve 脚本可以通过 :user:detail 两个地址匹配选项,分别取出基础用户名和标签部分,用于编写过滤规则。 需要强调的是,RFC 5233 只定义了 Sieve 语言层面如何”读取”已经存在的子地址结构,而真正”在投递阶段识别并剥离标签”的逻辑,是由邮件传输代理(MTA)或投递代理(MDA)各自实现的,标准本身并未强制规定分隔符必须是哪个字符,这也是为什么不同邮件系统支持的分隔符字符不完全一致。

3. 邮件服务器侧的实现方式

3.1 Postfix

Postfix 原生支持该功能,核心配置项是 recipient_delimiter,写在 main.cf 中:

1
recipient_delimiter = +

启用后,Postfix 在做本地投递或查询 virtual_alias_mapslocal_recipient_maps 等地址表时,会先尝试用完整地址(含标签)匹配,如果没有命中,再退化为去除分隔符及其后内容的基础地址重新匹配。这意味着管理员只需要在别名表里维护 user@example.com 一条记录,所有 user+任意标签@example.com 的变体都会自动落到同一个目标,不需要逐一配置。

Postfix 也支持把分隔符设为多个字符中的任意一个,例如 recipient_delimiter = +-,允许 +- 都作为合法分隔符使用。

3.2 Exim

Exim 通过路由器(router)配置中的 local_part_suffix 参数实现:

1
2
local_part_suffix = +*
local_part_suffix_optional

+* 表示分隔符为 +,后面可以跟任意字符的标签;local_part_suffix_optional 表示带不带后缀都合法。匹配到的后缀内容会被保存进 $local_part_suffix 变量,路由器在后续阶段仍可以读取这个变量,实现”投递照常进行,但标签信息不丢失”。

3.3 Sendmail

Sendmail 把这个特性称为 “plussed addressing” 或 detail addressing,需要在 sendmail.mc 中显式配置允许的域:

1
2
define(`confDELIVERY_MODE', `background')
define(`PLUS_OPTION_DOMAINS', `example.com')

并依赖 local_part 解析规则集(在标准配置中已内建相关处理逻辑)在投递到本地邮箱代理之前,把 + 后面的内容剥离并存入 $X 之类的宏变量,供后续 procmail 等本地投递程序使用。

3.4 Dovecot + Sieve:让标签真正”有用”

仅仅在 MTA 层剥离标签,只能保证邮件能正常送达,标签信息本身如果不被进一步利用就形同虚设。真正让子地址发挥分类作用的,通常是配合 Sieve 过滤规则,在 Dovecot 等 IMAP/投递服务上实现自动归档:

1
2
3
4
5
6
7
require ["subaddress", "fileinto"];
 
if address :detail :is "to" "newsletter" {
    fileinto "Newsletter";
} elsif address :detail :is "to" "shopping" {
    fileinto "Shopping";
}

这段脚本会检查收件地址的 :detail 部分(即 + 后面的标签),如果是 newsletter 就自动归类到”Newsletter”文件夹,如果是 shopping 就归类到对应文件夹。投递本身依然只认基础账户名,过滤是在那之后的独立步骤。

4. 主流邮箱服务商的支持情况

服务商 是否支持 + 子地址 分隔符 是否忽略用户名中的点号
Gmail / Googlemail 支持(默认开启,无需配置) +
Outlook.com / Hotmail 支持 +
Yahoo Mail 部分支持(需在设置中开启”处理别名”) -
iCloud Mail 支持(通过”隐藏我的邮箱”或原生别名功能) +
ProtonMail 支持 +
QQ邮箱 / 163邮箱 / 126邮箱 通常不支持,带 + 的地址可能被判定无效 不适用 不适用
企业自建邮箱(Exchange/Postfix等) 取决于管理员配置 取决于配置 取决于配置

4.1 Gmail 的特殊之处

Gmail 是子地址功能最广为人知、也是规则最特殊的实现,主要有三个特点:

Plus addressing:user+anything@gmail.com 都会投递到 user@gmail.com,标签内容几乎不受限制。

点号不敏感(dot-insensitive):这是 Gmail 独有(其他厂商基本不这么做)的特性,本地部分中的所有英文句点都会被忽略,不论位置。也就是说 j.ohn.doe@gmail.comjohndoe@gmail.comjo.hndoe@gmail.com 在 Gmail 看来是完全相同的账户。这两个特性可以叠加使用,比如 j.ohn.doe+work@gmail.com 最终会被解析为去掉所有点和标签后的 johndoe@gmail.com

gmail.com 与 googlemail.com 互通:googlemail.com 是 Gmail 早期因商标纠纷在德国、英国等地区使用的历史域名,目前两个域名在 Google 系统内部被视为同一域名的两种写法,发往任一域名的同名用户都会投递到同一账户。

大小写不敏感:本地部分大小写在 Gmail 中不影响匹配结果。

4.2 为何国内主流邮箱大多不支持

QQ邮箱、网易系邮箱等国内服务商,出于历史原因和反垃圾邮件策略考虑,普遍没有实现标准的 plus addressing,带 + 的地址要么被当作非法字符直接拒绝,要么干脆查无此人。如果产品面向国内用户但又依赖子地址做追踪,通常需要换一种思路(见第 6 节)。

5. 自行实现:在自建邮件系统中支持子地址

如果是自己开发邮件接收逻辑(例如一个 SaaS 系统需要支持 support+ticket12345@yourapp.com 这种带业务标识的收件地址),核心步骤如下:

第一步:在 SMTP 层解析 RCPT TO

收到 RCPT TO:<user+tag@yourapp.com> 时,用正则表达式拆分本地部分,典型写法:

1
^([^+]+)\+?(.*)$

捕获组一是账户标识(user),捕获组二是标签(tag,可能为空)。

第二步:仅用账户标识做用户匹配

查询用户表、路由表时,只使用捕获组一对应的内容,标签部分不参与账户存在性判断,避免出现”标签不同就被当成不同账户”的错误逻辑。

第三步:标签作为业务参数传递

把捕获组二的内容作为附加上下文(例如工单号、营销渠道来源、邀请码)传给应用层处理逻辑,而不是当作邮箱地址结构的一部分继续解析。

实现时需要注意的细节

标签内容可能包含特殊字符甚至恶意构造的字符串,需要做长度限制和转义,避免被用于邮件头注入或地址欺骗攻击;本地部分理论上按 RFC 5321 是大小写敏感的,但实际系统为了简化逻辑,通常统一转换为小写处理;还需要明确告知用户对方接收方(如果是转发到外部邮箱)是否支持这种格式,避免出现”发件成功但对方收不到”的情况。

6. 安全与隐私层面的考量

6.1 用作渠道追踪与数据泄露溯源

子地址最常见的实际用途之一,是用户在不同网站注册时人为加上不同标签,例如在 A 网站用 me+siteA@gmail.com,在 B 网站用 me+siteB@gmail.com。一旦某天收到的垃圾邮件或钓鱼邮件是发往 me+siteA@gmail.com 的,就能直接判断是 A 网站发生了数据泄露或把邮箱卖给了第三方,而不需要去猜测。这也是为什么安全研究人员在分析数据泄露样本时,经常能看到大量带随机标签的邮箱地址——很多是网站自动生成的追踪标识,并非用户本人手动设置。

6.2 钓鱼与欺骗风险

子地址同时也可能被恶意利用。由于 user+任何文字@gmail.com 在投递层面都等价于 user@gmail.com,攻击者可以构造看起来”具有迷惑性”的发件地址(例如 security+verify-account@attacker-controlled-domain.com)来伪装成正规通知邮件。接收端如果用标签内容做任何形式的自动信任判断(比如自动加白名单、自动跳过验证),需要格外谨慎——标签本身没有任何身份验证意义,只是一个可被任意填写的字符串。

6.3 不应依赖子地址做安全隔离

子地址只是一种”投递层面的便利标记”,不具备访问控制或权限隔离的语义。不应将其用作密码找回验证、双因素认证回退渠道等安全敏感场景的唯一判别依据,因为任何人只要知道你的基础账户名,都可以构造出携带任意标签的有效地址发邮件给你,也可以伪造发件人地址中包含某个标签,这并不能证明发件人对该标签有任何特殊授权。

7. 普通用户如何启用与使用

对绝大多数使用 Gmail、Outlook、ProtonMail 等主流邮箱的用户而言,子地址功能默认就是开启的,不需要在设置中做任何操作,直接在原邮箱用户名后加 +标签 发送或注册即可生效。正确格式是在自己的用户名后面加标签,而不是把标签换成别的内容:

正确:zhangsan+netflix@gmail.com(zhangsan 是你的真实用户名) 错误:netflix+zhangsan@gmail.com(这会被解析为账户名 netflix,与你本人无关)

如果想进一步利用标签做自动归类,可以在 Gmail 的”设置 → 过滤器和阻止的地址”中,新建过滤器,匹配条件填写完整的带标签地址(如 to:zhangsan+netflix@gmail.com),再设置打标签、自动归档、跳过收件箱等动作,实现按注册渠道自动整理邮件。

对使用不支持该功能的国内邮箱服务商的用户,目前没有原生替代方案,只能依赖第三方邮件转发/别名服务(如部分支持自定义域名转发的服务)来间接实现类似效果。

8. 小结

子地址是一个标准化(RFC 5233)但具体实现因厂商而异的邮件特性,核心思路是”投递层剥离标签,过滤层利用标签”。Postfix、Exim、Sendmail 等主流 MTA 都提供了原生支持,Gmail 在此基础上额外叠加了点号不敏感和域名互通两个特性,使其成为应用最广泛、规则最宽松的实现。对普通用户而言,合理使用子地址可以有效追踪个人信息的扩散路径;对开发者而言,理解其投递层与应用层分离的设计,是正确实现邮件路由与防止地址伪造攻击的基础。

本文由作者按照 CC BY 4.0 进行授权