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.
- checksums.yaml +4 -4
- data/lib/tempmail_sdk/providers/altmails.rb +99 -0
- data/lib/tempmail_sdk/providers/apihz.rb +138 -0
- data/lib/tempmail_sdk/providers/awamail.rb +95 -0
- data/lib/tempmail_sdk/providers/best_temp_mail.rb +77 -0
- data/lib/tempmail_sdk/providers/chatgpt_org_uk.rb +129 -0
- data/lib/tempmail_sdk/providers/disposablemail.rb +125 -0
- data/lib/tempmail_sdk/providers/disposablemail_app.rb +66 -0
- data/lib/tempmail_sdk/providers/email10min.rb +152 -0
- data/lib/tempmail_sdk/providers/emailnator.rb +132 -0
- data/lib/tempmail_sdk/providers/emailtemp_org.rb +131 -0
- data/lib/tempmail_sdk/providers/expressinboxhub.rb +118 -0
- data/lib/tempmail_sdk/providers/fakemail.rb +143 -0
- data/lib/tempmail_sdk/providers/haribu.rb +29 -3
- data/lib/tempmail_sdk/providers/linshiyouxiang_net.rb +85 -0
- data/lib/tempmail_sdk/providers/mail_sunls.rb +42 -1
- data/lib/tempmail_sdk/providers/mail_td.rb +161 -0
- data/lib/tempmail_sdk/providers/mailcat_ai.rb +52 -0
- data/lib/tempmail_sdk/providers/maildrop.rb +79 -4
- data/lib/tempmail_sdk/providers/mailgolem.rb +96 -0
- data/lib/tempmail_sdk/providers/mailinator.rb +9 -2
- data/lib/tempmail_sdk/providers/mailtemp_cc.rb +91 -0
- data/lib/tempmail_sdk/providers/minuteinbox.rb +174 -0
- data/lib/tempmail_sdk/providers/moakt.rb +29 -3
- data/lib/tempmail_sdk/providers/mohmal.rb +208 -0
- data/lib/tempmail_sdk/providers/mytempmail_cc.rb +76 -0
- data/lib/tempmail_sdk/providers/openinbox.rb +102 -0
- data/lib/tempmail_sdk/providers/smail_pw.rb +156 -0
- data/lib/tempmail_sdk/providers/socketio_mail.rb +25 -0
- data/lib/tempmail_sdk/providers/tempgbox.rb +118 -0
- data/lib/tempmail_sdk/providers/tempmail_cn.rb +111 -0
- data/lib/tempmail_sdk/providers/tenminutemail_net.rb +183 -0
- data/lib/tempmail_sdk/providers/twentyfourmail_chacuo.rb +83 -0
- data/lib/tempmail_sdk/providers/vip_215.rb +171 -0
- data/lib/tempmail_sdk/registry.rb +163 -1
- data/lib/tempmail_sdk/version.rb +1 -1
- metadata +30 -2
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
module TempmailSdk
|
|
6
|
+
module Providers
|
|
7
|
+
# 10minutemail.net 渠道实现
|
|
8
|
+
#
|
|
9
|
+
# 流程:GET / 获取 PHPSESSID session cookie + 从 HTML 输入框提取邮箱地址
|
|
10
|
+
# GET /mailbox.ajax.php?_={毫秒时间戳} 获取邮件列表(HTML 表格)
|
|
11
|
+
# GET /readmail.html?mid={id} 获取单封邮件正文
|
|
12
|
+
# token 为空字符串(session 由 cookie jar 自动维护)
|
|
13
|
+
module TenminutemailNet
|
|
14
|
+
CHANNEL = "10minutemail-net"
|
|
15
|
+
BASE_URL = "https://10minutemail.net"
|
|
16
|
+
|
|
17
|
+
EMAIL_RE = /value="([^"]+@[^"]+)"/
|
|
18
|
+
ROW_RE = /<tr[^>]*>(.*?)<\/tr>/im
|
|
19
|
+
MID_RE = /readmail\.html\?mid=([^'"&]+)/i
|
|
20
|
+
CELL_RE = /<td[^>]*>(.*?)<\/td>/im
|
|
21
|
+
TITLE_RE = /title="([^"]+)"/i
|
|
22
|
+
CF_RE = /data-cfemail="([0-9a-fA-F]+)"/i
|
|
23
|
+
TAG_RE = /<[^>]+>/
|
|
24
|
+
BODY_MARK = 'class="mailinhtml"'
|
|
25
|
+
|
|
26
|
+
BROWSER_HEADERS = {
|
|
27
|
+
"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
|
|
28
|
+
"(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0",
|
|
29
|
+
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif," \
|
|
30
|
+
"image/webp,image/apng,*/*;q=0.8",
|
|
31
|
+
"Accept-Language" => "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7"
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
AJAX_HEADERS = BROWSER_HEADERS.merge(
|
|
35
|
+
"Accept" => "*/*",
|
|
36
|
+
"X-Requested-With" => "XMLHttpRequest",
|
|
37
|
+
"Referer" => BASE_URL + "/"
|
|
38
|
+
).freeze
|
|
39
|
+
|
|
40
|
+
module_function
|
|
41
|
+
|
|
42
|
+
# 解码 Cloudflare 邮箱保护混淆字符串
|
|
43
|
+
# @param encoded [String] 十六进制字符串
|
|
44
|
+
# @return [String]
|
|
45
|
+
def cf_decode(encoded)
|
|
46
|
+
data = [encoded].pack("H*")
|
|
47
|
+
return "" if data.length < 2
|
|
48
|
+
|
|
49
|
+
key = data.getbyte(0)
|
|
50
|
+
out = data.bytes[1..].map { |b| b ^ key }.pack("C*")
|
|
51
|
+
out.include?("@") ? out : ""
|
|
52
|
+
rescue StandardError
|
|
53
|
+
""
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# 从单元格 HTML 提取纯文本(优先解码 CF 混淆)
|
|
57
|
+
# @param cell [String]
|
|
58
|
+
# @return [String]
|
|
59
|
+
def extract_text(cell)
|
|
60
|
+
if (m = cell.match(CF_RE))
|
|
61
|
+
decoded = cf_decode(m[1])
|
|
62
|
+
return decoded unless decoded.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
text = cell.gsub(TAG_RE, "")
|
|
66
|
+
text = text.gsub(" ", " ").gsub(" ", " ")
|
|
67
|
+
.gsub("&", "&").gsub("<", "<")
|
|
68
|
+
.gsub(">", ">").gsub(""", '"')
|
|
69
|
+
text.strip
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# 从整页 HTML 提取 mailinhtml div 正文
|
|
73
|
+
# @param page [String]
|
|
74
|
+
# @return [String]
|
|
75
|
+
def extract_body(page)
|
|
76
|
+
si = page.index(BODY_MARK)
|
|
77
|
+
return "" unless si
|
|
78
|
+
|
|
79
|
+
gt = page.index(">", si)
|
|
80
|
+
return "" unless gt
|
|
81
|
+
|
|
82
|
+
content_start = gt + 1
|
|
83
|
+
rest = page[content_start..]
|
|
84
|
+
|
|
85
|
+
ei = rest.index("email-decode.min.js")
|
|
86
|
+
segment = if ei
|
|
87
|
+
s = rest[0...ei]
|
|
88
|
+
s = s[0...s.rindex("<script")] if s.rindex("<script")
|
|
89
|
+
s.strip.sub(/<\/div>\s*\z/, "").strip.sub(/<\/div>\s*\z/, "").strip
|
|
90
|
+
else
|
|
91
|
+
di = rest.index("</div>")
|
|
92
|
+
di ? rest[0...di].strip : rest.strip
|
|
93
|
+
end
|
|
94
|
+
segment
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# 创建 10minutemail.net 临时邮箱
|
|
98
|
+
# @return [EmailInfo]
|
|
99
|
+
def generate_email
|
|
100
|
+
resp = Http.get(BASE_URL + "/", headers: BROWSER_HEADERS, timeout: 15)
|
|
101
|
+
resp.raise_for_status
|
|
102
|
+
m = resp.body.match(EMAIL_RE)
|
|
103
|
+
raise "10minutemail-net: 未能从首页提取邮箱地址" unless m
|
|
104
|
+
|
|
105
|
+
email = m[1].strip
|
|
106
|
+
raise "10minutemail-net: 获取到的邮箱地址无效" if email.empty? || !email.include?("@")
|
|
107
|
+
|
|
108
|
+
EmailInfo.new(channel: CHANNEL, email: email, token: "")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# 获取 10minutemail.net 邮件列表
|
|
112
|
+
# @param email [String]
|
|
113
|
+
# @param token [String] 未使用(session 由 cookie jar 维护)
|
|
114
|
+
# @return [Array<Email>]
|
|
115
|
+
def get_emails(email, token)
|
|
116
|
+
_ = token
|
|
117
|
+
ts = (Time.now.to_f * 1000).to_i
|
|
118
|
+
list_url = "#{BASE_URL}/mailbox.ajax.php?_=#{ts}"
|
|
119
|
+
resp = Http.get(list_url, headers: AJAX_HEADERS, timeout: 15)
|
|
120
|
+
resp.raise_for_status
|
|
121
|
+
|
|
122
|
+
rows = resp.body.scan(ROW_RE)
|
|
123
|
+
emails = []
|
|
124
|
+
rows.each do |row_inner_arr|
|
|
125
|
+
row_inner = row_inner_arr[0]
|
|
126
|
+
next if row_inner.downcase.include?("<th")
|
|
127
|
+
|
|
128
|
+
mid_m = row_inner.match(MID_RE)
|
|
129
|
+
next unless mid_m
|
|
130
|
+
|
|
131
|
+
mail_id = mid_m[1].strip
|
|
132
|
+
next if mail_id.empty?
|
|
133
|
+
|
|
134
|
+
cells = row_inner.scan(CELL_RE).map { |c| c[0] }
|
|
135
|
+
from_cell = cells[0] || ""
|
|
136
|
+
subject_cell = cells[1] || ""
|
|
137
|
+
date_cell = cells[2] || ""
|
|
138
|
+
|
|
139
|
+
from = extract_text(from_cell)
|
|
140
|
+
subject = extract_text(subject_cell)
|
|
141
|
+
date = if (tm = date_cell.match(TITLE_RE))
|
|
142
|
+
tm[1].strip
|
|
143
|
+
else
|
|
144
|
+
extract_text(date_cell)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# 未读行的 <tr> 样式含 font-weight: bold
|
|
148
|
+
full_row = "<tr#{row_inner}</tr>"
|
|
149
|
+
is_read = !full_row.downcase.include?("font-weight: bold")
|
|
150
|
+
|
|
151
|
+
html_body = fetch_body(mail_id)
|
|
152
|
+
|
|
153
|
+
flat = {
|
|
154
|
+
"id" => mail_id, "from" => from, "to" => email,
|
|
155
|
+
"subject" => subject, "html" => html_body,
|
|
156
|
+
"date" => date, "isRead" => is_read
|
|
157
|
+
}
|
|
158
|
+
emails << Normalize.normalize_email(flat, email)
|
|
159
|
+
end
|
|
160
|
+
emails
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# 获取单封邮件正文
|
|
164
|
+
# @param mail_id [String]
|
|
165
|
+
# @return [String]
|
|
166
|
+
def fetch_body(mail_id)
|
|
167
|
+
return "" if mail_id.empty?
|
|
168
|
+
|
|
169
|
+
url = "#{BASE_URL}/readmail.html?mid=#{mail_id}"
|
|
170
|
+
resp = Http.get(
|
|
171
|
+
url,
|
|
172
|
+
headers: BROWSER_HEADERS.merge("Referer" => BASE_URL + "/"),
|
|
173
|
+
timeout: 15
|
|
174
|
+
)
|
|
175
|
+
return "" unless resp.status_code == 200
|
|
176
|
+
|
|
177
|
+
extract_body(resp.body)
|
|
178
|
+
rescue StandardError
|
|
179
|
+
""
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "uri"
|
|
5
|
+
|
|
6
|
+
module TempmailSdk
|
|
7
|
+
module Providers
|
|
8
|
+
# 24mail.chacuo.net 渠道实现
|
|
9
|
+
# POST / 同一接口用于注册和收信,HTTP only
|
|
10
|
+
module TwentyfourmailChacuo
|
|
11
|
+
CHANNEL = "24mail-chacuo"
|
|
12
|
+
BASE_URL = "http://24mail.chacuo.net"
|
|
13
|
+
DOMAINS = %w[chacuo.net 027168.com].freeze
|
|
14
|
+
|
|
15
|
+
HEADERS = {
|
|
16
|
+
"Accept" => "application/json, text/javascript, */*; q=0.01",
|
|
17
|
+
"Accept-Language" => "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
18
|
+
"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8",
|
|
19
|
+
"Origin" => BASE_URL,
|
|
20
|
+
"Referer" => "#{BASE_URL}/",
|
|
21
|
+
"User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
|
|
22
|
+
"(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0",
|
|
23
|
+
"x-requested-with" => "XMLHttpRequest"
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
def random_local(length = 10)
|
|
29
|
+
chars = ("a".."z").to_a + ("0".."9").to_a
|
|
30
|
+
Array.new(length) { chars.sample }.join
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# 创建 24mail-chacuo 临时邮箱
|
|
34
|
+
# @return [EmailInfo]
|
|
35
|
+
def generate_email
|
|
36
|
+
name = random_local(10)
|
|
37
|
+
domain = DOMAINS.sample
|
|
38
|
+
body = "data=#{URI.encode_www_form_component("#{name}@#{domain}")}&type=refresh&arg="
|
|
39
|
+
resp = Http.post(BASE_URL + "/", headers: HEADERS, body: body, timeout: 15)
|
|
40
|
+
resp.raise_for_status
|
|
41
|
+
data = JSON.parse(resp.body)
|
|
42
|
+
raise "24mail-chacuo: 创建失败 status=#{data["status"]} info=#{data["info"]}" unless data["status"] == 1
|
|
43
|
+
|
|
44
|
+
email = "#{name}@#{domain}"
|
|
45
|
+
EmailInfo.new(channel: CHANNEL, email: email, token: email)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# 获取 24mail-chacuo 邮件列表
|
|
49
|
+
# @param email [String]
|
|
50
|
+
# @return [Array<Email>]
|
|
51
|
+
def get_emails(email)
|
|
52
|
+
addr = email.to_s.strip
|
|
53
|
+
raise "24mail-chacuo: 邮箱地址为空" if addr.empty?
|
|
54
|
+
|
|
55
|
+
at_idx = addr.index("@")
|
|
56
|
+
name = at_idx ? addr[0...at_idx] : addr
|
|
57
|
+
domain = at_idx ? addr[at_idx + 1..] : DOMAINS[0]
|
|
58
|
+
|
|
59
|
+
body = "data=#{URI.encode_www_form_component("#{name}@#{domain}")}&type=refresh&arg="
|
|
60
|
+
resp = Http.post(BASE_URL + "/", headers: HEADERS, body: body, timeout: 15)
|
|
61
|
+
resp.raise_for_status
|
|
62
|
+
data = JSON.parse(resp.body)
|
|
63
|
+
return [] unless data["status"] == 1 && data["data"].is_a?(Array) && !data["data"].empty?
|
|
64
|
+
|
|
65
|
+
list = data["data"][0]["list"]
|
|
66
|
+
return [] unless list.is_a?(Array)
|
|
67
|
+
|
|
68
|
+
list.map do |item|
|
|
69
|
+
flat = {
|
|
70
|
+
"id" => item["MID"],
|
|
71
|
+
"from" => item["FROM"],
|
|
72
|
+
"to" => addr,
|
|
73
|
+
"subject" => item["SUBJECT"],
|
|
74
|
+
"body" => item["CONTENT"],
|
|
75
|
+
"date" => item["TIME"],
|
|
76
|
+
"isRead" => false
|
|
77
|
+
}
|
|
78
|
+
Normalize.normalize_email(flat, addr)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "cgi"
|
|
6
|
+
|
|
7
|
+
module TempmailSdk
|
|
8
|
+
module Providers
|
|
9
|
+
# vip.215.im 渠道实现
|
|
10
|
+
# 流程:GET / 取首页 cookie → POST /api/temp-inbox 创建邮箱(得到 address + token)
|
|
11
|
+
# GET /v1/messages 拉取邮件列表(HTTP 优先)
|
|
12
|
+
# GET /v1/messages/{id} 补拉单封详情
|
|
13
|
+
# token 为 JWT,用于后续 API 鉴权
|
|
14
|
+
module Vip215
|
|
15
|
+
CHANNEL = "vip-215"
|
|
16
|
+
BASE = "https://vip.215.im"
|
|
17
|
+
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
|
|
18
|
+
"(KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
|
|
19
|
+
|
|
20
|
+
HOME_HEADERS = {
|
|
21
|
+
"User-Agent" => UA,
|
|
22
|
+
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
23
|
+
"Accept-Language" => "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
24
|
+
"Cache-Control" => "no-cache",
|
|
25
|
+
"DNT" => "1",
|
|
26
|
+
"Pragma" => "no-cache",
|
|
27
|
+
"Sec-Fetch-Dest" => "document",
|
|
28
|
+
"Sec-Fetch-Mode" => "navigate",
|
|
29
|
+
"Sec-Fetch-Site" => "same-origin",
|
|
30
|
+
"Upgrade-Insecure-Requests" => "1"
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
API_HEADERS = {
|
|
34
|
+
"User-Agent" => UA,
|
|
35
|
+
"Accept" => "*/*",
|
|
36
|
+
"Accept-Language" => "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
37
|
+
"Cache-Control" => "no-cache",
|
|
38
|
+
"Content-Type" => "application/json",
|
|
39
|
+
"DNT" => "1",
|
|
40
|
+
"Origin" => BASE,
|
|
41
|
+
"Pragma" => "no-cache",
|
|
42
|
+
"Referer" => "#{BASE}/",
|
|
43
|
+
"Sec-Fetch-Dest" => "empty",
|
|
44
|
+
"Sec-Fetch-Mode" => "cors",
|
|
45
|
+
"Sec-Fetch-Site" => "same-origin",
|
|
46
|
+
"X-Locale" => "zh"
|
|
47
|
+
}.freeze
|
|
48
|
+
|
|
49
|
+
module_function
|
|
50
|
+
|
|
51
|
+
# 合并 Set-Cookie 响应头到 cookie 字符串
|
|
52
|
+
def merge_cookies(existing, set_cookie_lines)
|
|
53
|
+
map = {}
|
|
54
|
+
existing.to_s.split(";").each do |part|
|
|
55
|
+
part = part.strip
|
|
56
|
+
next unless part.include?("=")
|
|
57
|
+
|
|
58
|
+
k, v = part.split("=", 2)
|
|
59
|
+
map[k.strip] = v.to_s.strip unless k.strip.empty?
|
|
60
|
+
end
|
|
61
|
+
set_cookie_lines.each do |line|
|
|
62
|
+
pair = line.split(";", 2).first.to_s.strip
|
|
63
|
+
next unless pair.include?("=")
|
|
64
|
+
|
|
65
|
+
k, v = pair.split("=", 2)
|
|
66
|
+
map[k.strip] = v.to_s.strip unless k.strip.empty?
|
|
67
|
+
end
|
|
68
|
+
map.map { |k, v| "#{k}=#{v}" }.join("; ")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# 访问首页获取必要 cookie(yyds_homepage_bridge / yyds_homepage_device)
|
|
72
|
+
def establish_session
|
|
73
|
+
resp = Http.get(BASE + "/", headers: HOME_HEADERS, timeout: 15)
|
|
74
|
+
resp.raise_for_status
|
|
75
|
+
cookie = merge_cookies("", resp.set_cookies)
|
|
76
|
+
raise "vip-215: 缺少首页 cookie" unless cookie.include?("yyds_homepage_bridge=") &&
|
|
77
|
+
cookie.include?("yyds_homepage_device=")
|
|
78
|
+
|
|
79
|
+
cookie
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# 创建 vip-215 临时邮箱
|
|
83
|
+
# @return [EmailInfo]
|
|
84
|
+
def generate_email
|
|
85
|
+
cookie = establish_session
|
|
86
|
+
resp = Http.post(
|
|
87
|
+
BASE + "/api/temp-inbox",
|
|
88
|
+
headers: API_HEADERS.merge("Cookie" => cookie),
|
|
89
|
+
body: "",
|
|
90
|
+
timeout: 15
|
|
91
|
+
)
|
|
92
|
+
resp.raise_for_status
|
|
93
|
+
data = JSON.parse(resp.body)
|
|
94
|
+
raise "vip-215: 创建失败" unless data["success"] && data["data"]
|
|
95
|
+
|
|
96
|
+
address = data["data"]["address"].to_s.strip
|
|
97
|
+
token = data["data"]["token"].to_s.strip
|
|
98
|
+
raise "vip-215: 响应缺少 address 或 token" if address.empty? || token.empty?
|
|
99
|
+
|
|
100
|
+
EmailInfo.new(channel: CHANNEL, email: address, token: token)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# 判断邮件条目是否已含真实正文
|
|
104
|
+
def has_real_body?(row)
|
|
105
|
+
%w[text body_text html body_html content body].any? do |key|
|
|
106
|
+
v = row[key]
|
|
107
|
+
v.is_a?(String) && !v.strip.empty?
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# 提取邮件 ID
|
|
112
|
+
def extract_message_id(row)
|
|
113
|
+
%w[id messageId message_id].each do |key|
|
|
114
|
+
v = row[key]
|
|
115
|
+
next if v.nil?
|
|
116
|
+
return v.to_s.strip if v.is_a?(String) && !v.strip.empty?
|
|
117
|
+
return v.to_i.to_s if v.is_a?(Numeric)
|
|
118
|
+
end
|
|
119
|
+
""
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# 补拉单封邮件详情
|
|
123
|
+
def fetch_message_detail(token, id)
|
|
124
|
+
mid = id.to_s.strip
|
|
125
|
+
return nil if mid.empty?
|
|
126
|
+
|
|
127
|
+
resp = Http.get(
|
|
128
|
+
"#{BASE}/v1/messages/#{URI.encode_www_form_component(mid)}",
|
|
129
|
+
headers: API_HEADERS.merge("Authorization" => "Bearer #{token}"),
|
|
130
|
+
timeout: 15
|
|
131
|
+
)
|
|
132
|
+
return nil unless resp.status_code == 200
|
|
133
|
+
|
|
134
|
+
parsed = JSON.parse(resp.body)
|
|
135
|
+
return nil unless parsed["success"] && parsed["data"].is_a?(Hash)
|
|
136
|
+
|
|
137
|
+
parsed["data"]
|
|
138
|
+
rescue StandardError
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# 获取 vip-215 邮件列表(HTTP GET /v1/messages)
|
|
143
|
+
# @param token [String] JWT
|
|
144
|
+
# @param email [String]
|
|
145
|
+
# @return [Array<Email>]
|
|
146
|
+
def get_emails(token, email)
|
|
147
|
+
raise "vip-215: token 为空" if token.to_s.strip.empty?
|
|
148
|
+
|
|
149
|
+
resp = Http.get(
|
|
150
|
+
BASE + "/v1/messages",
|
|
151
|
+
headers: API_HEADERS.merge("Authorization" => "Bearer #{token}"),
|
|
152
|
+
timeout: 15
|
|
153
|
+
)
|
|
154
|
+
resp.raise_for_status
|
|
155
|
+
parsed = JSON.parse(resp.body)
|
|
156
|
+
raise "vip-215: messages success=false" unless parsed["success"]
|
|
157
|
+
|
|
158
|
+
messages = parsed.dig("data", "messages") || []
|
|
159
|
+
messages.map do |row|
|
|
160
|
+
id = extract_message_id(row)
|
|
161
|
+
unless has_real_body?(row) || id.empty?
|
|
162
|
+
detail = fetch_message_detail(token, id)
|
|
163
|
+
row = row.merge(detail) if detail
|
|
164
|
+
end
|
|
165
|
+
row["to"] ||= email
|
|
166
|
+
Normalize.normalize_email(row, email)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
@@ -31,7 +31,21 @@ module TempmailSdk
|
|
|
31
31
|
TempmailLolV2: "tempmail_lol_v2", Tempmailpro: "tempmailpro", Tempmailten: "tempmailten",
|
|
32
32
|
TempMails: "tempp_mails", TenMinuteMailNet: "ten_minute_mail_net",
|
|
33
33
|
Throwawaymail: "throwawaymail", TmailLink: "tmail_link",
|
|
34
|
-
Uncorreotemporal: "uncorreotemporal", Webmailtemp: "webmailtemp", XkxMe: "xkx_me"
|
|
34
|
+
Uncorreotemporal: "uncorreotemporal", Webmailtemp: "webmailtemp", XkxMe: "xkx_me",
|
|
35
|
+
Altmails: "altmails", Apihz: "apihz", Awamail: "awamail", BestTempMail: "best_temp_mail",
|
|
36
|
+
ChatgptOrgUk: "chatgpt_org_uk", Disposablemail: "disposablemail",
|
|
37
|
+
DisposablemailApp: "disposablemail_app", Email10min: "email10min",
|
|
38
|
+
Emailnator: "emailnator", EmailtempOrg: "emailtemp_org",
|
|
39
|
+
Expressinboxhub: "expressinboxhub", Fakemail: "fakemail",
|
|
40
|
+
LinshiyouxiangNet: "linshiyouxiang_net", MailTd: "mail_td",
|
|
41
|
+
TempmailCn: "tempmail_cn", Linshiyou: "linshiyou", Mailnesia: "mailnesia",
|
|
42
|
+
Dropmail: "dropmail", SmailPw: "smail_pw", Vip215: "vip_215",
|
|
43
|
+
Tempgbox: "tempgbox", Anonbox: "anonbox", Eyepaste: "eyepaste",
|
|
44
|
+
Lroid: "lroid", Haribu: "haribu", Mohmal: "mohmal", Mailgolem: "mailgolem",
|
|
45
|
+
MytempmailCc: "mytempmail_cc", MailtempCc: "mailtemp_cc", Minuteinbox: "minuteinbox",
|
|
46
|
+
Mailcatch: "mailcatch", MaildropCc: "maildrop_cc", TenminutemailNet: "tenminutemail_net",
|
|
47
|
+
Openinbox: "openinbox", MailcatAi: "mailcat_ai", DropmailMe: "dropmail_me",
|
|
48
|
+
TwentyfourmailChacuo: "twentyfourmail_chacuo"
|
|
35
49
|
}.freeze
|
|
36
50
|
|
|
37
51
|
PROVIDER_AUTOLOADS.each do |mod_name, file|
|
|
@@ -1070,6 +1084,154 @@ module TempmailSdk
|
|
|
1070
1084
|
generate: ->(_o) { p::XkxMe.generate_email },
|
|
1071
1085
|
get_emails: ->(e, t) { p::XkxMe.get_emails(require_token(t, "xkx-me"), e) }
|
|
1072
1086
|
},
|
|
1087
|
+
"tempmail-cn" => {
|
|
1088
|
+
generate: ->(o) { p::TempmailCn.generate_email(o.domain) },
|
|
1089
|
+
get_emails: ->(e, _t) { p::TempmailCn.get_emails(e) }
|
|
1090
|
+
},
|
|
1091
|
+
"linshiyou" => {
|
|
1092
|
+
generate: ->(_o) { p::Linshiyou.generate_email },
|
|
1093
|
+
get_emails: ->(e, t) { p::Linshiyou.get_emails(require_token(t, "linshiyou"), e) }
|
|
1094
|
+
},
|
|
1095
|
+
"mailnesia" => {
|
|
1096
|
+
generate: ->(_o) { p::Mailnesia.generate_email },
|
|
1097
|
+
get_emails: ->(e, _t) { p::Mailnesia.get_emails(e) }
|
|
1098
|
+
},
|
|
1099
|
+
"dropmail" => {
|
|
1100
|
+
generate: ->(_o) { p::Dropmail.generate_email },
|
|
1101
|
+
get_emails: ->(e, t) { p::Dropmail.get_emails(require_token(t, "dropmail"), e) }
|
|
1102
|
+
},
|
|
1103
|
+
"smail-pw" => {
|
|
1104
|
+
generate: ->(_o) { p::SmailPw.generate_email },
|
|
1105
|
+
get_emails: ->(e, t) { p::SmailPw.get_emails(require_token(t, "smail-pw"), e) }
|
|
1106
|
+
},
|
|
1107
|
+
"vip-215" => {
|
|
1108
|
+
generate: ->(_o) { p::Vip215.generate_email },
|
|
1109
|
+
get_emails: ->(e, t) { p::Vip215.get_emails(require_token(t, "vip-215"), e) }
|
|
1110
|
+
},
|
|
1111
|
+
"tempgbox" => {
|
|
1112
|
+
generate: ->(_o) { p::Tempgbox.generate_email },
|
|
1113
|
+
get_emails: ->(e, t) { p::Tempgbox.get_emails(require_token(t, "tempgbox"), e) }
|
|
1114
|
+
},
|
|
1115
|
+
"emailnator" => {
|
|
1116
|
+
generate: ->(_o) { p::Emailnator.generate_email },
|
|
1117
|
+
get_emails: ->(e, t) { p::Emailnator.get_emails(e, require_token(t, "emailnator")) }
|
|
1118
|
+
},
|
|
1119
|
+
"anonbox" => {
|
|
1120
|
+
generate: ->(_o) { p::Anonbox.generate_email },
|
|
1121
|
+
get_emails: ->(e, t) { p::Anonbox.get_emails(require_token(t, "anonbox"), e) }
|
|
1122
|
+
},
|
|
1123
|
+
"eyepaste" => {
|
|
1124
|
+
generate: ->(_o) { p::Eyepaste.generate_email },
|
|
1125
|
+
get_emails: ->(e, _t) { p::Eyepaste.get_emails(e) }
|
|
1126
|
+
},
|
|
1127
|
+
"lroid" => {
|
|
1128
|
+
generate: ->(_o) { p::Lroid.generate_email },
|
|
1129
|
+
get_emails: ->(e, t) { p::Lroid.get_emails(require_token(t, "lroid"), e) }
|
|
1130
|
+
},
|
|
1131
|
+
"haribu" => {
|
|
1132
|
+
generate: ->(_o) { p::Haribu.generate_email },
|
|
1133
|
+
get_emails: ->(e, t) { p::Haribu.get_emails(require_token(t, "haribu"), e) }
|
|
1134
|
+
},
|
|
1135
|
+
"mohmal" => {
|
|
1136
|
+
generate: ->(_o) { p::Mohmal.generate_email },
|
|
1137
|
+
get_emails: ->(e, t) { p::Mohmal.get_emails(e, require_token(t, "mohmal")) }
|
|
1138
|
+
},
|
|
1139
|
+
"mailgolem" => {
|
|
1140
|
+
generate: ->(_o) { p::Mailgolem.generate_email },
|
|
1141
|
+
get_emails: ->(e, t) { p::Mailgolem.get_emails(e, require_token(t, "mailgolem")) }
|
|
1142
|
+
},
|
|
1143
|
+
"best-temp-mail" => {
|
|
1144
|
+
generate: ->(_o) { p::BestTempMail.generate_email },
|
|
1145
|
+
get_emails: ->(e, t) { p::BestTempMail.get_emails(e, require_token(t, "best-temp-mail")) }
|
|
1146
|
+
},
|
|
1147
|
+
"disposablemail-app" => {
|
|
1148
|
+
generate: ->(_o) { p::DisposablemailApp.generate_email },
|
|
1149
|
+
get_emails: ->(e, t) { p::DisposablemailApp.get_emails(e, require_token(t, "disposablemail-app")) }
|
|
1150
|
+
},
|
|
1151
|
+
"mailtemp-cc" => {
|
|
1152
|
+
generate: ->(_o) { p::MailtempCc.generate_email },
|
|
1153
|
+
get_emails: ->(e, t) { p::MailtempCc.get_emails(e, require_token(t, "mailtemp-cc")) }
|
|
1154
|
+
},
|
|
1155
|
+
"minuteinbox" => {
|
|
1156
|
+
generate: ->(_o) { p::Minuteinbox.generate_email },
|
|
1157
|
+
get_emails: ->(e, t) { p::Minuteinbox.get_emails(require_token(t, "minuteinbox"), e) }
|
|
1158
|
+
},
|
|
1159
|
+
"mailcatch" => {
|
|
1160
|
+
generate: ->(_o) { p::Mailcatch.generate_email },
|
|
1161
|
+
get_emails: ->(e, t) { p::Mailcatch.get_emails(e, require_token(t, "mailcatch")) }
|
|
1162
|
+
},
|
|
1163
|
+
"altmails" => {
|
|
1164
|
+
generate: ->(_o) { p::Altmails.generate_email },
|
|
1165
|
+
get_emails: ->(e, t) { p::Altmails.get_emails(e, require_token(t, "altmails")) }
|
|
1166
|
+
},
|
|
1167
|
+
"maildrop-cc" => {
|
|
1168
|
+
generate: ->(_o) { p::MaildropCc.generate_email },
|
|
1169
|
+
get_emails: ->(e, t) { p::MaildropCc.get_emails(e, t || "") }
|
|
1170
|
+
},
|
|
1171
|
+
"10minutemail-net" => {
|
|
1172
|
+
generate: ->(_o) { p::TenminutemailNet.generate_email },
|
|
1173
|
+
get_emails: ->(e, t) { p::TenminutemailNet.get_emails(e, require_token(t, "10minutemail-net")) }
|
|
1174
|
+
},
|
|
1175
|
+
"linshiyouxiang-net" => {
|
|
1176
|
+
generate: ->(_o) { p::LinshiyouxiangNet.generate_email },
|
|
1177
|
+
get_emails: ->(e, t) { p::LinshiyouxiangNet.get_emails(e, require_token(t, "linshiyouxiang-net")) }
|
|
1178
|
+
},
|
|
1179
|
+
"disposablemail-com" => {
|
|
1180
|
+
generate: ->(_o) { p::Disposablemail.generate_email },
|
|
1181
|
+
get_emails: ->(e, t) { p::Disposablemail.get_emails(e, require_token(t, "disposablemail-com")) }
|
|
1182
|
+
},
|
|
1183
|
+
"emailtemp-org" => {
|
|
1184
|
+
generate: ->(_o) { p::EmailtempOrg.generate_email },
|
|
1185
|
+
get_emails: ->(e, t) { p::EmailtempOrg.get_emails(e, require_token(t, "emailtemp-org")) }
|
|
1186
|
+
},
|
|
1187
|
+
"mytempmail-cc" => {
|
|
1188
|
+
generate: ->(_o) { p::MytempmailCc.generate_email },
|
|
1189
|
+
get_emails: ->(e, t) { p::MytempmailCc.get_emails(require_token(t, "mytempmail-cc"), e) }
|
|
1190
|
+
},
|
|
1191
|
+
"mail-td" => {
|
|
1192
|
+
generate: ->(_o) { p::MailTd.generate_email },
|
|
1193
|
+
get_emails: ->(e, t) { p::MailTd.get_emails(require_token(t, "mail-td"), e) }
|
|
1194
|
+
},
|
|
1195
|
+
"24mail-chacuo" => {
|
|
1196
|
+
generate: ->(_o) { p::TwentyfourmailChacuo.generate_email },
|
|
1197
|
+
get_emails: ->(e, _t) { p::TwentyfourmailChacuo.get_emails(e) }
|
|
1198
|
+
},
|
|
1199
|
+
"apihz" => {
|
|
1200
|
+
generate: ->(_o) { p::Apihz.generate_email },
|
|
1201
|
+
get_emails: ->(_e, t) { p::Apihz.get_emails(require_token(t, "apihz")) }
|
|
1202
|
+
},
|
|
1203
|
+
"mailcat-ai" => {
|
|
1204
|
+
generate: ->(_o) { p::MailcatAi.generate_email },
|
|
1205
|
+
get_emails: ->(e, t) { p::MailcatAi.get_emails(require_token(t, "mailcat-ai"), e) }
|
|
1206
|
+
},
|
|
1207
|
+
"dropmail-me" => {
|
|
1208
|
+
generate: ->(_o) { p::DropmailMe.generate_email },
|
|
1209
|
+
get_emails: ->(e, t) { p::DropmailMe.get_emails(require_token(t, "dropmail-me"), e) }
|
|
1210
|
+
},
|
|
1211
|
+
"openinbox" => {
|
|
1212
|
+
generate: ->(_o) { p::Openinbox.generate_email },
|
|
1213
|
+
get_emails: ->(e, t) { p::Openinbox.get_emails(require_token(t, "openinbox"), e) }
|
|
1214
|
+
},
|
|
1215
|
+
"chatgpt-org-uk" => {
|
|
1216
|
+
generate: ->(_o) { p::ChatgptOrgUk.generate_email },
|
|
1217
|
+
get_emails: ->(e, t) { p::ChatgptOrgUk.get_emails(e, require_token(t, "chatgpt-org-uk")) }
|
|
1218
|
+
},
|
|
1219
|
+
"expressinboxhub" => {
|
|
1220
|
+
generate: ->(_o) { p::Expressinboxhub.generate_email },
|
|
1221
|
+
get_emails: ->(e, t) { p::Expressinboxhub.get_emails(e, require_token(t, "expressinboxhub")) }
|
|
1222
|
+
},
|
|
1223
|
+
"fakemail" => {
|
|
1224
|
+
generate: ->(_o) { p::Fakemail.generate_email },
|
|
1225
|
+
get_emails: ->(e, t) { p::Fakemail.get_emails(require_token(t, "fakemail"), e) }
|
|
1226
|
+
},
|
|
1227
|
+
"awamail" => {
|
|
1228
|
+
generate: ->(_o) { p::Awamail.generate_email },
|
|
1229
|
+
get_emails: ->(e, t) { p::Awamail.get_emails(require_token(t, "awamail"), e) }
|
|
1230
|
+
},
|
|
1231
|
+
"email10min" => {
|
|
1232
|
+
generate: ->(_o) { p::Email10min.generate_email },
|
|
1233
|
+
get_emails: ->(e, t) { p::Email10min.get_emails(e, require_token(t, "email10min")) }
|
|
1234
|
+
},
|
|
1073
1235
|
}
|
|
1074
1236
|
end
|
|
1075
1237
|
|
data/lib/tempmail_sdk/version.rb
CHANGED