mirror of
https://github.com/zc-zhangchen/any-auto-register.git
synced 2026-05-08 00:04:07 +08:00
feat: 添加 MaliAPI 临时邮箱支持
This commit is contained in:
@@ -12,6 +12,7 @@ CONFIG_KEYS = [
|
||||
"freemail_api_url", "freemail_admin_token", "freemail_username", "freemail_password",
|
||||
"moemail_api_url",
|
||||
"mail_provider",
|
||||
"maliapi_base_url", "maliapi_api_key", "maliapi_domain", "maliapi_auto_domain_strategy",
|
||||
"cfworker_api_url", "cfworker_admin_token", "cfworker_domain", "cfworker_fingerprint",
|
||||
"luckmail_base_url", "luckmail_api_key", "luckmail_email_type", "luckmail_domain",
|
||||
"cpa_api_url", "cpa_api_key",
|
||||
|
||||
@@ -112,6 +112,14 @@ def create_mailbox(provider: str, extra: dict = None, proxy: str = None) -> 'Bas
|
||||
api_url=extra.get("moemail_api_url", "https://sall.cc"),
|
||||
proxy=proxy,
|
||||
)
|
||||
elif provider == "maliapi":
|
||||
return MaliAPIMailbox(
|
||||
api_url=extra.get("maliapi_base_url", "https://maliapi.215.im/v1"),
|
||||
api_key=extra.get("maliapi_api_key", ""),
|
||||
domain=extra.get("maliapi_domain", ""),
|
||||
auto_domain_strategy=extra.get("maliapi_auto_domain_strategy", ""),
|
||||
proxy=proxy,
|
||||
)
|
||||
elif provider == "cfworker":
|
||||
return CFWorkerMailbox(
|
||||
api_url=extra.get("cfworker_api_url", ""),
|
||||
@@ -406,6 +414,188 @@ class DuckMailMailbox(BaseMailbox):
|
||||
raise TimeoutError(f"等待验证码超时 ({timeout}s)")
|
||||
|
||||
|
||||
class MaliAPIMailbox(BaseMailbox):
|
||||
"""YYDS Mail / MaliAPI 临时邮箱服务"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api_url: str = "https://maliapi.215.im/v1",
|
||||
api_key: str = "",
|
||||
domain: str = "",
|
||||
auto_domain_strategy: str = "",
|
||||
proxy: str = None,
|
||||
):
|
||||
self.api = (api_url or "https://maliapi.215.im/v1").rstrip("/")
|
||||
self.api_key = str(api_key or "").strip()
|
||||
self.domain = str(domain or "").strip()
|
||||
self.auto_domain_strategy = str(auto_domain_strategy or "").strip()
|
||||
self.proxy = {"http": proxy, "https": proxy} if proxy else None
|
||||
self._email = None
|
||||
self._temp_token = None
|
||||
|
||||
def _headers(self, bearer: str = "") -> dict[str, str]:
|
||||
headers = {
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
}
|
||||
if self.api_key:
|
||||
headers["X-API-Key"] = self.api_key
|
||||
if bearer:
|
||||
headers["Authorization"] = f"Bearer {bearer}"
|
||||
return headers
|
||||
|
||||
def _request(self, method: str, path: str, *, json_body: dict = None,
|
||||
params: dict = None, bearer: str = "") -> Any:
|
||||
import requests
|
||||
|
||||
response = requests.request(
|
||||
method,
|
||||
f"{self.api}{path}",
|
||||
headers=self._headers(bearer),
|
||||
json=json_body,
|
||||
params=params,
|
||||
proxies=self.proxy,
|
||||
timeout=15,
|
||||
)
|
||||
try:
|
||||
payload = response.json()
|
||||
except Exception:
|
||||
payload = {}
|
||||
|
||||
if response.status_code >= 400:
|
||||
error = response.text or f"HTTP {response.status_code}"
|
||||
error_code = ""
|
||||
if isinstance(payload, dict):
|
||||
error = str(payload.get("error") or error).strip()
|
||||
error_code = str(payload.get("errorCode") or "").strip()
|
||||
if error_code:
|
||||
raise RuntimeError(f"MaliAPI 请求失败: {error} ({error_code})")
|
||||
raise RuntimeError(f"MaliAPI 请求失败: {str(error).strip()}")
|
||||
|
||||
if isinstance(payload, dict):
|
||||
if payload.get("success") is False:
|
||||
error = str(payload.get("error") or "unknown error").strip()
|
||||
error_code = str(payload.get("errorCode") or "").strip()
|
||||
if error_code:
|
||||
raise RuntimeError(f"MaliAPI 请求失败: {error} ({error_code})")
|
||||
raise RuntimeError(f"MaliAPI 请求失败: {error}")
|
||||
if "data" in payload:
|
||||
return payload.get("data")
|
||||
return payload
|
||||
|
||||
def _ensure_api_key(self) -> None:
|
||||
if not self.api_key:
|
||||
raise RuntimeError("MaliAPI 未配置:请在全局设置中填写 maliapi_api_key")
|
||||
|
||||
def _list_messages(self, account: MailboxAccount) -> list[dict]:
|
||||
data = self._request("GET", "/messages", params={"address": account.email})
|
||||
if isinstance(data, dict):
|
||||
messages = data.get("messages", [])
|
||||
else:
|
||||
messages = data
|
||||
return [item for item in (messages or []) if isinstance(item, dict)]
|
||||
|
||||
def _get_message_detail(self, message_id: str) -> dict:
|
||||
data = self._request("GET", f"/messages/{message_id}")
|
||||
if isinstance(data, dict) and isinstance(data.get("message"), dict):
|
||||
return data["message"]
|
||||
return data if isinstance(data, dict) else {}
|
||||
|
||||
def get_email(self) -> MailboxAccount:
|
||||
self._ensure_api_key()
|
||||
body = {}
|
||||
if self.domain:
|
||||
body["domain"] = self.domain
|
||||
if self.auto_domain_strategy:
|
||||
body["autoDomainStrategy"] = self.auto_domain_strategy
|
||||
|
||||
data = self._request("POST", "/accounts", json_body=body)
|
||||
if not isinstance(data, dict):
|
||||
raise RuntimeError(f"MaliAPI 返回异常: {data}")
|
||||
|
||||
email = str(data.get("address") or data.get("email") or "").strip()
|
||||
temp_token = str(
|
||||
data.get("tempToken")
|
||||
or data.get("temp_token")
|
||||
or data.get("token")
|
||||
or ""
|
||||
).strip()
|
||||
inbox_id = str(data.get("id") or "").strip()
|
||||
if not email:
|
||||
raise RuntimeError(f"MaliAPI 返回空邮箱: {data}")
|
||||
|
||||
self._email = email
|
||||
self._temp_token = temp_token
|
||||
self._log(f"[MaliAPI] 生成邮箱: {email}")
|
||||
return MailboxAccount(
|
||||
email=email,
|
||||
account_id=temp_token or inbox_id or email,
|
||||
extra={
|
||||
"provider": "maliapi",
|
||||
"temp_token": temp_token,
|
||||
"inbox_id": inbox_id,
|
||||
},
|
||||
)
|
||||
|
||||
def get_current_ids(self, account: MailboxAccount) -> set:
|
||||
self._ensure_api_key()
|
||||
try:
|
||||
return {
|
||||
str(message.get("id"))
|
||||
for message in self._list_messages(account)
|
||||
if message.get("id") is not None
|
||||
}
|
||||
except Exception:
|
||||
return set()
|
||||
|
||||
def wait_for_code(self, account: MailboxAccount, keyword: str = "",
|
||||
timeout: int = 120, before_ids: set = None,
|
||||
code_pattern: str = None, **kwargs) -> str:
|
||||
import re
|
||||
import time
|
||||
|
||||
self._ensure_api_key()
|
||||
seen = {str(mid) for mid in (before_ids or set())}
|
||||
start = time.time()
|
||||
while time.time() - start < timeout:
|
||||
try:
|
||||
for message in self._list_messages(account):
|
||||
message_id = str(message.get("id") or "").strip()
|
||||
if not message_id or message_id in seen:
|
||||
continue
|
||||
seen.add(message_id)
|
||||
|
||||
try:
|
||||
detail = self._get_message_detail(message_id)
|
||||
except Exception:
|
||||
detail = message
|
||||
|
||||
search_text = " ".join([
|
||||
str(detail.get("subject") or message.get("subject") or ""),
|
||||
str(detail.get("text") or ""),
|
||||
str(detail.get("html") or ""),
|
||||
str(message.get("subject") or ""),
|
||||
str(message.get("snippet") or ""),
|
||||
]).strip()
|
||||
search_text = self._decode_raw_content(search_text) or search_text
|
||||
search_text = re.sub(
|
||||
r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
|
||||
"",
|
||||
search_text,
|
||||
)
|
||||
if keyword and keyword.lower() not in search_text.lower():
|
||||
continue
|
||||
|
||||
code = self._safe_extract(search_text, code_pattern)
|
||||
if code:
|
||||
self._log(f"[MaliAPI] 收到验证码: {code}")
|
||||
return code
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(3)
|
||||
raise TimeoutError(f"等待验证码超时 ({timeout}s)")
|
||||
|
||||
|
||||
class CFWorkerMailbox(BaseMailbox):
|
||||
"""Cloudflare Worker 自建临时邮箱服务"""
|
||||
|
||||
|
||||
@@ -296,6 +296,10 @@ export default function Accounts() {
|
||||
laoudo_auth: cfg.laoudo_auth,
|
||||
laoudo_email: cfg.laoudo_email,
|
||||
laoudo_account_id: cfg.laoudo_account_id,
|
||||
maliapi_base_url: cfg.maliapi_base_url,
|
||||
maliapi_api_key: cfg.maliapi_api_key,
|
||||
maliapi_domain: cfg.maliapi_domain,
|
||||
maliapi_auto_domain_strategy: cfg.maliapi_auto_domain_strategy,
|
||||
yescaptcha_key: cfg.yescaptcha_key,
|
||||
moemail_api_url: cfg.moemail_api_url,
|
||||
duckmail_address: cfg.duckmail_address,
|
||||
|
||||
@@ -39,6 +39,10 @@ export default function Register() {
|
||||
laoudo_auth: cfg.laoudo_auth || '',
|
||||
laoudo_email: cfg.laoudo_email || '',
|
||||
laoudo_account_id: cfg.laoudo_account_id || '',
|
||||
maliapi_base_url: cfg.maliapi_base_url || 'https://maliapi.215.im/v1',
|
||||
maliapi_api_key: cfg.maliapi_api_key || '',
|
||||
maliapi_domain: cfg.maliapi_domain || '',
|
||||
maliapi_auto_domain_strategy: cfg.maliapi_auto_domain_strategy || 'balanced',
|
||||
duckmail_api_url: cfg.duckmail_api_url || '',
|
||||
duckmail_provider_url: cfg.duckmail_provider_url || '',
|
||||
duckmail_bearer: cfg.duckmail_bearer || '',
|
||||
@@ -76,6 +80,10 @@ export default function Register() {
|
||||
laoudo_auth: values.laoudo_auth,
|
||||
laoudo_email: values.laoudo_email,
|
||||
laoudo_account_id: values.laoudo_account_id,
|
||||
maliapi_base_url: values.maliapi_base_url,
|
||||
maliapi_api_key: values.maliapi_api_key,
|
||||
maliapi_domain: values.maliapi_domain,
|
||||
maliapi_auto_domain_strategy: values.maliapi_auto_domain_strategy,
|
||||
moemail_api_url: values.moemail_api_url,
|
||||
duckmail_api_url: values.duckmail_api_url,
|
||||
duckmail_provider_url: values.duckmail_provider_url,
|
||||
@@ -143,6 +151,8 @@ export default function Register() {
|
||||
mail_provider: 'moemail',
|
||||
count: 1,
|
||||
register_delay_seconds: 0,
|
||||
maliapi_base_url: 'https://maliapi.215.im/v1',
|
||||
maliapi_auto_domain_strategy: 'balanced',
|
||||
solver_url: 'http://localhost:8889',
|
||||
}}>
|
||||
<Card title="基本配置" style={{ marginBottom: 16 }}>
|
||||
@@ -192,6 +202,7 @@ export default function Register() {
|
||||
options={[
|
||||
{ value: 'moemail', label: 'MoeMail (sall.cc)' },
|
||||
{ value: 'tempmail_lol', label: 'TempMail.lol' },
|
||||
{ value: 'maliapi', label: 'YYDS Mail / MaliAPI' },
|
||||
{ value: 'duckmail', label: 'DuckMail' },
|
||||
{ value: 'freemail', label: 'Freemail' },
|
||||
{ value: 'laoudo', label: 'Laoudo' },
|
||||
@@ -213,6 +224,28 @@ export default function Register() {
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{mailProvider === 'maliapi' && (
|
||||
<>
|
||||
<Form.Item name="maliapi_base_url" label="API URL">
|
||||
<Input placeholder="https://maliapi.215.im/v1" />
|
||||
</Form.Item>
|
||||
<Form.Item name="maliapi_api_key" label="API Key">
|
||||
<Input.Password placeholder="AC-..." />
|
||||
</Form.Item>
|
||||
<Form.Item name="maliapi_domain" label="邮箱域名(可选)">
|
||||
<Input placeholder="example.com" />
|
||||
</Form.Item>
|
||||
<Form.Item name="maliapi_auto_domain_strategy" label="自动域名策略">
|
||||
<Select
|
||||
options={[
|
||||
{ value: 'balanced', label: 'balanced' },
|
||||
{ value: 'prefer_owned', label: 'prefer_owned' },
|
||||
{ value: 'prefer_public', label: 'prefer_public' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{mailProvider === 'cfworker' && (
|
||||
<>
|
||||
<Form.Item name="cfworker_api_url" label="API URL">
|
||||
|
||||
@@ -19,10 +19,16 @@ const SELECT_FIELDS: Record<string, { label: string; value: string }[]> = {
|
||||
{ label: 'TempMail.lol(自动生成)', value: 'tempmail_lol' },
|
||||
{ label: 'DuckMail(自动生成)', value: 'duckmail' },
|
||||
{ label: 'MoeMail (sall.cc)', value: 'moemail' },
|
||||
{ label: 'YYDS Mail / MaliAPI', value: 'maliapi' },
|
||||
{ label: 'Freemail(自建 CF Worker)', value: 'freemail' },
|
||||
{ label: 'CF Worker(自建域名)', value: 'cfworker' },
|
||||
{ label: 'LuckMail(订单接码 / 已购邮箱)', value: 'luckmail' },
|
||||
],
|
||||
maliapi_auto_domain_strategy: [
|
||||
{ label: 'balanced', value: 'balanced' },
|
||||
{ label: 'prefer_owned', value: 'prefer_owned' },
|
||||
{ label: 'prefer_public', value: 'prefer_public' },
|
||||
],
|
||||
default_executor: [
|
||||
{ label: 'API 协议(无浏览器)', value: 'protocol' },
|
||||
{ label: '无头浏览器', value: 'headless' },
|
||||
@@ -82,6 +88,16 @@ const TAB_ITEMS = [
|
||||
desc: '自动注册账号并生成临时邮箱',
|
||||
fields: [{ key: 'moemail_api_url', label: 'API URL', placeholder: 'https://sall.cc' }],
|
||||
},
|
||||
{
|
||||
title: 'YYDS Mail / MaliAPI',
|
||||
desc: '基于 API Key 创建临时邮箱并轮询收件箱消息',
|
||||
fields: [
|
||||
{ key: 'maliapi_base_url', label: 'API URL', placeholder: 'https://maliapi.215.im/v1' },
|
||||
{ key: 'maliapi_api_key', label: 'API Key', secret: true },
|
||||
{ key: 'maliapi_domain', label: '邮箱域名(可选)', placeholder: 'example.com' },
|
||||
{ key: 'maliapi_auto_domain_strategy', label: '自动域名策略', type: 'select' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'TempMail.lol',
|
||||
desc: '自动生成邮箱,无需配置,需要代理访问(CN IP 被封)',
|
||||
@@ -533,6 +549,9 @@ export default function Settings() {
|
||||
|
||||
useEffect(() => {
|
||||
apiFetch('/config').then((data) => {
|
||||
if (!data.maliapi_base_url) {
|
||||
data.maliapi_base_url = 'https://maliapi.215.im/v1'
|
||||
}
|
||||
if (!data.luckmail_base_url) {
|
||||
data.luckmail_base_url = 'https://mails.luckyous.com/'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user