diff --git a/background.js b/background.js
index 03e822f..1b1a176 100644
--- a/background.js
+++ b/background.js
@@ -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();
diff --git a/content/utils.js b/content/utils.js
index 1960e26..3b8f0f5 100644
--- a/content/utils.js
+++ b/content/utils.js
@@ -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}]`;
diff --git a/mail-provider-utils.js b/mail-provider-utils.js
new file mode 100644
index 0000000..cccb000
--- /dev/null
+++ b/mail-provider-utils.js
@@ -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;
+}
diff --git a/manifest.json b/manifest.json
index dd2a526..aca5f9b 100644
--- a/manifest.json
+++ b/manifest.json
@@ -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",
diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html
index 3dc8cec..f6f7c49 100644
--- a/sidepanel/sidepanel.html
+++ b/sidepanel/sidepanel.html
@@ -169,6 +169,7 @@
+
diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js
index f8bf5df..2a70689 100644
--- a/sidepanel/sidepanel.js
+++ b/sidepanel/sidepanel.js
@@ -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'
diff --git a/tests/content-utils.test.js b/tests/content-utils.test.js
new file mode 100644
index 0000000..0ea69ca
--- /dev/null
+++ b/tests/content-utils.test.js
@@ -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'
+ );
+});
diff --git a/tests/mail-provider-utils.test.js b/tests/mail-provider-utils.test.js
new file mode 100644
index 0000000..a52ce10
--- /dev/null
+++ b/tests/mail-provider-utils.test.js
@@ -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)',
+ }
+ );
+});