diff --git a/background.js b/background.js index 02ef4c82..7799ffb6 100644 --- a/background.js +++ b/background.js @@ -371,6 +371,7 @@ const { } = self.LuckMailUtils; const { DEFAULT_MAIL_PAGE_SIZE: CLOUDFLARE_TEMP_EMAIL_DEFAULT_PAGE_SIZE, + buildCloudflareTempEmailEffectiveDomain, buildCloudflareTempEmailHeaders, getCloudflareTempEmailAddressFromResponse, joinCloudflareTempEmailUrl, @@ -379,6 +380,7 @@ const { normalizeCloudflareTempEmailDomain, normalizeCloudflareTempEmailDomains, normalizeCloudflareTempEmailMailApiMessages, + normalizeCloudflareTempEmailSubdomainPrefix, } = self.CloudflareTempEmailUtils; const { DEFAULT_MAIL_PAGE_SIZE: CLOUD_MAIL_DEFAULT_PAGE_SIZE, @@ -1428,6 +1430,8 @@ const PERSISTED_SETTING_DEFAULTS = { cloudflareTempEmailLookupMode: DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE, cloudflareTempEmailReceiveMailbox: '', cloudflareTempEmailUseRandomSubdomain: false, + cloudflareTempEmailUseFixedSubdomain: false, + cloudflareTempEmailSubdomainPrefix: '', cloudflareTempEmailDomain: '', cloudflareTempEmailDomains: [], cloudMailBaseUrl: '', @@ -2899,16 +2903,25 @@ function getHotmailServiceSettings(state = {}) { } function getCloudflareTempEmailConfig(state = {}) { - return { + const useFixedSubdomain = Boolean(state.cloudflareTempEmailUseFixedSubdomain); + const subdomainPrefix = normalizeCloudflareTempEmailSubdomainPrefix(state.cloudflareTempEmailSubdomainPrefix); + const domain = normalizeCloudflareTempEmailDomain(state.cloudflareTempEmailDomain); + const config = { baseUrl: normalizeCloudflareTempEmailBaseUrl(state.cloudflareTempEmailBaseUrl), adminAuth: String(state.cloudflareTempEmailAdminAuth || ''), customAuth: String(state.cloudflareTempEmailCustomAuth || ''), lookupMode: normalizeCloudflareTempEmailLookupMode(state.cloudflareTempEmailLookupMode), receiveMailbox: normalizeCloudflareTempEmailReceiveMailbox(state.cloudflareTempEmailReceiveMailbox), - useRandomSubdomain: Boolean(state.cloudflareTempEmailUseRandomSubdomain), - domain: normalizeCloudflareTempEmailDomain(state.cloudflareTempEmailDomain), + useRandomSubdomain: useFixedSubdomain ? false : Boolean(state.cloudflareTempEmailUseRandomSubdomain), + useFixedSubdomain, + subdomainPrefix, + domain, domains: normalizeCloudflareTempEmailDomains(state.cloudflareTempEmailDomains), }; + return { + ...config, + effectiveDomain: buildCloudflareTempEmailEffectiveDomain(config), + }; } function normalizeCloudflareTempEmailReceiveMailbox(value = '') { @@ -3402,6 +3415,7 @@ function normalizePersistentSettingValue(key, value) { case 'autoDeleteUsedIcloudAlias': case 'accountRunHistoryTextEnabled': case 'cloudflareTempEmailUseRandomSubdomain': + case 'cloudflareTempEmailUseFixedSubdomain': return Boolean(value); case 'icloudHostPreference': return normalizeIcloudHost(value) || 'auto'; @@ -3455,6 +3469,8 @@ function normalizePersistentSettingValue(key, value) { return normalizeCloudflareTempEmailLookupMode(value); case 'cloudflareTempEmailReceiveMailbox': return normalizeCloudflareTempEmailReceiveMailbox(value); + case 'cloudflareTempEmailSubdomainPrefix': + return normalizeCloudflareTempEmailSubdomainPrefix(value); case 'cloudflareTempEmailDomain': return normalizeCloudflareTempEmailDomain(value); case 'cloudflareTempEmailDomains': @@ -3613,6 +3629,9 @@ function buildPersistentSettingsPayload(input = {}, options = {}) { } payload.cloudflareTempEmailDomains = domains; } + if (payload.cloudflareTempEmailUseFixedSubdomain) { + payload.cloudflareTempEmailUseRandomSubdomain = false; + } if (payload.cloudMailDomains) { const domains = normalizeCloudMailDomains(payload.cloudMailDomains); if (payload.cloudMailDomain && !domains.includes(payload.cloudMailDomain)) { @@ -11840,6 +11859,7 @@ function getCurrentPayPalAccount(state = null) { const generatedEmailHelpers = self.MultiPageGeneratedEmailHelpers?.createGeneratedEmailHelpers({ addLog, buildGeneratedAliasEmail, + buildCloudflareTempEmailEffectiveDomain, buildCloudflareTempEmailHeaders, CLOUDFLARE_TEMP_EMAIL_GENERATOR, CUSTOM_EMAIL_POOL_GENERATOR, diff --git a/background/generated-email-helpers.js b/background/generated-email-helpers.js index 81367d5c..e6f6ddb3 100644 --- a/background/generated-email-helpers.js +++ b/background/generated-email-helpers.js @@ -5,6 +5,7 @@ const { addLog, buildGeneratedAliasEmail, + buildCloudflareTempEmailEffectiveDomain, buildCloudflareTempEmailHeaders, CLOUDFLARE_TEMP_EMAIL_GENERATOR, CUSTOM_EMAIL_POOL_GENERATOR, @@ -92,6 +93,12 @@ if (requireDomain && !config.domain) { throw new Error('Cloudflare Temp Email 域名为空或格式无效。'); } + if (config.useFixedSubdomain && !config.effectiveDomain && typeof buildCloudflareTempEmailEffectiveDomain === 'function') { + config.effectiveDomain = buildCloudflareTempEmailEffectiveDomain(config); + } + if (requireDomain && config.useFixedSubdomain && !config.effectiveDomain) { + throw new Error('Cloudflare Temp Email 固定子域前缀为空或格式无效。'); + } return config; } @@ -159,11 +166,16 @@ requireDomain: true, }); const requestedName = String(options.localPart || options.name || '').trim().toLowerCase() || generateCloudflareAliasLocalPart(); + const effectiveDomain = config.effectiveDomain || ( + typeof buildCloudflareTempEmailEffectiveDomain === 'function' + ? buildCloudflareTempEmailEffectiveDomain(config) + : config.domain + ); const payload = { enablePrefix: true, - enableRandomSubdomain: Boolean(config.useRandomSubdomain), + enableRandomSubdomain: config.useFixedSubdomain ? false : Boolean(config.useRandomSubdomain), name: requestedName, - domain: config.domain, + domain: effectiveDomain, }; const result = await requestCloudflareTempEmailJson(config, '/admin/new_address', { method: 'POST', diff --git a/cloudflare-temp-email-utils.js b/cloudflare-temp-email-utils.js index 08f63eb0..ed6371d8 100644 --- a/cloudflare-temp-email-utils.js +++ b/cloudflare-temp-email-utils.js @@ -58,6 +58,29 @@ return domains; } + function normalizeCloudflareTempEmailSubdomainPrefix(rawValue = '') { + let value = String(rawValue || '').trim().toLowerCase(); + if (!value) return ''; + value = value.replace(/^@+/, ''); + value = value.replace(/^https?:\/\//, ''); + value = value.replace(/\/.*$/, ''); + value = value.replace(/^\.+|\.+$/g, ''); + if (!/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(value)) { + return ''; + } + return value; + } + + function buildCloudflareTempEmailEffectiveDomain(config = {}) { + const domain = normalizeCloudflareTempEmailDomain(config.domain); + if (!domain) return ''; + const useFixedSubdomain = Boolean(config.useFixedSubdomain); + const subdomainPrefix = normalizeCloudflareTempEmailSubdomainPrefix(config.subdomainPrefix); + if (!useFixedSubdomain) return domain; + if (!subdomainPrefix) return ''; + return `${subdomainPrefix}.${domain}`; + } + function buildCloudflareTempEmailHeaders(config = {}, options = {}) { const headers = {}; const adminAuth = firstNonEmptyString([config.adminAuth, config.cloudflareTempEmailAdminAuth]); @@ -563,6 +586,7 @@ return { DEFAULT_MAIL_PAGE_SIZE, + buildCloudflareTempEmailEffectiveDomain, buildCloudflareTempEmailHeaders, getCloudflareTempEmailAddressFromResponse, joinCloudflareTempEmailUrl, @@ -572,5 +596,6 @@ normalizeCloudflareTempEmailDomains, normalizeCloudflareTempEmailMailApiMessages, normalizeCloudflareTempEmailMessage, + normalizeCloudflareTempEmailSubdomainPrefix, }; }); diff --git "a/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213.md" "b/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213.md" index 831e7aed..ec4741a5 100644 --- "a/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213.md" +++ "b/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213.md" @@ -22,7 +22,7 @@ |---|---|---|---| | 01 | 相关项目地址与部署说明 | `cpa`、`sub2api`、项目地址、部署前提、部署环境 | `docs/使用教程/分部分/01-相关项目地址与部署说明.md` | | 02 | 更新扩展 | `git pull`、`GitHub Desktop`、手动覆盖更新、扩展重新加载 | `docs/使用教程/分部分/02-更新扩展.md` | -| 03 | Cloudflare Temp Email 使用说明 | `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、邮件接收 | `docs/使用教程/分部分/03-Cloudflare-Temp-Email-使用说明.md` | +| 03 | Cloudflare Temp Email 使用说明 | `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、固定子域、邮件接收 | `docs/使用教程/分部分/03-Cloudflare-Temp-Email-使用说明.md` | | 04 | iCloud 隐私邮箱使用方法 | `iCloud+`、`隐藏邮件地址`、Apple ID、转发邮箱、刷新隐私邮箱 | `docs/使用教程/分部分/04-iCloud-隐私邮箱使用方法.md` | | 05 | QQ 邮箱切换邮箱使用教程 | `QQ 邮箱`、英文邮箱、`Foxmail`、删除后重建 | `docs/使用教程/分部分/05-QQ-邮箱切换邮箱使用教程.md` | | 06 | PayPal 注册与绑卡使用教程 | `PayPal`、注册、绑卡、钱包、身份认证、右上角通知 | `docs/使用教程/分部分/06-PayPal-注册与绑卡使用教程.md` | diff --git "a/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213\344\271\246\345\206\231\346\250\241\346\235\277.md" "b/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213\344\271\246\345\206\231\346\250\241\346\235\277.md" index 7feb77c4..1908ccae 100644 --- "a/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213\344\271\246\345\206\231\346\250\241\346\235\277.md" +++ "b/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\344\275\277\347\224\250\346\225\231\347\250\213\344\271\246\345\206\231\346\250\241\346\235\277.md" @@ -72,7 +72,7 @@ AI 维护时默认按下面的范围归类: |---|---|---|---| | 01 | 相关项目地址与部署说明 | `cpa`、`sub2api`、项目地址、部署前提、部署环境 | `docs/使用教程/分部分/01-相关项目地址与部署说明.md` | | 02 | 更新扩展 | `git pull`、`GitHub Desktop`、手动覆盖更新、扩展重新加载 | `docs/使用教程/分部分/02-更新扩展.md` | -| 03 | Cloudflare Temp Email 使用说明 | `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、邮件接收 | `docs/使用教程/分部分/03-Cloudflare-Temp-Email-使用说明.md` | +| 03 | Cloudflare Temp Email 使用说明 | `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、固定子域、邮件接收 | `docs/使用教程/分部分/03-Cloudflare-Temp-Email-使用说明.md` | | 04 | iCloud 隐私邮箱使用方法 | `iCloud+`、`隐藏邮件地址`、Apple ID、转发邮箱、刷新隐私邮箱 | `docs/使用教程/分部分/04-iCloud-隐私邮箱使用方法.md` | | 05 | QQ 邮箱切换邮箱使用教程 | `QQ 邮箱`、英文邮箱、`Foxmail`、删除后重建 | `docs/使用教程/分部分/05-QQ-邮箱切换邮箱使用教程.md` | | 06 | PayPal 注册与绑卡使用教程 | `PayPal`、注册、绑卡、钱包、身份认证、右上角通知 | `docs/使用教程/分部分/06-PayPal-注册与绑卡使用教程.md` | diff --git "a/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\345\210\206\351\203\250\345\210\206/03-Cloudflare-Temp-Email-\344\275\277\347\224\250\350\257\264\346\230\216.md" "b/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\345\210\206\351\203\250\345\210\206/03-Cloudflare-Temp-Email-\344\275\277\347\224\250\350\257\264\346\230\216.md" index ad332320..82465d2a 100644 --- "a/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\345\210\206\351\203\250\345\210\206/03-Cloudflare-Temp-Email-\344\275\277\347\224\250\350\257\264\346\230\216.md" +++ "b/docs/\344\275\277\347\224\250\346\225\231\347\250\213/\345\210\206\351\203\250\345\210\206/03-Cloudflare-Temp-Email-\344\275\277\347\224\250\350\257\264\346\230\216.md" @@ -3,7 +3,7 @@ ## 部分信息 - `section_slug`: `cloudflare-temp-email` -- `适用主题`: `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、邮件接收 +- `适用主题`: `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、固定子域、邮件接收 - `维护方式`: `直接更新本文件` ## 适用场景 @@ -16,6 +16,7 @@ - 一个可用的 `Cloudflare Temp Email` 后端地址 - 如果要使用随机子域,对应域名解析已经提前配置好 +- 如果要使用固定子域,后端已经开启 `ENABLE_CREATE_ADDRESS_SUBDOMAIN_MATCH` - 后端的 `admin auth` - 如果站点额外设置了访问密码,对应的访问认证信息 - 一个真正用于接收转发邮件的收件邮箱 @@ -52,23 +53,39 @@ ### 第五步:配置 `Temp 域名` -这里填写允许创建邮箱的基础域名。 -即使你开启了 `随机子域`,这里仍然填写基础域名,而不是随机出来的子域名。 +这里选择允许创建邮箱的基础域名。 +即使你开启了 `随机子域` 或 `固定子域`,这里仍然选择基础域名,而不是最终子域名。 ### 第六步:按需开启 `随机子域` 只有在 `邮箱生成 = Cloudflare Temp Email` 时,这一项才会生效。 +`随机子域` 与 `固定子域` 互斥,只能开启其中一个。 启用前需要先确认: - 后端已经配置 `RANDOM_SUBDOMAIN_DOMAINS` - Cloudflare DNS 已经设置 `MX *` -### 第七步:作为 `邮箱服务` 时填写 `邮件接收` +### 第七步:按需开启 `固定子域` + +只有在 `邮箱生成 = Cloudflare Temp Email` 时,这一项才会生效。 +开启 `固定子域` 后再填写 `子域前缀`,例如: + +- `子域前缀 = a` +- `Temp 域名 = b.com` +- 最终提交给后端的域名是 `a.b.com` + +切换 `Temp 域名` 后,子域前缀会继续复用。例如选择 `c.com` 后会生成 `xxx@a.c.com`。 +启用前需要先确认: + +- 后端已经开启 `ENABLE_CREATE_ADDRESS_SUBDOMAIN_MATCH` +- 目标子域名的邮件解析已经准备好,或通配 MX 可以覆盖该子域 + +### 第八步:作为 `邮箱服务` 时填写 `邮件接收` 如果 `邮箱服务` 也选了 `Cloudflare Temp Email`,还需要填写真正的收件邮箱。 后续转发邮件会送到这里。 -### 第八步:查看后端搭建参考 +### 第九步:查看后端搭建参考 如果你还没有部署后端,可以参考: @@ -88,8 +105,14 @@ 通常是因为后端没有配置 `RANDOM_SUBDOMAIN_DOMAINS`,或者 Cloudflare DNS 没有完成 `MX *` 设置。 +### 为什么固定子域没有生效? + +通常是因为后端没有开启 `ENABLE_CREATE_ADDRESS_SUBDOMAIN_MATCH`,或者 `子域前缀` 不符合单段 DNS label 规则。 +前缀只能使用小写字母、数字和中横线,不能包含点号、下划线,也不能以中横线开头或结尾。 + ## 注意事项 - 如果同时把它用作 `邮箱生成` 和 `邮箱服务`,要把两边相关字段都检查一遍 - `Custom Auth` 只有额外访问密码场景才需要填写 -- 开启随机子域前,先确认后端和 DNS 已经准备好 +- `随机子域` 与 `固定子域` 互斥,开启固定子域时会自动关闭随机子域 +- 开启随机子域或固定子域前,先确认后端和 DNS 已经准备好 diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html index 401a97f2..c4fcec89 100644 --- a/sidepanel/sidepanel.html +++ b/sidepanel/sidepanel.html @@ -826,6 +826,25 @@ 依赖后端 RANDOM_SUBDOMAIN_DOMAINS + +