tempemail-sdk 1.2.1__tar.gz → 1.2.2.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/PKG-INFO +4 -2
  2. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/README.md +3 -1
  3. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/pyproject.toml +1 -1
  4. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempemail_sdk.egg-info/PKG-INFO +4 -2
  5. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempemail_sdk.egg-info/SOURCES.txt +1 -0
  6. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/client.py +13 -6
  7. tempemail_sdk-1.2.2.dev0/tempmail_sdk/providers/tempmailg.py +197 -0
  8. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/types.py +1 -0
  9. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/setup.cfg +0 -0
  10. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempemail_sdk.egg-info/dependency_links.txt +0 -0
  11. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempemail_sdk.egg-info/requires.txt +0 -0
  12. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempemail_sdk.egg-info/top_level.txt +0 -0
  13. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/__init__.py +0 -0
  14. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/config.py +0 -0
  15. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/http.py +0 -0
  16. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/logger.py +0 -0
  17. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/normalize.py +0 -0
  18. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/__init__.py +0 -0
  19. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/anonbox.py +0 -0
  20. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/awamail.py +0 -0
  21. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/boomlify.py +0 -0
  22. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/chatgpt_org_uk.py +0 -0
  23. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/dropmail.py +0 -0
  24. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/emailnator.py +0 -0
  25. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/fake_legal.py +0 -0
  26. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/guerrillamail.py +0 -0
  27. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/linshi_email.py +0 -0
  28. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/linshi_token.py +0 -0
  29. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/linshiyou.py +0 -0
  30. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/mail_cx.py +0 -0
  31. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/mail_gw.py +0 -0
  32. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/mail_tm.py +0 -0
  33. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/maildrop.py +0 -0
  34. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/mffac.py +0 -0
  35. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/minmail.py +0 -0
  36. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/moakt.py +0 -0
  37. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/smail_pw.py +0 -0
  38. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/ta_easy.py +0 -0
  39. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/temp_mail_io.py +0 -0
  40. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/tempmail.py +0 -0
  41. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/tempmail_cn.py +0 -0
  42. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/tempmail_lol.py +0 -0
  43. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/temporary_email_org.py +0 -0
  44. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/tenmail_wangtz.py +0 -0
  45. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/tenminute_one.py +0 -0
  46. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/tmpmails.py +0 -0
  47. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/providers/vip_215.py +0 -0
  48. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/retry.py +0 -0
  49. {tempemail_sdk-1.2.1 → tempemail_sdk-1.2.2.dev0}/tempmail_sdk/telemetry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempemail-sdk
3
- Version: 1.2.1
3
+ Version: 1.2.2.dev0
4
4
  Summary: 临时邮箱 SDK,所有渠道返回统一标准化格式
5
5
  License: GPL-3.0
6
6
  Requires-Python: >=3.10
@@ -15,7 +15,7 @@ Requires-Dist: pygments>=2.19.2; extra == "dev"
15
15
 
16
16
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
17
17
 
18
- 临时邮箱 SDK(Python),支持 **25** 个邮箱服务提供商,顺序与 `client.py` 中 `ALL_CHANNELS` 一致,返回格式与根目录 README 描述一致(无 `tempmailg`,与 npm/Rust/C 一致)。
18
+ 临时邮箱 SDK(Python),支持 **27** 个邮箱服务提供商,顺序与 `client.py` 中 `ALL_CHANNELS` 一致,返回格式与根目录 README 描述一致,并与 Go / npm / Rust / C 对齐。
19
19
 
20
20
  ## 安装
21
21
 
@@ -34,8 +34,10 @@ pip install https://github.com/XxxXTeam/tempmail-sdk/releases/latest/download/te
34
34
  | `tempmail` | tempmail.ing | - | 支持自定义有效期 |
35
35
  | `tempmail-cn` | tempmail.cn | - | Socket.IO:`request shortid` / `set shortid` / `mail`;`GenerateEmailOptions.domain` 可指定自定义接入域名 |
36
36
  | `tmpmails` | tmpmails.com | ✅ | Next.js Server Action 收信;`domain` 可选语言路径 |
37
+ | `tempmailg` | tempmailg.com | ✅ | 独立 `requests.Session` 建邮;`GET /public/{locale}` + `POST /public/get_messages`;Token `tmg1:` + Base64(JSON);`domain` 可选语言路径 |
37
38
  | `ta-easy` | ta-easy.com | ✅ | REST `api-endpoint.ta-easy.com` |
38
39
  | `10mail-wangtz` | 10mail.wangtz.cn | - | REST `/api/tempMail`、`/api/emailList`;**默认跳过 TLS 证书校验** |
40
+ | `10minute-one` | 10minutemail.one | ✅ | SSR / JWT + Web API;`GenerateEmailOptions.domain` 可选 |
39
41
  | `linshi-email` | linshi-email.com | - | |
40
42
  | `linshiyou` | linshiyou.com | ✅ | `NEXUS_TOKEN` + Cookie;HTML 分段解析 |
41
43
  | `mffac` | mffac.com | ✅ | mailbox `id`;REST 24h |
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
4
4
 
5
- 临时邮箱 SDK(Python),支持 **25** 个邮箱服务提供商,顺序与 `client.py` 中 `ALL_CHANNELS` 一致,返回格式与根目录 README 描述一致(无 `tempmailg`,与 npm/Rust/C 一致)。
5
+ 临时邮箱 SDK(Python),支持 **27** 个邮箱服务提供商,顺序与 `client.py` 中 `ALL_CHANNELS` 一致,返回格式与根目录 README 描述一致,并与 Go / npm / Rust / C 对齐。
6
6
 
7
7
  ## 安装
8
8
 
@@ -21,8 +21,10 @@ pip install https://github.com/XxxXTeam/tempmail-sdk/releases/latest/download/te
21
21
  | `tempmail` | tempmail.ing | - | 支持自定义有效期 |
22
22
  | `tempmail-cn` | tempmail.cn | - | Socket.IO:`request shortid` / `set shortid` / `mail`;`GenerateEmailOptions.domain` 可指定自定义接入域名 |
23
23
  | `tmpmails` | tmpmails.com | ✅ | Next.js Server Action 收信;`domain` 可选语言路径 |
24
+ | `tempmailg` | tempmailg.com | ✅ | 独立 `requests.Session` 建邮;`GET /public/{locale}` + `POST /public/get_messages`;Token `tmg1:` + Base64(JSON);`domain` 可选语言路径 |
24
25
  | `ta-easy` | ta-easy.com | ✅ | REST `api-endpoint.ta-easy.com` |
25
26
  | `10mail-wangtz` | 10mail.wangtz.cn | - | REST `/api/tempMail`、`/api/emailList`;**默认跳过 TLS 证书校验** |
27
+ | `10minute-one` | 10minutemail.one | ✅ | SSR / JWT + Web API;`GenerateEmailOptions.domain` 可选 |
26
28
  | `linshi-email` | linshi-email.com | - | |
27
29
  | `linshiyou` | linshiyou.com | ✅ | `NEXUS_TOKEN` + Cookie;HTML 分段解析 |
28
30
  | `mffac` | mffac.com | ✅ | mailbox `id`;REST 24h |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tempemail-sdk"
7
- version = "1.2.01"
7
+ version = "1.2.02-dev"
8
8
  description = "临时邮箱 SDK,所有渠道返回统一标准化格式"
9
9
  readme = "README.md"
10
10
  license = {text = "GPL-3.0"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tempemail-sdk
3
- Version: 1.2.1
3
+ Version: 1.2.2.dev0
4
4
  Summary: 临时邮箱 SDK,所有渠道返回统一标准化格式
5
5
  License: GPL-3.0
6
6
  Requires-Python: >=3.10
@@ -15,7 +15,7 @@ Requires-Dist: pygments>=2.19.2; extra == "dev"
15
15
 
16
16
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
17
17
 
18
- 临时邮箱 SDK(Python),支持 **25** 个邮箱服务提供商,顺序与 `client.py` 中 `ALL_CHANNELS` 一致,返回格式与根目录 README 描述一致(无 `tempmailg`,与 npm/Rust/C 一致)。
18
+ 临时邮箱 SDK(Python),支持 **27** 个邮箱服务提供商,顺序与 `client.py` 中 `ALL_CHANNELS` 一致,返回格式与根目录 README 描述一致,并与 Go / npm / Rust / C 对齐。
19
19
 
20
20
  ## 安装
21
21
 
@@ -34,8 +34,10 @@ pip install https://github.com/XxxXTeam/tempmail-sdk/releases/latest/download/te
34
34
  | `tempmail` | tempmail.ing | - | 支持自定义有效期 |
35
35
  | `tempmail-cn` | tempmail.cn | - | Socket.IO:`request shortid` / `set shortid` / `mail`;`GenerateEmailOptions.domain` 可指定自定义接入域名 |
36
36
  | `tmpmails` | tmpmails.com | ✅ | Next.js Server Action 收信;`domain` 可选语言路径 |
37
+ | `tempmailg` | tempmailg.com | ✅ | 独立 `requests.Session` 建邮;`GET /public/{locale}` + `POST /public/get_messages`;Token `tmg1:` + Base64(JSON);`domain` 可选语言路径 |
37
38
  | `ta-easy` | ta-easy.com | ✅ | REST `api-endpoint.ta-easy.com` |
38
39
  | `10mail-wangtz` | 10mail.wangtz.cn | - | REST `/api/tempMail`、`/api/emailList`;**默认跳过 TLS 证书校验** |
40
+ | `10minute-one` | 10minutemail.one | ✅ | SSR / JWT + Web API;`GenerateEmailOptions.domain` 可选 |
39
41
  | `linshi-email` | linshi-email.com | - | |
40
42
  | `linshiyou` | linshiyou.com | ✅ | `NEXUS_TOKEN` + Cookie;HTML 分段解析 |
41
43
  | `mffac` | mffac.com | ✅ | mailbox `id`;REST 24h |
@@ -39,6 +39,7 @@ tempmail_sdk/providers/temp_mail_io.py
39
39
  tempmail_sdk/providers/tempmail.py
40
40
  tempmail_sdk/providers/tempmail_cn.py
41
41
  tempmail_sdk/providers/tempmail_lol.py
42
+ tempmail_sdk/providers/tempmailg.py
42
43
  tempmail_sdk/providers/temporary_email_org.py
43
44
  tempmail_sdk/providers/tenmail_wangtz.py
44
45
  tempmail_sdk/providers/tenminute_one.py
@@ -14,7 +14,7 @@ from .retry import with_retry, with_retry_with_attempts
14
14
  from .telemetry import report_telemetry
15
15
  from .logger import get_logger
16
16
  from .providers import (
17
- tempmail, tempmail_cn, tmpmails, ta_easy, tenmail_wangtz, linshi_email, linshiyou, mffac, tempmail_lol, chatgpt_org_uk,
17
+ tempmail, tempmail_cn, tmpmails, tempmailg, ta_easy, tenmail_wangtz, linshi_email, linshiyou, mffac, tempmail_lol, chatgpt_org_uk,
18
18
  temp_mail_io, awamail, temporary_email_org, mail_tm, mail_cx,
19
19
  dropmail, guerrillamail, maildrop, smail_pw,
20
20
  boomlify, minmail, vip_215, anonbox, fake_legal, moakt, tenminute_one,
@@ -22,10 +22,10 @@ from .providers import (
22
22
 
23
23
  # 所有支持的渠道列表
24
24
  ALL_CHANNELS = [
25
- "tempmail", "tempmail-cn", "tmpmails", "ta-easy", "10mail-wangtz", "linshi-email", "linshiyou", "mffac", "tempmail-lol", "chatgpt-org-uk",
25
+ "tempmail", "tempmail-cn", "tmpmails", "tempmailg", "ta-easy", "10mail-wangtz", "10minute-one", "linshi-email", "linshiyou", "mffac", "tempmail-lol", "chatgpt-org-uk",
26
26
  "temp-mail-io", "awamail", "temporary-email-org", "mail-tm", "mail-cx",
27
27
  "dropmail", "guerrillamail", "maildrop", "smail-pw",
28
- "boomlify", "minmail", "vip-215", "anonbox", "fake-legal", "moakt", "10minute-one",
28
+ "boomlify", "minmail", "vip-215", "anonbox", "fake-legal", "moakt",
29
29
  ]
30
30
 
31
31
  # 渠道信息映射表
@@ -33,8 +33,10 @@ CHANNEL_INFO_MAP = {
33
33
  "tempmail": ChannelInfo(channel="tempmail", name="TempMail", website="tempmail.ing"),
34
34
  "tempmail-cn": ChannelInfo(channel="tempmail-cn", name="TempMail CN", website="tempmail.cn"),
35
35
  "tmpmails": ChannelInfo(channel="tmpmails", name="TmpMails", website="tmpmails.com"),
36
+ "tempmailg": ChannelInfo(channel="tempmailg", name="TempMailG", website="tempmailg.com"),
36
37
  "ta-easy": ChannelInfo(channel="ta-easy", name="TA Easy", website="ta-easy.com"),
37
38
  "10mail-wangtz": ChannelInfo(channel="10mail-wangtz", name="10mail Wangtz", website="10mail.wangtz.cn"),
39
+ "10minute-one": ChannelInfo(channel="10minute-one", name="10 Minute Email", website="10minutemail.one"),
38
40
  "linshi-email": ChannelInfo(channel="linshi-email", name="临时邮箱", website="linshi-email.com"),
39
41
  "linshiyou": ChannelInfo(channel="linshiyou", name="临时邮", website="linshiyou.com"),
40
42
  "mffac": ChannelInfo(channel="mffac", name="MFFAC", website="mffac.com"),
@@ -55,7 +57,6 @@ CHANNEL_INFO_MAP = {
55
57
  "anonbox": ChannelInfo(channel="anonbox", name="Anonbox", website="anonbox.net"),
56
58
  "fake-legal": ChannelInfo(channel="fake-legal", name="Fake Legal", website="fake.legal"),
57
59
  "moakt": ChannelInfo(channel="moakt", name="Moakt", website="moakt.com"),
58
- "10minute-one": ChannelInfo(channel="10minute-one", name="10 Minute Email", website="10minutemail.one"),
59
60
  }
60
61
 
61
62
 
@@ -137,10 +138,14 @@ def _generate_email_once(channel: str, options: GenerateEmailOptions) -> EmailIn
137
138
  return tempmail_cn.generate_email(options.domain)
138
139
  elif channel == "tmpmails":
139
140
  return tmpmails.generate_email(options.domain)
141
+ elif channel == "tempmailg":
142
+ return tempmailg.generate_email(options.domain)
140
143
  elif channel == "ta-easy":
141
144
  return ta_easy.generate_email()
142
145
  elif channel == "10mail-wangtz":
143
146
  return tenmail_wangtz.generate_email(options.domain)
147
+ elif channel == "10minute-one":
148
+ return tenminute_one.generate_email(options.domain)
144
149
  elif channel == "linshi-email":
145
150
  return linshi_email.generate_email()
146
151
  elif channel == "linshiyou":
@@ -181,8 +186,6 @@ def _generate_email_once(channel: str, options: GenerateEmailOptions) -> EmailIn
181
186
  return fake_legal.generate_email(options.domain)
182
187
  elif channel == "moakt":
183
188
  return moakt.generate_email(options.domain)
184
- elif channel == "10minute-one":
185
- return tenminute_one.generate_email(options.domain)
186
189
  else:
187
190
  raise ValueError(f"Unknown channel: {channel}")
188
191
 
@@ -253,6 +256,10 @@ def _get_emails_once(channel: str, email: str, token: Optional[str]) -> List[Ema
253
256
  if not token:
254
257
  raise ValueError("token is required for tmpmails channel")
255
258
  return tmpmails.get_emails(email, token)
259
+ elif channel == "tempmailg":
260
+ if not token:
261
+ raise ValueError("token is required for tempmailg channel")
262
+ return tempmailg.get_emails(email, token)
256
263
  elif channel == "ta-easy":
257
264
  if not token:
258
265
  raise ValueError("token is required for ta-easy channel")
@@ -0,0 +1,197 @@
1
+ """
2
+ tempmailg.com:独立 Session GET /public/{locale} + POST get_messages;Token 为 tmg1: + base64(JSON)。
3
+ """
4
+
5
+ import base64
6
+ import json
7
+ import re
8
+ from typing import List, Optional
9
+
10
+ import requests
11
+ from urllib.parse import quote
12
+
13
+ from ..config import get_config
14
+ from ..normalize import normalize_email
15
+ from ..types import EmailInfo, Email
16
+
17
+ CHANNEL = "tempmailg"
18
+ ORIGIN = "https://tempmailg.com"
19
+ TOK_PREFIX = "tmg1:"
20
+
21
+ CSRF_RE = re.compile(r'<meta\s+name="csrf-token"\s+content="([^"]+)"', re.I)
22
+
23
+ _UA = (
24
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
25
+ "Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0"
26
+ )
27
+
28
+
29
+ def _ephemeral_session() -> requests.Session:
30
+ cfg = get_config()
31
+ s = requests.Session()
32
+ s.verify = not cfg.insecure
33
+ if cfg.proxy:
34
+ s.proxies = {"http": cfg.proxy, "https": cfg.proxy}
35
+ if cfg.headers:
36
+ s.headers.update(cfg.headers)
37
+ return s
38
+
39
+
40
+ def _locale(domain: Optional[str]) -> str:
41
+ s = (domain or "").strip()
42
+ if not s or any(c in s for c in "/?#\\"):
43
+ return "zh"
44
+ return s
45
+
46
+
47
+ def _cookie_map(hdr: str) -> dict:
48
+ m = {}
49
+ for part in hdr.split(";"):
50
+ p = part.strip()
51
+ if "=" in p:
52
+ k, v = p.split("=", 1)
53
+ k, v = k.strip(), v.strip()
54
+ if k:
55
+ m[k] = v
56
+ return m
57
+
58
+
59
+ def _cookie_hdr_from_map(m: dict) -> str:
60
+ return "; ".join(f"{k}={m[k]}" for k in sorted(m.keys()))
61
+
62
+
63
+ def _merge_set_cookies(prev: str, resp: requests.Response) -> str:
64
+ m = _cookie_map(prev)
65
+ for c in resp.cookies.items():
66
+ m[str(c[0])] = str(c[1])
67
+ return _cookie_hdr_from_map(m)
68
+
69
+
70
+ def _xsrf(cookie_hdr: str) -> str:
71
+ m = _cookie_map(cookie_hdr)
72
+ for key in ("XSRF-TOKEN", "xsrf-token"):
73
+ if key in m:
74
+ return m[key]
75
+ for k, v in m.items():
76
+ if k.lower() == "xsrf-token":
77
+ return v
78
+ return ""
79
+
80
+
81
+ def _parse_csrf(html: str) -> str:
82
+ m = CSRF_RE.search(html)
83
+ if not m or not (t := m.group(1).strip()):
84
+ raise RuntimeError("tempmailg: csrf-token not found in page")
85
+ return t
86
+
87
+
88
+ def _encode_token(locale: str, cookie_hdr: str, csrf: str) -> str:
89
+ raw = json.dumps({"l": locale, "c": cookie_hdr, "s": csrf}, separators=(",", ":"))
90
+ return TOK_PREFIX + base64.b64encode(raw.encode("utf-8")).decode("ascii")
91
+
92
+
93
+ def _decode_token(tok: str) -> dict:
94
+ if not tok.startswith(TOK_PREFIX):
95
+ raise ValueError("tempmailg: invalid session token")
96
+ raw = base64.b64decode(tok[len(TOK_PREFIX) :].encode("ascii")).decode("utf-8")
97
+ o = json.loads(raw)
98
+ if not o.get("c") or not o.get("s"):
99
+ raise ValueError("tempmailg: invalid session token")
100
+ return o
101
+
102
+
103
+ def generate_email(domain: Optional[str] = None, **kwargs) -> EmailInfo:
104
+ loc = _locale(domain)
105
+ page_url = f"{ORIGIN}/public/{quote(loc, safe='')}"
106
+ cfg = get_config()
107
+ timeout = cfg.timeout
108
+ s = _ephemeral_session()
109
+
110
+ r = s.get(
111
+ page_url,
112
+ headers={
113
+ "User-Agent": _UA,
114
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
115
+ "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
116
+ "Cache-Control": "no-cache",
117
+ "DNT": "1",
118
+ "Pragma": "no-cache",
119
+ "Referer": page_url,
120
+ "Upgrade-Insecure-Requests": "1",
121
+ },
122
+ timeout=timeout,
123
+ )
124
+ r.raise_for_status()
125
+ html = r.text
126
+ csrf = _parse_csrf(html)
127
+ cookie_hdr = _merge_set_cookies("", r)
128
+ xsrf = _xsrf(cookie_hdr)
129
+ if not xsrf:
130
+ raise RuntimeError("tempmailg: missing XSRF-TOKEN cookie")
131
+
132
+ post_url = f"{ORIGIN}/public/get_messages"
133
+ r2 = s.post(
134
+ post_url,
135
+ json={"_token": csrf},
136
+ headers={
137
+ "User-Agent": _UA,
138
+ "Accept": "application/json, text/plain, */*",
139
+ "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
140
+ "Content-Type": "application/json",
141
+ "Origin": ORIGIN,
142
+ "Referer": page_url,
143
+ "Cache-Control": "no-cache",
144
+ "Pragma": "no-cache",
145
+ "DNT": "1",
146
+ "Cookie": cookie_hdr,
147
+ "X-XSRF-TOKEN": xsrf,
148
+ },
149
+ timeout=timeout,
150
+ )
151
+ r2.raise_for_status()
152
+ wrap = r2.json()
153
+ if not wrap.get("status") or not wrap.get("mailbox"):
154
+ raise RuntimeError("tempmailg: create mailbox failed")
155
+ cookie_hdr = _merge_set_cookies(cookie_hdr, r2)
156
+ tok = _encode_token(loc, cookie_hdr, csrf)
157
+ return EmailInfo(channel=CHANNEL, email=wrap["mailbox"], _token=tok)
158
+
159
+
160
+ def get_emails(email: str, token: str) -> List[Email]:
161
+ o = _decode_token(token)
162
+ loc = o.get("l") or "zh"
163
+ page_url = f"{ORIGIN}/public/{quote(str(loc), safe='')}"
164
+ post_url = f"{ORIGIN}/public/get_messages"
165
+ cookie_hdr = str(o["c"])
166
+ xsrf = _xsrf(cookie_hdr)
167
+ cfg = get_config()
168
+
169
+ r = requests.post(
170
+ post_url,
171
+ json={"_token": o["s"]},
172
+ headers={
173
+ "User-Agent": _UA,
174
+ "Accept": "application/json, text/plain, */*",
175
+ "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
176
+ "Content-Type": "application/json",
177
+ "Origin": ORIGIN,
178
+ "Referer": page_url,
179
+ "Cache-Control": "no-cache",
180
+ "Pragma": "no-cache",
181
+ "DNT": "1",
182
+ "Cookie": cookie_hdr,
183
+ "X-XSRF-TOKEN": xsrf,
184
+ },
185
+ timeout=cfg.timeout,
186
+ verify=not cfg.insecure,
187
+ proxies={"http": cfg.proxy, "https": cfg.proxy} if cfg.proxy else None,
188
+ )
189
+ r.raise_for_status()
190
+ wrap = r.json()
191
+ if not wrap.get("status"):
192
+ raise RuntimeError("tempmailg: get_messages failed")
193
+ mb = (wrap.get("mailbox") or "").strip()
194
+ if mb and mb.lower() != email.strip().lower():
195
+ raise RuntimeError("tempmailg: mailbox mismatch")
196
+ messages = wrap.get("messages") or []
197
+ return [normalize_email(m, email) for m in messages if isinstance(m, dict)]
@@ -10,6 +10,7 @@ Channel = Literal[
10
10
  "tempmail",
11
11
  "tempmail-cn",
12
12
  "tmpmails",
13
+ "tempmailg",
13
14
  "ta-easy",
14
15
  "10mail-wangtz",
15
16
  "10minute-one",