feat: add 126 mail provider routing

This commit is contained in:
Ryan Liu
2026-04-19 11:36:31 +08:00
parent 914dd8f2a5
commit 508fbdc50a
8 changed files with 214 additions and 7 deletions
+4
View File
@@ -628,6 +628,7 @@ function normalizeMailProvider(value = '') {
case CLOUDFLARE_TEMP_EMAIL_PROVIDER:
case '163':
case '163-vip':
case '126':
case 'qq':
case 'inbucket':
case '2925':
@@ -6131,6 +6132,9 @@ function getMailConfig(state) {
if (provider === '163-vip') {
return { source: 'mail-163', url: 'https://webmail.vip.163.com/js6/main.jsp?df=mail163_letter#module=mbox.ListModule%7C%7B%22fid%22%3A1%2C%22order%22%3A%22date%22%2C%22desc%22%3Atrue%7D', label: '163 VIP 邮箱' };
}
if (provider === '126') {
return { source: 'mail-163', url: 'https://mail.126.com/js6/main.jsp?df=mail163_letter#module=mbox.ListModule%7C%7B%22fid%22%3A1%2C%22order%22%3A%22date%22%2C%22desc%22%3Atrue%7D', label: '126 邮箱' };
}
if (provider === 'inbucket') {
const host = normalizeInbucketOrigin(state.inbucketHost);
const mailbox = (state.inbucketMailbox || '').trim();
+20 -5
View File
@@ -2,13 +2,20 @@
const getActivationStrategy = self.MultiPageActivationUtils?.getActivationStrategy;
const SCRIPT_SOURCE = (() => {
if (window.__MULTIPAGE_SOURCE) return window.__MULTIPAGE_SOURCE;
const url = location.href;
const hostname = location.hostname;
function detectScriptSource({
injectedSource,
url = '',
hostname = '',
} = {}) {
if (injectedSource) return injectedSource;
if (url.includes('auth0.openai.com') || url.includes('auth.openai.com') || url.includes('accounts.openai.com')) return 'signup-page';
if (hostname === 'mail.qq.com' || hostname === 'wx.mail.qq.com') return 'qq-mail';
if (hostname === 'mail.163.com' || hostname.endsWith('.mail.163.com') || hostname === 'webmail.vip.163.com') return 'mail-163';
if (
hostname === 'mail.163.com'
|| hostname.endsWith('.mail.163.com')
|| hostname === 'webmail.vip.163.com'
|| hostname === 'mail.126.com'
) return 'mail-163';
if (hostname === 'mail.google.com') return 'gmail-mail';
if (hostname === 'www.icloud.com' || hostname === 'www.icloud.com.cn') return 'icloud-mail';
if (url.includes('duckduckgo.com/email/settings/autofill')) return 'duck-mail';
@@ -16,6 +23,14 @@ const SCRIPT_SOURCE = (() => {
if (url.includes("2925.com")) return "mail-2925";
// VPS panel — detected dynamically since URL is configurable
return 'vps-panel';
}
const SCRIPT_SOURCE = (() => {
return detectScriptSource({
injectedSource: window.__MULTIPAGE_SOURCE,
url: location.href,
hostname: location.hostname,
});
})();
const LOG_PREFIX = `[MultiPage:${SCRIPT_SOURCE}]`;
+80
View File
@@ -0,0 +1,80 @@
const HOTMAIL_PROVIDER = 'hotmail-api';
const NETEASE_LIST_PATH = '/js6/main.jsp?df=mail163_letter#module=mbox.ListModule%7C%7B%22fid%22%3A1%2C%22order%22%3A%22date%22%2C%22desc%22%3Atrue%7D';
function normalizeMailProvider(value = '') {
const normalized = String(value || '').trim().toLowerCase();
switch (normalized) {
case HOTMAIL_PROVIDER:
case '163':
case '163-vip':
case '126':
case 'qq':
case 'inbucket':
return normalized;
default:
return '163';
}
}
function getMailProviderConfig(state = {}, options = {}) {
const provider = normalizeMailProvider(state.mailProvider);
const normalizeInbucketOrigin = options.normalizeInbucketOrigin || (() => '');
if (provider === HOTMAIL_PROVIDER) {
return { provider: HOTMAIL_PROVIDER, label: 'Hotmail(微软 Graph' };
}
if (provider === '163') {
return {
source: 'mail-163',
url: `https://mail.163.com${NETEASE_LIST_PATH}`,
label: '163 邮箱',
};
}
if (provider === '163-vip') {
return {
source: 'mail-163',
url: `https://webmail.vip.163.com${NETEASE_LIST_PATH}`,
label: '163 VIP 邮箱',
};
}
if (provider === '126') {
return {
source: 'mail-163',
url: `https://mail.126.com${NETEASE_LIST_PATH}`,
label: '126 邮箱',
};
}
if (provider === 'inbucket') {
const host = normalizeInbucketOrigin(state.inbucketHost);
const mailbox = String(state.inbucketMailbox || '').trim();
if (!host) {
return { error: 'Inbucket 主机地址为空或无效。' };
}
if (!mailbox) {
return { error: 'Inbucket 邮箱名称为空。' };
}
return {
source: 'inbucket-mail',
url: `${host}/m/${encodeURIComponent(mailbox)}/`,
label: `Inbucket 邮箱(${mailbox}`,
navigateOnReuse: true,
inject: ['content/activation-utils.js', 'content/utils.js', 'content/inbucket-mail.js'],
injectSource: 'inbucket-mail',
};
}
return { source: 'qq-mail', url: 'https://wx.mail.qq.com/', label: 'QQ 邮箱' };
}
const api = {
HOTMAIL_PROVIDER,
getMailProviderConfig,
normalizeMailProvider,
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = api;
}
if (typeof self !== 'undefined') {
self.MailProviderUtils = api;
}
+2 -1
View File
@@ -69,7 +69,8 @@
"matches": [
"https://mail.163.com/*",
"https://*.mail.163.com/*",
"https://webmail.vip.163.com/*"
"https://webmail.vip.163.com/*",
"https://mail.126.com/*"
],
"js": [
"content/activation-utils.js",
+1
View File
@@ -169,6 +169,7 @@
<option value="icloud">iCloud 邮箱</option>
<option value="163">163 邮箱 (mail.163.com)</option>
<option value="163-vip">163 VIP 邮箱 (vip.163.com)</option>
<option value="126">126 邮箱 (mail.126.com)</option>
<option value="qq">QQ 邮箱 (wx.mail.qq.com)</option>
<option value="inbucket">Inbucket(自定义主机)</option>
<option value="2925">2925 邮箱 (2925.com)</option>
+6 -1
View File
@@ -444,6 +444,11 @@ const MAIL_PROVIDER_LOGIN_CONFIGS = {
url: 'https://webmail.vip.163.com/',
buttonLabel: '登录',
},
'126': {
label: '126 邮箱',
url: 'https://mail.126.com/',
buttonLabel: '登录',
},
qq: {
label: 'QQ 邮箱',
url: 'https://wx.mail.qq.com/',
@@ -1693,7 +1698,7 @@ function applySettingsState(state) {
inputSub2ApiGroup.value = state?.sub2apiGroupName || '';
inputSub2ApiDefaultProxy.value = state?.sub2apiDefaultProxyName || '';
const restoredMailProvider = isCustomMailProvider(state?.mailProvider)
|| [ICLOUD_PROVIDER, 'hotmail-api', GMAIL_PROVIDER, 'luckmail-api', '163', '163-vip', 'qq', 'inbucket', '2925', 'cloudflare-temp-email'].includes(String(state?.mailProvider || '').trim())
|| [ICLOUD_PROVIDER, 'hotmail-api', GMAIL_PROVIDER, 'luckmail-api', '163', '163-vip', '126', 'qq', 'inbucket', '2925', 'cloudflare-temp-email'].includes(String(state?.mailProvider || '').trim())
? String(state?.mailProvider || '163').trim()
: (String(state?.emailGenerator || '').trim().toLowerCase() === 'custom'
|| String(state?.emailGenerator || '').trim().toLowerCase() === 'manual'
+66
View File
@@ -0,0 +1,66 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const source = fs.readFileSync('content/utils.js', 'utf8');
function extractFunction(name) {
const start = source.indexOf(`function ${name}(`);
if (start < 0) {
throw new Error(`missing function ${name}`);
}
let parenDepth = 0;
let signatureEnded = false;
let braceStart = -1;
for (let index = start; index < source.length; index += 1) {
const ch = source[index];
if (ch === '(') {
parenDepth += 1;
} else if (ch === ')') {
parenDepth -= 1;
if (parenDepth === 0) {
signatureEnded = true;
}
} else if (ch === '{' && signatureEnded) {
braceStart = index;
break;
}
}
if (braceStart < 0) {
throw new Error(`missing body for function ${name}`);
}
let depth = 0;
let end = braceStart;
for (; end < source.length; end += 1) {
const ch = source[end];
if (ch === '{') depth += 1;
if (ch === '}') {
depth -= 1;
if (depth === 0) {
end += 1;
break;
}
}
}
return source.slice(start, end);
}
test('detectScriptSource maps 126 mail hosts to the shared 163 mail source', () => {
const bundle = [extractFunction('detectScriptSource')].join('\n');
const api = new Function(`
${bundle}
return { detectScriptSource };
`)();
assert.equal(
api.detectScriptSource({
url: 'https://mail.126.com/js6/main.jsp',
hostname: 'mail.126.com',
}),
'mail-163'
);
});
+35
View File
@@ -0,0 +1,35 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const {
HOTMAIL_PROVIDER,
getMailProviderConfig,
normalizeMailProvider,
} = require('../mail-provider-utils.js');
test('normalizeMailProvider accepts 126 and falls back to 163', () => {
assert.equal(normalizeMailProvider('126'), '126');
assert.equal(normalizeMailProvider('163-vip'), '163-vip');
assert.equal(normalizeMailProvider('unknown-provider'), '163');
});
test('getMailProviderConfig returns the shared NetEase source for 126 mail', () => {
assert.deepEqual(
getMailProviderConfig({ mailProvider: '126' }),
{
source: 'mail-163',
url: 'https://mail.126.com/js6/main.jsp?df=mail163_letter#module=mbox.ListModule%7C%7B%22fid%22%3A1%2C%22order%22%3A%22date%22%2C%22desc%22%3Atrue%7D',
label: '126 邮箱',
}
);
});
test('getMailProviderConfig preserves the hotmail provider sentinel', () => {
assert.deepEqual(
getMailProviderConfig({ mailProvider: HOTMAIL_PROVIDER }),
{
provider: HOTMAIL_PROVIDER,
label: 'Hotmail(微软 Graph',
}
);
});