@@ -1833,19 +1833,22 @@ def apply_runtime_settings_to_modules() -> None:
18331833 # Per-provider base URLs for self-hosted services (do not share one field).
18341834 "moemail_base_url" ,
18351835 "cfmail_base_url" ,
1836+ "cloudmail_base_url" ,
18361837 # Active key (derived from selected provider). Kept for adapter/env compat.
18371838 "api_key" ,
18381839 # Per-provider secrets — all persist in DB so switching provider keeps keys.
18391840 "moemail_api_key" ,
18401841 "yyds_api_key" ,
18411842 "gptmail_api_key" ,
18421843 "cfmail_api_key" ,
1844+ "cloudmail_api_key" ,
18431845 # Active domain + per-provider domains (same pattern as keys).
18441846 "domain" ,
18451847 "moemail_domain" ,
18461848 "yyds_domain" ,
18471849 "gptmail_domain" ,
18481850 "cfmail_domain" ,
1851+ "cloudmail_domain" ,
18491852 "prefix" ,
18501853 "expiry_ms" ,
18511854 "captcha_provider" ,
@@ -1868,6 +1871,7 @@ def apply_runtime_settings_to_modules() -> None:
18681871 "yyds_api_key" ,
18691872 "gptmail_api_key" ,
18701873 "cfmail_api_key" ,
1874+ "cloudmail_api_key" ,
18711875 "yescaptcha_key" ,
18721876 "proxy_password" ,
18731877 }
@@ -1878,20 +1882,23 @@ def apply_runtime_settings_to_modules() -> None:
18781882 "yyds" : "yyds_api_key" ,
18791883 "gptmail" : "gptmail_api_key" ,
18801884 "cfmail" : "cfmail_api_key" ,
1885+ "cloudmail" : "cloudmail_api_key" ,
18811886}
18821887
18831888_MAIL_PROVIDER_DOMAIN_FIELDS = {
18841889 "moemail" : "moemail_domain" ,
18851890 "yyds" : "yyds_domain" ,
18861891 "gptmail" : "gptmail_domain" ,
18871892 "cfmail" : "cfmail_domain" ,
1893+ "cloudmail" : "cloudmail_domain" ,
18881894}
18891895
18901896# Self-hosted providers keep independent base URLs so switching never overwrites
1891- # another provider's host (MoeMail vs Cloudflare Temp Email).
1897+ # another provider's host (MoeMail vs Cloudflare Temp Email vs Cloud Mail ).
18921898_MAIL_PROVIDER_BASE_URL_FIELDS = {
18931899 "moemail" : "moemail_base_url" ,
18941900 "cfmail" : "cfmail_base_url" ,
1901+ "cloudmail" : "cloudmail_base_url" ,
18951902}
18961903
18971904
@@ -1983,6 +1990,27 @@ def _env_registration_defaults() -> dict[str, Any]:
19831990 if cf_base :
19841991 # Dedicated CF host only — never overwrite MoeMail base_url.
19851992 out ["cfmail_base_url" ] = cf_base
1993+ cm_key = (
1994+ os .environ .get ("GROK2API_CLOUDMAIL_API_KEY" )
1995+ or os .environ .get ("CLOUDMAIL_API_KEY" )
1996+ or ""
1997+ ).strip ()
1998+ if cm_key :
1999+ out ["cloudmail_api_key" ] = cm_key
2000+ cm_base = (
2001+ os .environ .get ("GROK2API_CLOUDMAIL_BASE_URL" )
2002+ or os .environ .get ("CLOUDMAIL_BASE_URL" )
2003+ or ""
2004+ ).strip ()
2005+ if cm_base :
2006+ out ["cloudmail_base_url" ] = cm_base
2007+ cm_dom = (
2008+ os .environ .get ("GROK2API_CLOUDMAIL_DOMAIN" )
2009+ or os .environ .get ("CLOUDMAIL_DOMAIN" )
2010+ or ""
2011+ ).strip ().lstrip ("@" ).strip ("." )
2012+ if cm_dom :
2013+ out ["cloudmail_domain" ] = cm_dom
19862014 # Prefer multi-line pool env when present; keep single-proxy fallback.
19872015 pool_env = (
19882016 os .environ .get ("GROK2API_XAI_PROXY_POOL" )
@@ -2078,11 +2106,13 @@ def _pick_domain(key: str) -> str:
20782106 legacy_base_url = _pick_str ("base_url" , 256 )
20792107 cfg ["moemail_base_url" ] = _pick_str ("moemail_base_url" , 256 )
20802108 cfg ["cfmail_base_url" ] = _pick_str ("cfmail_base_url" , 256 )
2109+ cfg ["cloudmail_base_url" ] = _pick_str ("cloudmail_base_url" , 256 )
20812110 legacy_api_key = _pick_str ("api_key" , 512 )
20822111 cfg ["moemail_api_key" ] = _pick_str ("moemail_api_key" , 512 )
20832112 cfg ["yyds_api_key" ] = _pick_str ("yyds_api_key" , 512 )
20842113 cfg ["gptmail_api_key" ] = _pick_str ("gptmail_api_key" , 512 )
20852114 cfg ["cfmail_api_key" ] = _pick_str ("cfmail_api_key" , 512 )
2115+ cfg ["cloudmail_api_key" ] = _pick_str ("cloudmail_api_key" , 512 )
20862116 # Do NOT env-fill legacy domain into every provider — only use explicit src.
20872117 if "domain" in src :
20882118 legacy_domain = str (src .get ("domain" ) or "" ).strip ().lstrip ("@" ).strip ("." )[:128 ]
@@ -2092,10 +2122,12 @@ def _pick_domain(key: str) -> str:
20922122 cfg ["yyds_domain" ] = _pick_domain ("yyds_domain" )
20932123 cfg ["gptmail_domain" ] = _pick_domain ("gptmail_domain" )
20942124 cfg ["cfmail_domain" ] = _pick_domain ("cfmail_domain" )
2125+ cfg ["cloudmail_domain" ] = _pick_domain ("cloudmail_domain" )
20952126 cfg ["prefix" ] = _pick_str ("prefix" , 64 )
20962127 try :
20972128 from grok2api .upstream .moemail import (
20982129 normalize_cfmail_base_url ,
2130+ normalize_cloudmail_base_url ,
20992131 normalize_gptmail_base_url ,
21002132 normalize_mail_provider ,
21012133 normalize_yyds_base_url ,
@@ -2105,13 +2137,15 @@ def _pick_domain(key: str) -> str:
21052137 normalize_yyds_base_url = None # type: ignore[assignment]
21062138 normalize_gptmail_base_url = None # type: ignore[assignment]
21072139 normalize_cfmail_base_url = None # type: ignore[assignment]
2140+ normalize_cloudmail_base_url = None # type: ignore[assignment]
21082141
21092142 mail_raw = _pick_str ("mail_provider" , 32 ).lower ()
21102143 # Prefer explicit mail_provider; only use base_url as a hint when empty.
21112144 if normalize_mail_provider is not None :
21122145 cfg ["mail_provider" ] = normalize_mail_provider (
21132146 mail_raw or None ,
21142147 base_url = legacy_base_url
2148+ or cfg .get ("cloudmail_base_url" )
21152149 or cfg .get ("cfmail_base_url" )
21162150 or cfg .get ("moemail_base_url" )
21172151 or None ,
@@ -2123,10 +2157,12 @@ def _pick_domain(key: str) -> str:
21232157 cfg ["mail_provider" ] = "gptmail"
21242158 elif mail_raw in {"cfmail" , "cloudflare" , "cloudflare_temp_email" , "awsl" }:
21252159 cfg ["mail_provider" ] = "cfmail"
2160+ elif mail_raw in {"cloudmail" , "cloud-mail" , "skymail" , "maillab" }:
2161+ cfg ["mail_provider" ] = "cloudmail"
21262162 else :
21272163 cfg ["mail_provider" ] = (
21282164 mail_raw
2129- if mail_raw in {"moemail" , "yyds" , "gptmail" , "cfmail" }
2165+ if mail_raw in {"moemail" , "yyds" , "gptmail" , "cfmail" , "cloudmail" }
21302166 else "moemail"
21312167 )
21322168
@@ -2179,11 +2215,13 @@ def _pick_domain(key: str) -> str:
21792215 # selected self-hosted provider so adapter/env keep working.
21802216 if normalize_cfmail_base_url is not None and cfg .get ("cfmail_base_url" ):
21812217 cfg ["cfmail_base_url" ] = normalize_cfmail_base_url (cfg ["cfmail_base_url" ])
2218+ if normalize_cloudmail_base_url is not None and cfg .get ("cloudmail_base_url" ):
2219+ cfg ["cloudmail_base_url" ] = normalize_cloudmail_base_url (cfg ["cloudmail_base_url" ])
21822220 if cfg .get ("moemail_base_url" ):
21832221 cfg ["moemail_base_url" ] = str (cfg ["moemail_base_url" ]).strip ().rstrip ("/" )
21842222
21852223 # YYDS / GPTMail use fixed official hosts — no user URL required.
2186- # CF Temp Email / MoeMail are self-hosted and keep independent slots.
2224+ # CF Temp Email / MoeMail / Cloud Mail are self-hosted and keep independent slots.
21872225 if cfg ["mail_provider" ] == "yyds" :
21882226 cfg ["base_url" ] = (
21892227 normalize_yyds_base_url (None )
@@ -2204,6 +2242,15 @@ def _pick_domain(key: str) -> str:
22042242 else (str (raw_base ).strip () or "https://temp-email-api.awsl.uk" )
22052243 )
22062244 cfg ["base_url" ] = cfg ["cfmail_base_url" ]
2245+ elif cfg ["mail_provider" ] == "cloudmail" :
2246+ raw_base = cfg .get ("cloudmail_base_url" ) or ""
2247+ if normalize_cloudmail_base_url is not None :
2248+ cfg ["cloudmail_base_url" ] = normalize_cloudmail_base_url (
2249+ str (raw_base ) if raw_base else None
2250+ )
2251+ else :
2252+ cfg ["cloudmail_base_url" ] = str (raw_base ).strip ().rstrip ("/" )
2253+ cfg ["base_url" ] = cfg ["cloudmail_base_url" ]
22072254 else :
22082255 # MoeMail: active base_url mirrors moemail_base_url.
22092256 cfg ["base_url" ] = str (cfg .get ("moemail_base_url" ) or "" ).strip ()
@@ -2314,13 +2361,15 @@ def get_registration_config(*, include_secrets: bool = True) -> dict[str, Any]:
23142361 has_yyds = bool (cfg .get ("yyds_api_key" ))
23152362 has_gpt = bool (cfg .get ("gptmail_api_key" ))
23162363 has_cf = bool (cfg .get ("cfmail_api_key" ))
2364+ has_cm = bool (cfg .get ("cloudmail_api_key" ))
23172365 has_active = bool (cfg .get ("api_key" ))
23182366 public ["configured" ] = {
23192367 "moemail" : has_moemail ,
23202368 "yyds" : has_yyds ,
23212369 "gptmail" : has_gpt ,
23222370 "cfmail" : has_cf ,
2323- "mail" : has_active or has_moemail or has_yyds or has_gpt or has_cf ,
2371+ "cloudmail" : has_cm ,
2372+ "mail" : has_active or has_moemail or has_yyds or has_gpt or has_cf or has_cm ,
23242373 "yescaptcha" : bool (cfg .get ("yescaptcha_key" )),
23252374 "local_solver" : bool (cfg .get ("local_solver_url" )),
23262375 "captcha" : (
@@ -2537,14 +2586,17 @@ def set_registration_config(
25372586 "yyds_domain" ,
25382587 "gptmail_domain" ,
25392588 "cfmail_domain" ,
2589+ "cloudmail_domain" ,
25402590 "api_key" ,
25412591 "moemail_api_key" ,
25422592 "yyds_api_key" ,
25432593 "gptmail_api_key" ,
25442594 "cfmail_api_key" ,
2595+ "cloudmail_api_key" ,
25452596 "base_url" ,
25462597 "moemail_base_url" ,
25472598 "cfmail_base_url" ,
2599+ "cloudmail_base_url" ,
25482600 # Proxy pool: empty means "cleared" so env cannot revive a deleted list.
25492601 "proxy" ,
25502602 "proxy_username" ,
@@ -2560,13 +2612,13 @@ def set_registration_config(
25602612 for k in ("expiry_ms" , "count" , "concurrency" , "stagger_ms" , "probe_delay_sec" ):
25612613 cleaned [k ] = cfg [k ]
25622614 # Always persist active + per-provider domain slots (including empty).
2563- for k in ("domain" , "moemail_domain" , "yyds_domain" , "gptmail_domain" , "cfmail_domain" ):
2615+ for k in ("domain" , "moemail_domain" , "yyds_domain" , "gptmail_domain" , "cfmail_domain" , "cloudmail_domain" ):
25642616 cleaned [k ] = str (cfg .get (k ) or "" ).strip ().lstrip ("@" ).strip ("." )
25652617 # Always persist active + per-provider keys (including empty after clear).
2566- for k in ("api_key" , "moemail_api_key" , "yyds_api_key" , "gptmail_api_key" , "cfmail_api_key" ):
2618+ for k in ("api_key" , "moemail_api_key" , "yyds_api_key" , "gptmail_api_key" , "cfmail_api_key" , "cloudmail_api_key" ):
25672619 cleaned [k ] = str (cfg .get (k ) or "" ).strip ()
25682620 # Always persist active + per-provider base URLs (including empty after clear).
2569- for k in ("base_url" , "moemail_base_url" , "cfmail_base_url" ):
2621+ for k in ("base_url" , "moemail_base_url" , "cfmail_base_url" , "cloudmail_base_url" ):
25702622 cleaned [k ] = str (cfg .get (k ) or "" ).strip ().rstrip ("/" )
25712623
25722624 _set_setting_value ("registration_config" , cleaned )
@@ -2590,19 +2642,22 @@ def _set_env(name: str, value: str) -> None:
25902642 os .environ .pop (name , None )
25912643
25922644 mail_provider = str (cfg .get ("mail_provider" ) or "moemail" ).strip ().lower ()
2593- if mail_provider not in {"moemail" , "yyds" , "gptmail" , "cfmail" }:
2645+ if mail_provider not in {"moemail" , "yyds" , "gptmail" , "cfmail" , "cloudmail" }:
25942646 mail_provider = "moemail"
25952647 # Prefer per-provider key; fall back to legacy api_key.
25962648 slot = _MAIL_PROVIDER_KEY_FIELDS .get (mail_provider , "moemail_api_key" )
25972649 api_key = str (cfg .get (slot ) or cfg .get ("api_key" ) or "" ).strip ()
25982650 moe_base = str (cfg .get ("moemail_base_url" ) or "" ).strip ().rstrip ("/" )
25992651 cf_base = str (cfg .get ("cfmail_base_url" ) or "" ).strip ().rstrip ("/" )
2652+ cm_base = str (cfg .get ("cloudmail_base_url" ) or "" ).strip ().rstrip ("/" )
26002653 if mail_provider == "yyds" :
26012654 base_url = "https://maliapi.215.im"
26022655 elif mail_provider == "gptmail" :
26032656 base_url = "https://mail.chatgpt.org.uk"
26042657 elif mail_provider == "cfmail" :
26052658 base_url = cf_base or str (cfg .get ("base_url" ) or "" ).strip ().rstrip ("/" )
2659+ elif mail_provider == "cloudmail" :
2660+ base_url = cm_base or str (cfg .get ("base_url" ) or "" ).strip ().rstrip ("/" )
26062661 else :
26072662 base_url = moe_base or str (cfg .get ("base_url" ) or "" ).strip ().rstrip ("/" )
26082663 dslot = _MAIL_PROVIDER_DOMAIN_FIELDS .get (mail_provider , "moemail_domain" )
@@ -2631,28 +2686,41 @@ def _set_env(name: str, value: str) -> None:
26312686 ykey = str (cfg .get ("yyds_api_key" ) or "" ).strip ()
26322687 gkey = str (cfg .get ("gptmail_api_key" ) or "" ).strip ()
26332688 ckey = str (cfg .get ("cfmail_api_key" ) or "" ).strip ()
2689+ cmkey = str (cfg .get ("cloudmail_api_key" ) or "" ).strip ()
26342690 _set_env ("GROK2API_MOEMAIL_ONLY_API_KEY" , mkey )
26352691 _set_env ("GROK2API_YYDS_API_KEY" , ykey )
26362692 _set_env ("YYDS_API_KEY" , ykey )
26372693 _set_env ("GROK2API_GPTMAIL_API_KEY" , gkey )
26382694 _set_env ("GPTMAIL_API_KEY" , gkey )
26392695 _set_env ("GROK2API_CFMAIL_API_KEY" , ckey )
26402696 _set_env ("CFMAIL_API_KEY" , ckey )
2641- # Keep MoeMail / CF hosts in dedicated env slots — never overwrite one with
2642- # the other when switching the active provider.
2697+ _set_env ("GROK2API_CLOUDMAIL_API_KEY" , cmkey )
2698+ _set_env ("CLOUDMAIL_API_KEY" , cmkey )
2699+ # Keep MoeMail / CF / Cloud Mail hosts in dedicated env slots — never
2700+ # overwrite one with the other when switching the active provider.
26432701 _set_env ("GROK2API_MOEMAIL_BASE_URL" , moe_base if mail_provider == "moemail" else moe_base )
26442702 _set_env ("GROK2API_CFMAIL_BASE_URL" , cf_base )
26452703 _set_env ("CFMAIL_BASE_URL" , cf_base )
2704+ _set_env ("GROK2API_CLOUDMAIL_BASE_URL" , cm_base )
2705+ _set_env ("CLOUDMAIL_BASE_URL" , cm_base )
26462706 if base_url :
26472707 # Active adapter host (helpers still read MOEMAIL_BASE_URL historically).
2648- _set_env ("GROK2API_MOEMAIL_BASE_URL" , base_url if mail_provider != "cfmail" else moe_base )
2708+ _set_env ("GROK2API_MOEMAIL_BASE_URL" , base_url if mail_provider not in { "cfmail" , "cloudmail" } else moe_base )
26492709 if mail_provider == "cfmail" :
26502710 _set_env ("GROK2API_CFMAIL_BASE_URL" , base_url )
26512711 _set_env ("CFMAIL_BASE_URL" , base_url )
26522712 # Active helpers fall back to MOEMAIL_BASE_URL — mirror CF host only
26532713 # while CF is selected so create/fetch hit the right Workers URL.
26542714 _set_env ("GROK2API_MOEMAIL_BASE_URL" , base_url )
26552715 _set_env ("MOEMAIL_BASE_URL" , base_url )
2716+ elif mail_provider == "cloudmail" :
2717+ _set_env ("GROK2API_CLOUDMAIL_BASE_URL" , base_url )
2718+ _set_env ("CLOUDMAIL_BASE_URL" , base_url )
2719+ # Active helpers fall back to MOEMAIL_BASE_URL — mirror Cloud Mail
2720+ # host only while Cloud Mail is selected so create/fetch hit the
2721+ # right Worker origin.
2722+ _set_env ("GROK2API_MOEMAIL_BASE_URL" , base_url )
2723+ _set_env ("MOEMAIL_BASE_URL" , base_url )
26562724 elif mail_provider == "moemail" :
26572725 _set_env ("MOEMAIL_BASE_URL" , base_url )
26582726 _set_env ("GROK2API_MOEMAIL_DOMAIN" , domain if mail_provider == "moemail" else str (cfg .get ("moemail_domain" ) or "" ).strip ())
@@ -2663,6 +2731,13 @@ def _set_env(name: str, value: str) -> None:
26632731 # Keep dedicated CF domain env in sync with stored slot even when inactive.
26642732 _set_env ("GROK2API_CFMAIL_DOMAIN" , str (cfg .get ("cfmail_domain" ) or "" ).strip ())
26652733 _set_env ("CFMAIL_DOMAIN" , str (cfg .get ("cfmail_domain" ) or "" ).strip ())
2734+ if mail_provider == "cloudmail" :
2735+ _set_env ("GROK2API_CLOUDMAIL_DOMAIN" , domain )
2736+ _set_env ("CLOUDMAIL_DOMAIN" , domain )
2737+ else :
2738+ # Keep dedicated Cloud Mail domain env in sync with stored slot even when inactive.
2739+ _set_env ("GROK2API_CLOUDMAIL_DOMAIN" , str (cfg .get ("cloudmail_domain" ) or "" ).strip ())
2740+ _set_env ("CLOUDMAIL_DOMAIN" , str (cfg .get ("cloudmail_domain" ) or "" ).strip ())
26662741 try :
26672742 probe_delay = int (cfg .get ("probe_delay_sec" , 30 ))
26682743 except (TypeError , ValueError ):
0 commit comments