tempmail_sdk 1.3.3 → 1.3.4

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tempmail_sdk/providers/altmails.rb +99 -0
  3. data/lib/tempmail_sdk/providers/apihz.rb +138 -0
  4. data/lib/tempmail_sdk/providers/awamail.rb +95 -0
  5. data/lib/tempmail_sdk/providers/best_temp_mail.rb +77 -0
  6. data/lib/tempmail_sdk/providers/chatgpt_org_uk.rb +129 -0
  7. data/lib/tempmail_sdk/providers/disposablemail.rb +125 -0
  8. data/lib/tempmail_sdk/providers/disposablemail_app.rb +66 -0
  9. data/lib/tempmail_sdk/providers/email10min.rb +152 -0
  10. data/lib/tempmail_sdk/providers/emailnator.rb +132 -0
  11. data/lib/tempmail_sdk/providers/emailtemp_org.rb +131 -0
  12. data/lib/tempmail_sdk/providers/expressinboxhub.rb +118 -0
  13. data/lib/tempmail_sdk/providers/fakemail.rb +143 -0
  14. data/lib/tempmail_sdk/providers/haribu.rb +29 -3
  15. data/lib/tempmail_sdk/providers/linshiyouxiang_net.rb +85 -0
  16. data/lib/tempmail_sdk/providers/mail_sunls.rb +42 -1
  17. data/lib/tempmail_sdk/providers/mail_td.rb +161 -0
  18. data/lib/tempmail_sdk/providers/mailcat_ai.rb +52 -0
  19. data/lib/tempmail_sdk/providers/maildrop.rb +79 -4
  20. data/lib/tempmail_sdk/providers/mailgolem.rb +96 -0
  21. data/lib/tempmail_sdk/providers/mailinator.rb +9 -2
  22. data/lib/tempmail_sdk/providers/mailtemp_cc.rb +91 -0
  23. data/lib/tempmail_sdk/providers/minuteinbox.rb +174 -0
  24. data/lib/tempmail_sdk/providers/moakt.rb +29 -3
  25. data/lib/tempmail_sdk/providers/mohmal.rb +208 -0
  26. data/lib/tempmail_sdk/providers/mytempmail_cc.rb +76 -0
  27. data/lib/tempmail_sdk/providers/openinbox.rb +102 -0
  28. data/lib/tempmail_sdk/providers/smail_pw.rb +156 -0
  29. data/lib/tempmail_sdk/providers/socketio_mail.rb +25 -0
  30. data/lib/tempmail_sdk/providers/tempgbox.rb +118 -0
  31. data/lib/tempmail_sdk/providers/tempmail_cn.rb +111 -0
  32. data/lib/tempmail_sdk/providers/tenminutemail_net.rb +183 -0
  33. data/lib/tempmail_sdk/providers/twentyfourmail_chacuo.rb +83 -0
  34. data/lib/tempmail_sdk/providers/vip_215.rb +171 -0
  35. data/lib/tempmail_sdk/registry.rb +163 -1
  36. data/lib/tempmail_sdk/version.rb +1 -1
  37. metadata +30 -2
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # mytempmail.cc 渠道实现
8
+ #
9
+ # 流程:POST /api/address 创建邮箱(JSON body),返回 token + address
10
+ # GET /api/mails/{token} 获取邮件列表
11
+ # 域名固定 nilvaro.com,有效期 600 秒
12
+ module MytempmailCc
13
+ CHANNEL = "mytempmail-cc"
14
+ BASE_URL = "https://api.mytempmail.cc"
15
+
16
+ HEADERS = {
17
+ "Content-Type" => "application/json",
18
+ "Accept" => "application/json"
19
+ }.freeze
20
+
21
+ CHARS = ("a".."z").to_a.freeze
22
+
23
+ module_function
24
+
25
+ # 生成随机 8 位小写字母用户名
26
+ # @return [String]
27
+ def random_name
28
+ Array.new(8) { CHARS.sample }.join
29
+ end
30
+
31
+ # 创建 mytempmail.cc 临时邮箱
32
+ # @return [EmailInfo]
33
+ def generate_email
34
+ body = JSON.generate("domain" => "nilvaro.com", "name" => random_name, "expiry" => 600)
35
+ resp = Http.post(BASE_URL + "/api/address", headers: HEADERS, body: body, timeout: 15)
36
+ resp.raise_for_status
37
+ data = resp.json
38
+ email = data["address"].to_s.strip
39
+ token = data["token"].to_s.strip
40
+ raise "mytempmail-cc: 无效的邮箱响应" if email.empty? || !email.include?("@")
41
+ raise "mytempmail-cc: 响应中缺少 token" if token.empty?
42
+
43
+ EmailInfo.new(channel: CHANNEL, email: email, token: token)
44
+ end
45
+
46
+ # 获取 mytempmail.cc 邮件列表
47
+ # @param token [String]
48
+ # @param email [String]
49
+ # @return [Array<Email>]
50
+ def get_emails(token, email)
51
+ token = token.to_s.strip
52
+ raise "mytempmail-cc: token 为空" if token.empty?
53
+
54
+ resp = Http.get("#{BASE_URL}/api/mails/#{token}", headers: HEADERS, timeout: 15)
55
+ resp.raise_for_status
56
+ data = resp.json
57
+ results = data.is_a?(Hash) ? Array(data["results"]) : []
58
+
59
+ results.filter_map do |msg|
60
+ next unless msg.is_a?(Hash)
61
+
62
+ flat = {
63
+ "id" => msg["id"],
64
+ "from" => msg["from"],
65
+ "to" => email,
66
+ "subject" => msg["subject"],
67
+ "text" => msg["body_text"],
68
+ "html" => msg["body_html"],
69
+ "received_at" => msg["received_at"]
70
+ }
71
+ Normalize.normalize_email(flat, email)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # openinbox.io 渠道实现
8
+ #
9
+ # 流程:POST /api/inbox 创建邮箱,返回 id + email
10
+ # GET /api/emails/inbox/{id}?page=1&limit=50 获取邮件列表
11
+ # GET /api/emails/{messageId} 获取邮件详情
12
+ # token 存储 inbox id
13
+ module Openinbox
14
+ CHANNEL = "openinbox"
15
+ BASE_URL = "https://api.openinbox.io/api"
16
+
17
+ HEADERS = {
18
+ "Accept" => "application/json, text/plain, */*",
19
+ "Origin" => "https://openinbox.io",
20
+ "Referer" => "https://openinbox.io/",
21
+ "User-Agent" => "Mozilla/5.0"
22
+ }.freeze
23
+
24
+ module_function
25
+
26
+ # 发起 JSON 请求
27
+ # @param method [String] "GET" 或 "POST"
28
+ # @param url [String]
29
+ # @return [Object] 解析后的 JSON
30
+ def json_request(method, url)
31
+ hdrs = HEADERS.dup
32
+ hdrs["Content-Type"] = "application/json" if method == "POST"
33
+ resp = method == "POST" ? Http.post(url, headers: hdrs, timeout: 15) : Http.get(url, headers: hdrs, timeout: 15)
34
+ resp.raise_for_status
35
+ resp.json
36
+ end
37
+
38
+ # 将邮件 raw map 展平为标准字段
39
+ # @param raw [Hash]
40
+ # @param recipient [String]
41
+ # @return [Hash]
42
+ def flatten(raw, recipient)
43
+ {
44
+ "id" => raw["id"],
45
+ "from" => raw["from"],
46
+ "to" => recipient,
47
+ "subject" => raw["subject"],
48
+ "text" => raw["textBody"],
49
+ "html" => raw["htmlBody"],
50
+ "receivedAt" => raw["receivedAt"],
51
+ "isRead" => raw["isRead"],
52
+ "attachments" => []
53
+ }
54
+ end
55
+
56
+ # 创建 openinbox.io 临时邮箱
57
+ # @return [EmailInfo]
58
+ def generate_email
59
+ data = json_request("POST", BASE_URL + "/inbox")
60
+ id = data["id"].to_s.strip
61
+ email = data["email"].to_s.strip
62
+ raise "openinbox: 无效的邮箱响应" if id.empty? || email.empty? || !email.include?("@")
63
+
64
+ EmailInfo.new(channel: CHANNEL, email: email, token: id)
65
+ end
66
+
67
+ # 获取 openinbox.io 邮件列表
68
+ # @param inbox_id [String] inbox id(token)
69
+ # @param email [String]
70
+ # @return [Array<Email>]
71
+ def get_emails(inbox_id, email)
72
+ inbox_id = inbox_id.to_s.strip
73
+ raise "openinbox: empty inbox id" if inbox_id.empty?
74
+
75
+ url = "#{BASE_URL}/emails/inbox/#{URI.encode_uri_component(inbox_id)}?page=1&limit=50"
76
+ data = json_request("GET", url)
77
+ rows = data.is_a?(Hash) ? Array(data["emails"]) : []
78
+
79
+ rows.filter_map do |row|
80
+ next unless row.is_a?(Hash)
81
+
82
+ raw = row
83
+ msg_id = row["id"].to_s.strip
84
+ unless msg_id.empty?
85
+ detail = fetch_detail(msg_id)
86
+ raw = detail if detail.is_a?(Hash)
87
+ end
88
+ Normalize.normalize_email(flatten(raw, email), email)
89
+ end
90
+ end
91
+
92
+ # 获取单封邮件详情
93
+ # @param message_id [String]
94
+ # @return [Hash, nil]
95
+ def fetch_detail(message_id)
96
+ json_request("GET", "#{BASE_URL}/emails/#{URI.encode_uri_component(message_id)}")
97
+ rescue StandardError
98
+ nil
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "uri"
5
+
6
+ module TempmailSdk
7
+ module Providers
8
+ # smail.pw 渠道实现
9
+ #
10
+ # 流程:POST /_root.data body: intent=generate 创建邮箱,保存 __session cookie
11
+ # GET /_root.data + Cookie 获取邮件列表(解析 React Flight 格式或正则提取)
12
+ # GET /api/email/{id} 获取单封邮件正文
13
+ # token 存储 __session=xxx cookie 字符串
14
+ module SmailPw
15
+ CHANNEL = "smail-pw"
16
+ ROOT_DATA_URL = "https://smail.pw/_root.data"
17
+
18
+ HEADERS = {
19
+ "Accept" => "*/*",
20
+ "accept-language" => "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
21
+ "cache-control" => "no-cache",
22
+ "dnt" => "1",
23
+ "origin" => "https://smail.pw",
24
+ "pragma" => "no-cache",
25
+ "referer" => "https://smail.pw/",
26
+ "sec-fetch-dest" => "empty",
27
+ "sec-fetch-mode" => "cors",
28
+ "sec-fetch-site" => "same-origin",
29
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
30
+ "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0"
31
+ }.freeze
32
+
33
+ QUOTED_INBOX_RE = /"([a-z0-9][a-z0-9.\-]*@smail\.pw)"/i
34
+ PLAIN_INBOX_RE = /\b([a-z0-9][a-z0-9.\-]*@smail\.pw)\b/i
35
+ MAIL_BLOCK_RE = /"id","([^"]+)","to_address","([^"]*)","from_name","([^"]*)","from_address","([^"]*)","subject","([^"]*)","time",(\d+)/
36
+ MAIL_BLOCK2_RE = /"id","([^"]+)","from_name","([^"]*)","from_address","([^"]*)","subject","([^"]*)","time",(\d+)/
37
+
38
+ module_function
39
+
40
+ # 从响应 Set-Cookie 中提取 __session cookie
41
+ # @param set_cookie_lines [Array<String>]
42
+ # @return [String]
43
+ def extract_session(set_cookie_lines)
44
+ set_cookie_lines.each do |line|
45
+ pair = line.split(";", 2).first.to_s.strip
46
+ return pair if pair.start_with?("__session=")
47
+ end
48
+ ""
49
+ end
50
+
51
+ # 从响应体中提取邮箱地址
52
+ # @param body [String]
53
+ # @return [String]
54
+ def extract_inbox(body)
55
+ m = body.match(QUOTED_INBOX_RE)
56
+ return m[1] if m
57
+
58
+ m = body.match(PLAIN_INBOX_RE)
59
+ m ? m[1] : ""
60
+ end
61
+
62
+ # 从响应体解析邮件列表
63
+ # @param body [String]
64
+ # @param recipient [String]
65
+ # @return [Array<Hash>]
66
+ def parse_mails(body, recipient)
67
+ out = []
68
+ body.scan(MAIL_BLOCK_RE) do |id, to_addr, from_name, from_addr, subj, ts|
69
+ out << {
70
+ "id" => id, "to_address" => to_addr.empty? ? recipient : to_addr,
71
+ "from_name" => from_name, "from_address" => from_addr,
72
+ "subject" => subj, "date" => ts.to_f,
73
+ "text" => "", "html" => "", "attachments" => []
74
+ }
75
+ end
76
+ return out unless out.empty?
77
+
78
+ body.scan(MAIL_BLOCK2_RE) do |id, from_name, from_addr, subj, ts|
79
+ out << {
80
+ "id" => id, "to_address" => recipient,
81
+ "from_name" => from_name, "from_address" => from_addr,
82
+ "subject" => subj, "date" => ts.to_f,
83
+ "text" => "", "html" => "", "attachments" => []
84
+ }
85
+ end
86
+ out
87
+ end
88
+
89
+ # 创建 smail.pw 临时邮箱
90
+ # @return [EmailInfo]
91
+ def generate_email
92
+ resp = Http.post(
93
+ ROOT_DATA_URL,
94
+ headers: HEADERS.merge("Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"),
95
+ body: "intent=generate",
96
+ timeout: 15
97
+ )
98
+ raise "smail.pw generate failed: #{resp.status_code}" unless resp.ok?
99
+
100
+ cookie = extract_session(resp.set_cookies)
101
+ raise "smail.pw: 未能提取 __session cookie" if cookie.empty?
102
+
103
+ email = extract_inbox(resp.body)
104
+ raise "smail.pw: 未能解析邮箱地址" if email.empty?
105
+
106
+ EmailInfo.new(channel: CHANNEL, email: email, token: cookie)
107
+ end
108
+
109
+ # 获取 smail.pw 邮件列表
110
+ # @param token [String] __session=xxx cookie 字符串
111
+ # @param email [String]
112
+ # @return [Array<Email>]
113
+ def get_emails(token, email)
114
+ resp = Http.get(
115
+ ROOT_DATA_URL,
116
+ headers: HEADERS.merge("Cookie" => token),
117
+ timeout: 15
118
+ )
119
+ raise "smail.pw get emails failed: #{resp.status_code}" unless resp.ok?
120
+
121
+ mails = parse_mails(resp.body, email)
122
+ return [] if mails.empty?
123
+
124
+ mails.map do |m|
125
+ ne = Normalize.normalize_email(m, email)
126
+ id = m["id"].to_s
127
+ unless id.empty?
128
+ body_html = fetch_body(token, id)
129
+ ne.html = body_html unless body_html.empty?
130
+ end
131
+ ne
132
+ end
133
+ end
134
+
135
+ # 获取单封邮件正文
136
+ # @param token [String]
137
+ # @param id [String]
138
+ # @return [String]
139
+ def fetch_body(token, id)
140
+ return "" if id.empty?
141
+
142
+ resp = Http.get(
143
+ "https://smail.pw/api/email/#{URI.encode_uri_component(id)}",
144
+ headers: HEADERS.merge("Cookie" => token, "Accept" => "application/json"),
145
+ timeout: 15
146
+ )
147
+ return "" unless resp.ok?
148
+
149
+ data = resp.json
150
+ data.is_a?(Hash) ? data["body"].to_s : ""
151
+ rescue StandardError
152
+ ""
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TempmailSdk
4
+ module Providers
5
+ # socketio-mail 渠道桩实现
6
+ #
7
+ # 该渠道依赖 WebSocket/Socket.IO 协议,Ruby 标准 HTTP 客户端无法实现。
8
+ # 当前注册为桩,调用时抛出 NotImplementedProviderError。
9
+ module SocketioMail
10
+ CHANNEL = "socketio-mail"
11
+
12
+ module_function
13
+
14
+ # @raise [NotImplementedError]
15
+ def generate_email
16
+ raise NotImplementedProviderError, "channel not implemented yet: #{CHANNEL}"
17
+ end
18
+
19
+ # @raise [NotImplementedError]
20
+ def get_emails(_email, _token)
21
+ raise NotImplementedProviderError, "channel not implemented yet: #{CHANNEL}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # tempgbox.net 渠道实现
8
+ #
9
+ # 流程:POST /api/proxy?route=generate 创建邮箱(JSON body,X-Device-ID 头)
10
+ # POST /api/proxy?route=inbox 获取邮件列表
11
+ # 响应体为 HTML 页面,实际数据编码在 data-x 属性(base64 JSON)
12
+ # token 存储 device_id
13
+ module Tempgbox
14
+ CHANNEL = "tempgbox"
15
+ API_URL = "https://tempgbox.net/api/proxy"
16
+
17
+ module_function
18
+
19
+ # 生成随机 64 位十六进制 device id
20
+ # @return [String]
21
+ def random_device_id
22
+ require "securerandom"
23
+ SecureRandom.hex(32)
24
+ end
25
+
26
+ # 生成随机 IP 地址
27
+ # @return [String]
28
+ def random_ip
29
+ "#{rand(1..254)}.#{rand(1..254)}.#{rand(1..254)}.#{rand(1..254)}"
30
+ end
31
+
32
+ # 构造请求头
33
+ # @param device_id [String]
34
+ # @return [Hash]
35
+ def build_headers(device_id)
36
+ ip = random_ip
37
+ {
38
+ "Accept" => "text/html,application/json",
39
+ "Content-Type" => "application/json",
40
+ "Origin" => "https://tempgbox.net",
41
+ "Referer" => "https://tempgbox.net/",
42
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
43
+ "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
44
+ "X-Device-ID" => device_id,
45
+ "X-Forwarded-For" => ip,
46
+ "X-Real-IP" => ip,
47
+ "X-Originating-IP" => ip
48
+ }
49
+ end
50
+
51
+ # 从响应 HTML 中解码 data-x 属性(base64 JSON)
52
+ # @param body [String]
53
+ # @return [Hash]
54
+ def decode_payload(body)
55
+ require "base64"
56
+ m = body.match(/data-x=["']([^"']+)["']/)
57
+ raise "tempgbox: 响应中缺少 data-x 属性" unless m
58
+
59
+ raw = Base64.strict_decode64(m[1])
60
+ JSON.parse(raw)
61
+ end
62
+
63
+ # 发起 POST 请求并解码响应
64
+ # @param route [String]
65
+ # @param device_id [String]
66
+ # @param body [Hash]
67
+ # @return [Hash]
68
+ def post_route(route, device_id, body)
69
+ resp = Http.post(
70
+ "#{API_URL}?route=#{route}",
71
+ headers: build_headers(device_id),
72
+ body: JSON.generate(body),
73
+ timeout: 15
74
+ )
75
+ resp.raise_for_status
76
+ decode_payload(resp.body)
77
+ end
78
+
79
+ # 创建 tempgbox.net 临时邮箱
80
+ # @return [EmailInfo]
81
+ def generate_email
82
+ device_id = random_device_id
83
+ payload = post_route("generate", device_id, "variant" => "googlemail")
84
+ alias_data = payload["alias"]
85
+ raise "tempgbox: 响应缺少 alias" unless alias_data.is_a?(Hash)
86
+
87
+ email = alias_data["email"].to_s.strip
88
+ email = alias_data["alias"].to_s.strip if email.empty?
89
+ raise "tempgbox: 响应缺少 email" if email.empty?
90
+
91
+ EmailInfo.new(channel: CHANNEL, email: email, token: device_id)
92
+ end
93
+
94
+ # 获取 tempgbox.net 邮件列表
95
+ # @param device_id [String] token
96
+ # @param email [String]
97
+ # @return [Array<Email>]
98
+ def get_emails(device_id, email)
99
+ raise "tempgbox: missing device id" if device_id.to_s.strip.empty?
100
+
101
+ payload = post_route("inbox", device_id, "email" => email)
102
+ messages = Array(payload["messages"])
103
+
104
+ messages.filter_map do |raw|
105
+ next unless raw.is_a?(Hash)
106
+
107
+ raw["from"] ||= raw["sender"]
108
+ raw["text"] ||= raw["body_text"]
109
+ raw["html"] ||= raw["body_html"]
110
+ raw["date"] ||= raw["received_at"]
111
+ raw["messageId"] ||= raw["message_id"]
112
+ raw["attachments"] ||= raw["attachments_info"]
113
+ Normalize.normalize_email(raw.merge("to" => email), email)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "json"
5
+
6
+ module TempmailSdk
7
+ module Providers
8
+ # tempmail.cn 渠道实现(HTTP API 模式)
9
+ #
10
+ # 流程:WebSocket 创建邮箱(request mailbox 事件),获取 shortID
11
+ # GET /api/mails/{email} 获取邮件列表(HTTP API)
12
+ # Ruby 端使用 HTTP API 拉取邮件,不实现 WebSocket 推送
13
+ # token 不需要(无状态 HTTP API)
14
+ module TempmailCn
15
+ CHANNEL = "tempmail-cn"
16
+ DEFAULT_HOST = "tempmail.cn"
17
+
18
+ module_function
19
+
20
+ # 规范化 host(去除协议前缀、路径、@ 符号等)
21
+ # @param domain [String, nil]
22
+ # @return [String]
23
+ def normalize_host(domain)
24
+ return DEFAULT_HOST if domain.nil? || domain.to_s.strip.empty?
25
+
26
+ host = domain.to_s.strip
27
+ if host.start_with?("http://", "https://")
28
+ begin
29
+ uri = URI.parse(host)
30
+ host = uri.host.to_s unless uri.host.to_s.empty?
31
+ rescue URI::InvalidURIError
32
+ nil
33
+ end
34
+ elsif host.include?("/")
35
+ host = host.split("/").first.to_s
36
+ end
37
+ host = host.split("@").last.to_s if host.include?("@")
38
+ host = host.strip.gsub(/\A\.+|\.+\z/, "")
39
+ host.empty? ? DEFAULT_HOST : host
40
+ end
41
+
42
+ # 生成随机本地部分(小写字母 + 数字)
43
+ # @param length [Integer]
44
+ # @return [String]
45
+ def random_local(length = 10)
46
+ chars = ("a".."z").to_a + ("0".."9").to_a
47
+ Array.new(length) { chars.sample }.join
48
+ end
49
+
50
+ # 创建 tempmail.cn 临时邮箱
51
+ # @param domain [String, nil]
52
+ # @return [EmailInfo]
53
+ def generate_email(domain = nil)
54
+ host = normalize_host(domain)
55
+ # 直接生成随机邮箱(HTTP 模式,不走 WebSocket)
56
+ email = "#{random_local}@#{host}"
57
+ EmailInfo.new(channel: CHANNEL, email: email)
58
+ end
59
+
60
+ # 获取 tempmail.cn 邮件列表
61
+ # @param email [String]
62
+ # @return [Array<Email>]
63
+ def get_emails(email)
64
+ email = email.to_s.strip
65
+ raise "tempmail-cn: 邮箱地址为空" if email.empty?
66
+
67
+ at_idx = email.index("@")
68
+ host = at_idx ? email[(at_idx + 1)..] : DEFAULT_HOST
69
+ host = normalize_host(host)
70
+
71
+ api_url = "https://#{host}/api/mails/#{URI.encode_uri_component(email)}"
72
+ hdrs = {
73
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
74
+ "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0",
75
+ "Accept" => "application/json",
76
+ "Accept-Language" => "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
77
+ "Cache-Control" => "no-cache",
78
+ "DNT" => "1",
79
+ "Pragma" => "no-cache",
80
+ "Referer" => "https://#{host}/"
81
+ }
82
+
83
+ resp = Http.get(api_url, headers: hdrs, timeout: 15)
84
+ resp.raise_for_status
85
+
86
+ data = resp.json
87
+ mails = data.is_a?(Hash) ? Array(data["mails"]) : []
88
+
89
+ mails.filter_map do |raw|
90
+ next unless raw.is_a?(Hash)
91
+
92
+ id = raw["id"].to_s
93
+ id = raw["_id"].to_s if id.empty?
94
+ flat = {
95
+ "id" => id,
96
+ "from" => raw["from"].to_s,
97
+ "to" => email,
98
+ "subject" => raw["subject"].to_s,
99
+ "text" => raw["text"].to_s,
100
+ "html" => raw["html"].to_s,
101
+ "date" => raw["date"].to_s,
102
+ "isRead" => false,
103
+ "attachments" => raw["attachments"]
104
+ }
105
+ flat["text"] = raw["body"].to_s if flat["text"].empty?
106
+ Normalize.normalize_email(flat, email)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end