Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions background.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ const {
} = self.LuckMailUtils;
const {
DEFAULT_MAIL_PAGE_SIZE: CLOUDFLARE_TEMP_EMAIL_DEFAULT_PAGE_SIZE,
buildCloudflareTempEmailEffectiveDomain,
buildCloudflareTempEmailHeaders,
getCloudflareTempEmailAddressFromResponse,
joinCloudflareTempEmailUrl,
Expand All @@ -379,6 +380,7 @@ const {
normalizeCloudflareTempEmailDomain,
normalizeCloudflareTempEmailDomains,
normalizeCloudflareTempEmailMailApiMessages,
normalizeCloudflareTempEmailSubdomainPrefix,
} = self.CloudflareTempEmailUtils;
const {
DEFAULT_MAIL_PAGE_SIZE: CLOUD_MAIL_DEFAULT_PAGE_SIZE,
Expand Down Expand Up @@ -1428,6 +1430,8 @@ const PERSISTED_SETTING_DEFAULTS = {
cloudflareTempEmailLookupMode: DEFAULT_CLOUDFLARE_TEMP_EMAIL_LOOKUP_MODE,
cloudflareTempEmailReceiveMailbox: '',
cloudflareTempEmailUseRandomSubdomain: false,
cloudflareTempEmailUseFixedSubdomain: false,
cloudflareTempEmailSubdomainPrefix: '',
cloudflareTempEmailDomain: '',
cloudflareTempEmailDomains: [],
cloudMailBaseUrl: '',
Expand Down Expand Up @@ -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 = '') {
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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,
Expand Down
16 changes: 14 additions & 2 deletions background/generated-email-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
const {
addLog,
buildGeneratedAliasEmail,
buildCloudflareTempEmailEffectiveDomain,
buildCloudflareTempEmailHeaders,
CLOUDFLARE_TEMP_EMAIL_GENERATOR,
CUSTOM_EMAIL_POOL_GENERATOR,
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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',
Expand Down
25 changes: 25 additions & 0 deletions cloudflare-temp-email-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down Expand Up @@ -563,6 +586,7 @@

return {
DEFAULT_MAIL_PAGE_SIZE,
buildCloudflareTempEmailEffectiveDomain,
buildCloudflareTempEmailHeaders,
getCloudflareTempEmailAddressFromResponse,
joinCloudflareTempEmailUrl,
Expand All @@ -572,5 +596,6 @@
normalizeCloudflareTempEmailDomains,
normalizeCloudflareTempEmailMailApiMessages,
normalizeCloudflareTempEmailMessage,
normalizeCloudflareTempEmailSubdomainPrefix,
};
});
2 changes: 1 addition & 1 deletion docs/使用教程/使用教程.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down
2 changes: 1 addition & 1 deletion docs/使用教程/使用教程书写模板.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## 部分信息

- `section_slug`: `cloudflare-temp-email`
- `适用主题`: `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、邮件接收
- `适用主题`: `Cloudflare Temp Email`、`Admin Auth`、`Custom Auth`、随机子域、固定子域、邮件接收
- `维护方式`: `直接更新本文件`

## 适用场景
Expand All @@ -16,6 +16,7 @@

- 一个可用的 `Cloudflare Temp Email` 后端地址
- 如果要使用随机子域,对应域名解析已经提前配置好
- 如果要使用固定子域,后端已经开启 `ENABLE_CREATE_ADDRESS_SUBDOMAIN_MATCH`
- 后端的 `admin auth`
- 如果站点额外设置了访问密码,对应的访问认证信息
- 一个真正用于接收转发邮件的收件邮箱
Expand Down Expand Up @@ -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`,还需要填写真正的收件邮箱。
后续转发邮件会送到这里。

### 第八步:查看后端搭建参考
### 第九步:查看后端搭建参考

如果你还没有部署后端,可以参考:

Expand All @@ -88,8 +105,14 @@

通常是因为后端没有配置 `RANDOM_SUBDOMAIN_DOMAINS`,或者 Cloudflare DNS 没有完成 `MX *` 设置。

### 为什么固定子域没有生效?

通常是因为后端没有开启 `ENABLE_CREATE_ADDRESS_SUBDOMAIN_MATCH`,或者 `子域前缀` 不符合单段 DNS label 规则。
前缀只能使用小写字母、数字和中横线,不能包含点号、下划线,也不能以中横线开头或结尾。

## 注意事项

- 如果同时把它用作 `邮箱生成` 和 `邮箱服务`,要把两边相关字段都检查一遍
- `Custom Auth` 只有额外访问密码场景才需要填写
- 开启随机子域前,先确认后端和 DNS 已经准备好
- `随机子域` 与 `固定子域` 互斥,开启固定子域时会自动关闭随机子域
- 开启随机子域或固定子域前,先确认后端和 DNS 已经准备好
19 changes: 19 additions & 0 deletions sidepanel/sidepanel.html
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,25 @@
<span class="setting-caption">依赖后端 RANDOM_SUBDOMAIN_DOMAINS</span>
</div>
</div>
<div class="data-row" id="row-temp-email-fixed-subdomain-toggle" style="display:none;">
<span class="data-label">固定子域</span>
<div class="data-inline">
<label class="toggle-switch" for="input-temp-email-use-fixed-subdomain"
title="依赖后端 ENABLE_CREATE_ADDRESS_SUBDOMAIN_MATCH 配置">
<input type="checkbox" id="input-temp-email-use-fixed-subdomain" />
<span class="toggle-switch-track" aria-hidden="true">
<span class="toggle-switch-thumb"></span>
</span>
<span>启用</span>
</label>
<span class="setting-caption">与随机子域互斥</span>
</div>
</div>
<div class="data-row" id="row-temp-email-fixed-subdomain-prefix" style="display:none;">
<span class="data-label">子域前缀</span>
<input type="text" id="input-temp-email-subdomain-prefix" class="data-input"
placeholder="例如 a;当前域名为 b.com 时生成 xxx@a.b.com" />
</div>
<div class="data-row" id="row-temp-email-domain" style="display:none;">
<span class="data-label">Temp 域名</span>
<div class="data-inline">
Expand Down
Loading