feat: support custom DuckMail domains
This commit is contained in:
@@ -398,9 +398,10 @@ class MoeMailProvider(MailProvider):
|
|||||||
# ==================== DuckMail ====================
|
# ==================== DuckMail ====================
|
||||||
|
|
||||||
class DuckMailProvider(MailProvider):
|
class DuckMailProvider(MailProvider):
|
||||||
def __init__(self, api_base: str = "https://api.duckmail.sbs", bearer_token: str = ""):
|
def __init__(self, api_base: str = "https://api.duckmail.sbs", bearer_token: str = "", domain: str = ""):
|
||||||
self.api_base = api_base.rstrip("/")
|
self.api_base = api_base.rstrip("/")
|
||||||
self.bearer_token = bearer_token
|
self.bearer_token = bearer_token
|
||||||
|
self.domain = str(domain).strip()
|
||||||
|
|
||||||
def _auth_headers(self, token: str = "") -> Dict[str, str]:
|
def _auth_headers(self, token: str = "") -> Dict[str, str]:
|
||||||
h: Dict[str, str] = {"Accept": "application/json"}
|
h: Dict[str, str] = {"Accept": "application/json"}
|
||||||
@@ -419,17 +420,19 @@ class DuckMailProvider(MailProvider):
|
|||||||
headers["Authorization"] = f"Bearer {self.bearer_token}"
|
headers["Authorization"] = f"Bearer {self.bearer_token}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
domains_resp = session.get(f"{self.api_base}/domains", headers={"Accept": "application/json"}, timeout=15, verify=False)
|
domain = self.domain
|
||||||
if domains_resp.status_code != 200:
|
if not domain:
|
||||||
return "", ""
|
domains_resp = session.get(f"{self.api_base}/domains", headers={"Accept": "application/json"}, timeout=15, verify=False)
|
||||||
data = domains_resp.json()
|
if domains_resp.status_code != 200:
|
||||||
items = data if isinstance(data, list) else (data.get("hydra:member") or [])
|
return "", ""
|
||||||
domains = [str(i.get("domain") or "") for i in items if isinstance(i, dict) and i.get("domain") and i.get("isActive", True)]
|
data = domains_resp.json()
|
||||||
if not domains:
|
items = data if isinstance(data, list) else (data.get("hydra:member") or [])
|
||||||
return "", ""
|
domains = [str(i.get("domain") or "") for i in items if isinstance(i, dict) and i.get("domain") and i.get("isActive", True)]
|
||||||
# 优先使用 duckmail.sbs 主域名,避免临时域名被 OpenAI 封禁
|
if not domains:
|
||||||
_preferred = [d for d in domains if "duckmail" in d.lower()]
|
return "", ""
|
||||||
domain = random.choice(_preferred) if _preferred else random.choice(domains)
|
# 优先使用 duckmail.sbs 主域名,避免临时域名被 OpenAI 封禁
|
||||||
|
_preferred = [d for d in domains if "duckmail" in d.lower()]
|
||||||
|
domain = random.choice(_preferred) if _preferred else random.choice(domains)
|
||||||
|
|
||||||
local = f"oc{secrets.token_hex(5)}"
|
local = f"oc{secrets.token_hex(5)}"
|
||||||
email = f"{local}@{domain}"
|
email = f"{local}@{domain}"
|
||||||
@@ -793,6 +796,7 @@ def create_provider_by_name(provider_type: str, mail_cfg: Dict[str, Any]) -> Mai
|
|||||||
return DuckMailProvider(
|
return DuckMailProvider(
|
||||||
api_base=api_base or "https://api.duckmail.sbs",
|
api_base=api_base or "https://api.duckmail.sbs",
|
||||||
bearer_token=str(mail_cfg.get("bearer_token", "")).strip(),
|
bearer_token=str(mail_cfg.get("bearer_token", "")).strip(),
|
||||||
|
domain=str(mail_cfg.get("domain", "")).strip(),
|
||||||
)
|
)
|
||||||
elif provider_type == "cloudflare_temp_email":
|
elif provider_type == "cloudflare_temp_email":
|
||||||
return CloudflareTempEmailProvider(
|
return CloudflareTempEmailProvider(
|
||||||
|
|||||||
@@ -632,6 +632,11 @@
|
|||||||
<input type="text" data-key="api_base" placeholder="https://api.duckmail.sbs" autocomplete="off"
|
<input type="text" data-key="api_base" placeholder="https://api.duckmail.sbs" autocomplete="off"
|
||||||
spellcheck="false" />
|
spellcheck="false" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="config-field">
|
||||||
|
<label>分配域名</label>
|
||||||
|
<input type="text" data-key="domain" placeholder="example.com" autocomplete="off"
|
||||||
|
spellcheck="false" />
|
||||||
|
</div>
|
||||||
<div class="config-field">
|
<div class="config-field">
|
||||||
<label>Bearer Token</label>
|
<label>Bearer Token</label>
|
||||||
<input type="password" data-key="bearer_token" placeholder="DuckMail Bearer Token"
|
<input type="password" data-key="bearer_token" placeholder="DuckMail Bearer Token"
|
||||||
|
|||||||
Reference in New Issue
Block a user