tempmail_sdk 1.3.4 → 1.3.5

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/tempmail_sdk/channels.rb +29 -7
  4. data/lib/tempmail_sdk/channels_data.rb +29 -7
  5. data/lib/tempmail_sdk/providers/clawdemail.rb +122 -0
  6. data/lib/tempmail_sdk/providers/crazymailing.rb +114 -0
  7. data/lib/tempmail_sdk/providers/firetempmail.rb +86 -0
  8. data/lib/tempmail_sdk/providers/flybymail.rb +93 -0
  9. data/lib/tempmail_sdk/providers/generator_email.rb +146 -0
  10. data/lib/tempmail_sdk/providers/huskmail.rb +132 -0
  11. data/lib/tempmail_sdk/providers/internxt.rb +176 -0
  12. data/lib/tempmail_sdk/providers/linshi_xyz.rb +79 -0
  13. data/lib/tempmail_sdk/providers/mailmomy.rb +1 -1
  14. data/lib/tempmail_sdk/providers/mailticking.rb +139 -0
  15. data/lib/tempmail_sdk/providers/mtempmail.rb +140 -0
  16. data/lib/tempmail_sdk/providers/nowtempmail.rb +112 -0
  17. data/lib/tempmail_sdk/providers/noxen_de5_net.rb +392 -0
  18. data/lib/tempmail_sdk/providers/nukemail.rb +188 -0
  19. data/lib/tempmail_sdk/providers/nullmail.rb +95 -0
  20. data/lib/tempmail_sdk/providers/shadowmail.rb +174 -0
  21. data/lib/tempmail_sdk/providers/shitpost_email.rb +85 -0
  22. data/lib/tempmail_sdk/providers/smails.rb +128 -0
  23. data/lib/tempmail_sdk/providers/temp_mail_gg.rb +362 -0
  24. data/lib/tempmail_sdk/providers/tempmail100.rb +148 -0
  25. data/lib/tempmail_sdk/providers/tempmail_ee.rb +373 -0
  26. data/lib/tempmail_sdk/providers/tempmailportal.rb +131 -0
  27. data/lib/tempmail_sdk/providers/tempmails_io.rb +89 -0
  28. data/lib/tempmail_sdk/providers/tempmailto.rb +312 -0
  29. data/lib/tempmail_sdk/providers/temporarymail_com.rb +184 -0
  30. data/lib/tempmail_sdk/providers/tenmin_app.rb +100 -0
  31. data/lib/tempmail_sdk/providers/thirty_min_email.rb +90 -0
  32. data/lib/tempmail_sdk/providers/tmpkit.rb +129 -0
  33. data/lib/tempmail_sdk/providers/zerodrop.rb +90 -0
  34. data/lib/tempmail_sdk/registry.rb +129 -29
  35. data/lib/tempmail_sdk/types.rb +13 -0
  36. data/lib/tempmail_sdk/version.rb +1 -1
  37. data/lib/tempmail_sdk.rb +1 -1
  38. metadata +31 -7
  39. data/lib/tempmail_sdk/providers/gonebox_email.rb +0 -89
  40. data/lib/tempmail_sdk/providers/mohmal.rb +0 -208
  41. data/lib/tempmail_sdk/providers/temp_mail_now.rb +0 -103
  42. data/lib/tempmail_sdk/providers/webmailtemp.rb +0 -108
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9633959dc0f47ae3b8b30e6cb69db5e16976773039a186303e47701efd37a6b
4
- data.tar.gz: 50eed70cbb31235fef5d96ea9d2288cc8d099568bd35946e752875d2c945291d
3
+ metadata.gz: 94b1283ca19ff9597330edb468dfa560e673fe8176921d74834e348ade013dc1
4
+ data.tar.gz: 1e9e82a350c0d42cba190079c117ed520ee4d48c2a28a0b2765e8746696856cd
5
5
  SHA512:
6
- metadata.gz: b54a192368aa851e240a34c91c7e8f2b6fc5b0d5587f6091fabd79f54b89bf7f29dc51c13c57987f499c65b570084aa0754838fbe263d7fbc8d564b5ce2e1bc2
7
- data.tar.gz: f630396b6757e1dd049a931141f946a99c92bcf28a28b3aeb8c78d69767f1b5c383a580cfefdc1ade984cbbaec051173ec82f904dff11ee9b5a8983dec03d7ea
6
+ metadata.gz: 1b1d8285e29796a127ae34c83fd014df2fcf7a06efccc6739bac2a567cbf9eb9d15b87861ec488a61c432be578b5426643c6ded3ff6c2bfeccf2a9a7a7045709
7
+ data.tar.gz: d1c0b4969332cecc27ed714ebfa1adaef8715eb0c53fddc836c0b1c87a299b4f202081e180490500196f4f59ff165633ef46f09357d9f21d9fc12208e1c8417b
data/README.md CHANGED
@@ -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
- Ruby 语言临时邮箱 SDK,公开 **279** 个 `channel` 渠道标识,聚合 100+ 个第三方临时邮箱服务商,所有渠道返回**统一标准化格式**。渠道标识与顺序与 Go / npm / Rust / Python / C 等其余各端保持一致(十端同步);随机生成邮箱时在本端独立打乱尝试顺序。
5
+ Ruby 语言临时邮箱 SDK,公开 **296** 个 `channel` 渠道标识,聚合 100+ 个第三方临时邮箱服务商,所有渠道返回**统一标准化格式**。渠道标识与顺序与 Go / npm / Rust / Python / C 等其余各端保持一致(十端同步);随机生成邮箱时在本端独立打乱尝试顺序。
6
6
 
7
7
  ## 安装
8
8
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  #
3
- # 渠道标识常量模块(279 个),常量值即渠道 slug。
3
+ # 渠道标识常量模块(296 个),常量值即渠道 slug。
4
4
  # 由 .channel_meta.json 生成,供用户以常量方式引用渠道,避免手写字符串出错。
5
5
  #
6
6
  module TempmailSdk
@@ -31,6 +31,7 @@ module TempmailSdk
31
31
  MAILFORSPAM_DISPOSABLE = "mailforspam-disposable"
32
32
  TEMPMAILC = "tempmailc"
33
33
  MAILNESIA = "mailnesia"
34
+ MAILTICKING = "mailticking"
34
35
  THROWAWAYMAIL = "throwawaymail"
35
36
  TEMPMAIL_FISH = "tempmail-fish"
36
37
  NEIGHBOURS_SH = "neighbours-sh"
@@ -80,7 +81,6 @@ module TempmailSdk
80
81
  VILLATOGEL_COM = "villatogel-com"
81
82
  MAIL123 = "mail123"
82
83
  MAIL10S = "mail10s"
83
- WEBMAILTEMP = "webmailtemp"
84
84
  TEMPFASTMAIL = "tempfastmail"
85
85
  C_1SEC_MAIL = "1sec-mail"
86
86
  FAKEMAIL = "fakemail"
@@ -162,7 +162,6 @@ module TempmailSdk
162
162
  HARIBU = "haribu"
163
163
  ROOTSH = "rootsh"
164
164
  FAKE_EMAIL_SITE = "fake-email-site"
165
- MOHMAL = "mohmal"
166
165
  MAILGOLEM = "mailgolem"
167
166
  BEST_TEMP_MAIL = "best-temp-mail"
168
167
  DISPOSABLEMAIL_APP = "disposablemail-app"
@@ -183,14 +182,12 @@ module TempmailSdk
183
182
  TEMPP_MAILS = "tempp-mails"
184
183
  EMAILTEMP_ORG = "emailtemp-org"
185
184
  MYTEMPMAIL_CC = "mytempmail-cc"
186
- TEMP_MAIL_NOW = "temp-mail-now"
187
185
  MAIL_TD = "mail-td"
188
186
  MAILHOLE_DE = "mailhole-de"
189
187
  TMAIL_LINK = "tmail-link"
190
188
  C_24MAIL_CHACUO = "24mail-chacuo"
191
189
  NIMAIL = "nimail"
192
190
  FREECUSTOM = "freecustom"
193
- C_16888888_CYOU = "16888888-cyou"
194
191
  C_17666688_SHOP = "17666688-shop"
195
192
  C_282MAIL_COM = "282mail-com"
196
193
  BLACKHOLE_DJURBY_SE = "blackhole-djurby-se"
@@ -205,7 +202,6 @@ module TempmailSdk
205
202
  EASYME_PRO = "easyme-pro"
206
203
  EBS_COM_AR = "ebs-com-ar"
207
204
  ETGDEV_DE = "etgdev-de"
208
- EVERGREENCO_SHOP = "evergreenco-shop"
209
205
  FWD2M_ESZETT_ES = "fwd2m-eszett-es"
210
206
  JAMA_TRENET_EU = "jama-trenet-eu"
211
207
  J_FAIRUSE_ORG = "j-fairuse-org"
@@ -279,11 +275,37 @@ module TempmailSdk
279
275
  TEMPGMAILER = "tempgmailer"
280
276
  TEMP_MAIL_ORG = "temp-mail-org"
281
277
  XKX_ME = "xkx-me"
282
- GONEBOX_EMAIL = "gonebox-email"
283
278
  MAILCAT_AI = "mailcat-ai"
284
279
  TEMPGO_EMAIL = "tempgo-email"
285
280
  RESTMAIL_NET = "restmail-net"
286
281
  DROPMAIL_ME = "dropmail-me"
287
282
  TEN_MINUTE_MAIL_NET = "ten-minute-mail-net"
283
+ TEMPMAILS_IO = "tempmails-io"
284
+ SHITPOST_EMAIL = "shitpost-email"
285
+ SMAILS = "smails"
286
+ TEMPMAILPORTAL = "tempmailportal"
287
+ HUSKMAIL = "huskmail"
288
+ ZERODROP = "zerodrop"
289
+ FIRETEMPMAIL = "firetempmail"
290
+ NULLMAIL = "nullmail"
291
+ TENMIN_APP = "tenmin-app"
292
+ MTEMPMAIL = "mtempmail"
293
+ TEMPMAIL_EE = "tempmail-ee"
294
+ TEMPORARYMAIL_COM = "temporarymail-com"
295
+ C_30MINEMAIL = "30minemail"
296
+ LINSHI_XYZ = "linshi-xyz"
297
+ CRAZYMAILING = "crazymailing"
298
+ NOXEN_DE5_NET = "noxen-de5-net"
299
+ NUKEMAIL = "nukemail"
300
+ SHADOWMAIL = "shadowmail"
301
+ FLYBYMAIL = "flybymail"
302
+ NOWTEMPMAIL = "nowtempmail"
303
+ CLAWDEMAIL = "clawdemail"
304
+ TEMPMAIL100 = "tempmail100"
305
+ TEMPMAILTO = "tempmailto"
306
+ TEMP_MAIL_GG = "temp-mail-gg"
307
+ TMPKIT = "tmpkit"
308
+ INTERNXT = "internxt"
309
+ GENERATOR_EMAIL = "generator-email"
288
310
  end
289
311
  end
@@ -4,7 +4,7 @@
4
4
  # 每项为 [slug, name, website],注册表按此顺序枚举,顺序为硬约束。
5
5
  #
6
6
  module TempmailSdk
7
- # 279 个渠道的有序元数据
7
+ # 296 个渠道的有序元数据
8
8
  CHANNEL_DATA = [
9
9
  ["tempmail", "TempMail", "tempmail.ing"],
10
10
  ["tempmail-cn", "TempMail CN", "tempmail.cn"],
@@ -31,6 +31,7 @@ module TempmailSdk
31
31
  ["mailforspam-disposable", "MailForSpam Disposable", "disposable.email"],
32
32
  ["tempmailc", "TempMailC", "tempmailc.com"],
33
33
  ["mailnesia", "Mailnesia", "mailnesia.com"],
34
+ ["mailticking", "MailTicking", "mailticking.com"],
34
35
  ["throwawaymail", "ThrowawayMail", "throwawaymail.app"],
35
36
  ["tempmail-fish", "TempMail Fish", "tempmail.fish"],
36
37
  ["neighbours-sh", "Neighbours", "neighbours.sh"],
@@ -80,7 +81,6 @@ module TempmailSdk
80
81
  ["villatogel-com", "villatogel.com", "getnada.net"],
81
82
  ["mail123", "Mail123", "mail123.fr"],
82
83
  ["mail10s", "Mail10s", "mail10s.com"],
83
- ["webmailtemp", "WebMailTemp", "webmailtemp.com"],
84
84
  ["tempfastmail", "TempFastMail", "tempfastmail.com"],
85
85
  ["1sec-mail", "1SecMail", "1sec-mail.com"],
86
86
  ["fakemail", "FakeMail", "fakemail.net"],
@@ -162,7 +162,6 @@ module TempmailSdk
162
162
  ["haribu", "Haribu", "haribu.net"],
163
163
  ["rootsh", "Rootsh(BccTo)", "rootsh.com"],
164
164
  ["fake-email-site", "FakeEmailSite", "fake-email.site"],
165
- ["mohmal", "Mohmal", "mohmal.com"],
166
165
  ["mailgolem", "MailGolem", "mailgolem.com"],
167
166
  ["best-temp-mail", "BestTempMail", "best-temp-mail.com"],
168
167
  ["disposablemail-app", "DisposableMail", "disposablemail.app"],
@@ -183,14 +182,12 @@ module TempmailSdk
183
182
  ["tempp-mails", "TemppMails", "tempp-mails.com"],
184
183
  ["emailtemp-org", "EmailTemp", "emailtemp.org"],
185
184
  ["mytempmail-cc", "MyTempMail.cc", "mytempmail.cc"],
186
- ["temp-mail-now", "TempMailNow", "temp-mail.now"],
187
185
  ["mail-td", "Mail.td", "mail.td"],
188
186
  ["mailhole-de", "Mailhole.de", "mailhole.de"],
189
187
  ["tmail-link", "TMail.link", "tmail.link"],
190
188
  ["24mail-chacuo", "24Mail Chacuo", "24mail.chacuo.net"],
191
189
  ["nimail", "NiMail", "nimail.cn"],
192
190
  ["freecustom", "FreeCustom.Email", "freecustom.email"],
193
- ["16888888-cyou", "Mailmomy (16888888.cyou)", "mailmomy.com"],
194
191
  ["17666688-shop", "Mailmomy (17666688.shop)", "mailmomy.com"],
195
192
  ["282mail-com", "Mailmomy (282mail.com)", "mailmomy.com"],
196
193
  ["blackhole-djurby-se", "Mailinator (blackhole.djurby.se)", "mailinator.com"],
@@ -205,7 +202,6 @@ module TempmailSdk
205
202
  ["easyme-pro", "Mailmomy (easyme.pro)", "mailmomy.com"],
206
203
  ["ebs-com-ar", "Mailinator (ebs.com.ar)", "mailinator.com"],
207
204
  ["etgdev-de", "Mailinator (etgdev.de)", "mailinator.com"],
208
- ["evergreenco-shop", "Mailmomy (evergreenco.shop)", "mailmomy.com"],
209
205
  ["fwd2m-eszett-es", "Mailinator (fwd2m.eszett.es)", "mailinator.com"],
210
206
  ["jama-trenet-eu", "Mailinator (jama.trenet.eu)", "mailinator.com"],
211
207
  ["j-fairuse-org", "Mailinator (j.fairuse.org)", "mailinator.com"],
@@ -279,11 +275,37 @@ module TempmailSdk
279
275
  ["tempgmailer", "TempGmailer", "tempgmailer.com"],
280
276
  ["temp-mail-org", "Temp-Mail.org", "temp-mail.org"],
281
277
  ["xkx-me", "XKX.me", "xkx.me"],
282
- ["gonebox-email", "Gonebox Email", "gonebox.email"],
283
278
  ["mailcat-ai", "Mailcat AI", "mailcat.ai"],
284
279
  ["tempgo-email", "TempGo Email", "tempgo.email"],
285
280
  ["restmail-net", "Restmail.net", "restmail.net"],
286
281
  ["dropmail-me", "DropMail.me", "dropmail.me"],
287
282
  ["ten-minute-mail-net", "10MinuteMail.net", "10minutemail.net"],
283
+ ["tempmails-io", "TempMails.io", "tempmails.io"],
284
+ ["shitpost-email", "ShitPost.email", "shitpost.email"],
285
+ ["smails", "Smails.dev", "smails.dev"],
286
+ ["tempmailportal", "TempMail Portal", "tempmailportal.com"],
287
+ ["huskmail", "HuskMail", "huskmail.xyz"],
288
+ ["zerodrop", "Zerodrop", "zerodrop.dev"],
289
+ ["firetempmail", "FireTempMail", "firetempmail.com"],
290
+ ["nullmail", "NullMail", "nullmail.cc"],
291
+ ["tenmin-app", "Tenmin.app", "tenmin.app"],
292
+ ["mtempmail", "MTempMail", "mtempmail.com"],
293
+ ["tempmail-ee", "TempMail.ee", "tempmail.ee"],
294
+ ["temporarymail-com", "Temporarymail.com", "temporarymail.com"],
295
+ ["30minemail", "30minemail", "30minemail.com"],
296
+ ["linshi-xyz", "Linshi.xyz", "linshi.xyz"],
297
+ ["crazymailing", "CrazyMailing", "crazymailing.com"],
298
+ ["noxen-de5-net", "UniMail Bot", "tempmail.noxen.de5.net"],
299
+ ["nukemail", "NukeMail", "nukemail.app"],
300
+ ["shadowmail", "ShadowMail", "shadowmail.win"],
301
+ ["flybymail", "FlyByMail", "flybymail.com"],
302
+ ["nowtempmail", "NowTempMail", "nowtempmail.com"],
303
+ ["clawdemail", "ClawdEmail", "clawdemail.com"],
304
+ ["tempmail100", "TempMail100", "tempmail100.com"],
305
+ ["tempmailto", "Tempmailto", "tempmailto.com"],
306
+ ["temp-mail-gg", "TempMailGG", "temp-mail.gg"],
307
+ ["tmpkit", "Tmpkit", "tmpkit.com"],
308
+ ["internxt", "Internxt", "internxt.com"],
309
+ ["generator-email", "GeneratorEmail", "generator.email"],
288
310
  ].freeze
289
311
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # ClawdEmail 渠道实现(clawdemail.com,API 域 api.clawdemail.com)
8
+ #
9
+ # POST /register 建箱(无验证码,body {"name":"xxx"},响应 success/email/token),
10
+ # GET /inbox 读信列表(Header Authorization: Bearer <token>,
11
+ # 响应 success/email/count/unread/emails[]),GET /email/{id} 取单封详情(Bearer)。
12
+ # 信件保留 30 分钟,仅接收不发送,正文仅纯文本。
13
+ module Clawdemail
14
+ CHANNEL = "clawdemail"
15
+ BASE_URL = "https://api.clawdemail.com"
16
+
17
+ HEADERS = {
18
+ "Accept" => "application/json",
19
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " \
20
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
21
+ }.freeze
22
+
23
+ RETRY_KEYS = %w[id Id slug messageId message_id].freeze
24
+
25
+ module_function
26
+
27
+ # 设置 clawdemail 请求的通用请求头(可选附带 Bearer token)
28
+ # @param token [String] 认证令牌
29
+ # @return [Hash]
30
+ def auth_headers(token)
31
+ hdrs = HEADERS.dup
32
+ hdrs["Authorization"] = "Bearer #{token}" unless token.to_s.empty?
33
+ hdrs
34
+ end
35
+
36
+ # 创建 clawdemail.com 临时邮箱
37
+ # POST /register(body {"name":""})返回 email 与 token。
38
+ # @return [EmailInfo]
39
+ def generate_email
40
+ resp = Http.post("#{BASE_URL}/register",
41
+ headers: auth_headers("").merge("Content-Type" => "application/json"),
42
+ json: { "name" => "" }, timeout: 15)
43
+ raise "clawdemail: 创建邮箱失败 http #{resp.status_code}" unless resp.ok?
44
+
45
+ data = resp.json
46
+ raise "clawdemail: 创建响应非对象" unless data.is_a?(Hash)
47
+
48
+ email = data["email"].to_s.strip
49
+ token = data["token"].to_s.strip
50
+ raise "clawdemail: 创建邮箱响应缺少必要字段" if email.empty? || token.empty? || !email.include?("@")
51
+
52
+ EmailInfo.new(channel: CHANNEL, email: email, token: token)
53
+ end
54
+
55
+ # 获取 clawdemail.com 邮件列表
56
+ # 流程:GET /inbox?limit=50 取列表,对每个元素按 id 逐封 GET /email/{id} 合并详情;
57
+ # 详情失败时以列表摘要归一。
58
+ # @param email [String] 邮箱地址
59
+ # @param token [String] 注册返回的认证令牌
60
+ # @return [Array<Email>]
61
+ def get_emails(email, token)
62
+ addr = email.to_s.strip
63
+ resp = Http.get("#{BASE_URL}/inbox?limit=50",
64
+ headers: auth_headers(token), timeout: 15)
65
+ raise "clawdemail: 获取邮件列表失败 http #{resp.status_code}" unless resp.ok?
66
+
67
+ data = resp.json
68
+ raise "clawdemail: 收件箱响应非对象" unless data.is_a?(Hash)
69
+
70
+ unless data["success"] == true
71
+ raise "clawdemail: 读取收件箱失败: #{data["error"]}"
72
+ end
73
+ emails = data["emails"]
74
+ return [] unless emails.is_a?(Array)
75
+
76
+ emails.filter_map do |m|
77
+ next unless m.is_a?(Hash)
78
+
79
+ detail = get_detail(token, message_id_of(m))
80
+ row = m.dup
81
+ if detail.is_a?(Hash)
82
+ detail.each { |k, v| row[k] = v unless row.key?(k) }
83
+ end
84
+ Normalize.normalize_email(row, addr)
85
+ end
86
+ end
87
+
88
+ # 从列表元素中提取邮件 ID(候选键 id/Id/slug/messageId/message_id)
89
+ # @param row [Hash]
90
+ # @return [String]
91
+ def message_id_of(row)
92
+ RETRY_KEYS.each do |key|
93
+ val = row[key]
94
+ return val.to_s.strip unless val.nil? || val.to_s.strip.empty?
95
+ end
96
+ ""
97
+ end
98
+
99
+ # 获取 clawdemail.com 单封邮件详情
100
+ # GET /email/{id}(Bearer token),响应含 email 嵌套对象(from_addr/body_text/received_at)
101
+ # 时提升嵌套对象。
102
+ # @param token [String] 认证令牌
103
+ # @param id [String] 邮件 ID
104
+ # @return [Hash, nil]
105
+ def get_detail(token, id)
106
+ return nil if id.to_s.empty?
107
+
108
+ uri = "#{BASE_URL}/email/#{URI.encode_www_form_component(id)}"
109
+ resp = Http.get(uri, headers: auth_headers(token), timeout: 15)
110
+ return nil unless resp.ok?
111
+
112
+ detail = resp.json
113
+ return nil unless detail.is_a?(Hash)
114
+
115
+ nested = detail["email"]
116
+ nested.is_a?(Hash) ? nested : detail
117
+ rescue StandardError
118
+ nil
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # Crazymailing 渠道实现(crazymailing.com)
8
+ #
9
+ # Next.js 全栈站点,API 结构:
10
+ # POST /api/mailbox(空 JSON body)建箱,响应
11
+ # {"mailbox":{"id":"...","address":"...@crazymailing.com","expiresAt":"<RFC3339>"}};
12
+ # GET /api/messages?mailbox=<完整地址 URL 编码> 读信,响应 {"messages":[...]};
13
+ # GET /api/message/{id}/body 取单封正文(完整 HTML 页面)。
14
+ # 请求需携带 Origin/Referer 浏览器形态头。
15
+ module Crazymailing
16
+ CHANNEL = "crazymailing"
17
+ BASE_URL = "https://crazymailing.com"
18
+
19
+ HEADERS = {
20
+ "Content-Type" => "application/json",
21
+ "Accept" => "application/json",
22
+ "Origin" => BASE_URL,
23
+ "Referer" => "#{BASE_URL}/",
24
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " \
25
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
26
+ }.freeze
27
+
28
+ RETRY_KEYS = %w[id Id slug messageId message_id].freeze
29
+
30
+ module_function
31
+
32
+ # 创建临时邮箱
33
+ # POST /api/mailbox(空 JSON body);域名由服务端统一分配(当前仅 @crazymailing.com)。
34
+ # @return [EmailInfo]
35
+ def generate_email
36
+ resp = Http.post("#{BASE_URL}/api/mailbox",
37
+ headers: HEADERS, json: {}, timeout: 15)
38
+ raise "crazymailing: 创建邮箱失败 http #{resp.status_code}" unless resp.ok?
39
+
40
+ data = resp.json
41
+ mailbox = data.is_a?(Hash) ? data["mailbox"] : nil
42
+ raise "crazymailing: 创建响应缺少 mailbox" unless mailbox.is_a?(Hash)
43
+
44
+ address = mailbox["address"].to_s.strip
45
+ raise "crazymailing: 创建响应缺少 mailbox.address" if address.empty?
46
+
47
+ EmailInfo.new(channel: CHANNEL, email: address,
48
+ token: mailbox["id"].to_s, expires_at: mailbox["expiresAt"].to_s)
49
+ end
50
+
51
+ # 读取收件箱
52
+ # GET /api/messages?mailbox=<完整地址 URL 编码>,响应 {"messages":[...]};
53
+ # 对每个元素逐封 GET /api/message/{id}/body 拉取正文(失败不阻断列表)。
54
+ # @param email [String] 完整邮箱地址
55
+ # @param token [String] 建箱返回的 mailbox id
56
+ # @return [Array<Email>]
57
+ def get_emails(email, token)
58
+ addr = email.to_s.strip
59
+ raise "crazymailing: 邮箱地址为空" if addr.empty?
60
+
61
+ uri = "#{BASE_URL}/api/messages?mailbox=#{URI.encode_www_form_component(addr)}"
62
+ resp = Http.get(uri, headers: HEADERS, timeout: 15)
63
+ raise "crazymailing: 读取收件箱失败 http #{resp.status_code}" unless resp.ok?
64
+
65
+ data = resp.json
66
+ messages = data.is_a?(Hash) ? data["messages"] : nil
67
+ return [] unless messages.is_a?(Array)
68
+
69
+ messages.filter_map do |m|
70
+ next unless m.is_a?(Hash)
71
+
72
+ row = m.dup
73
+ row["to"] = addr unless row.key?("to")
74
+ id = message_id_of(row)
75
+ unless id.empty?
76
+ # 列表元素为摘要,正文须逐封二拉(失败不阻断)
77
+ html = get_body(id)
78
+ row["html"] = html if !html.empty?
79
+ end
80
+ Normalize.normalize_email(row, addr)
81
+ end
82
+ end
83
+
84
+ # 从列表元素中提取邮件 ID(候选键 id/Id/slug/messageId/message_id)
85
+ # @param row [Hash]
86
+ # @return [String]
87
+ def message_id_of(row)
88
+ RETRY_KEYS.each do |key|
89
+ val = row[key]
90
+ return val.to_s.strip unless val.nil? || val.to_s.strip.empty?
91
+ end
92
+ ""
93
+ end
94
+
95
+ # 拉取单封正文(GET /api/message/{id}/body,响应为完整 HTML 页面)
96
+ # @param id [String] 邮件 ID
97
+ # @return [String]
98
+ def get_body(id)
99
+ uri = "#{BASE_URL}/api/message/#{URI.encode_www_form_component(id)}/body"
100
+ resp = Http.get(uri,
101
+ headers: {
102
+ "Accept" => "text/html,application/xhtml+xml,*/*;q=0.8",
103
+ "Origin" => BASE_URL,
104
+ "Referer" => "#{BASE_URL}/",
105
+ "User-Agent" => HEADERS["User-Agent"]
106
+ },
107
+ timeout: 15)
108
+ return "" unless resp.ok?
109
+
110
+ resp.body.to_s
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # Firetempmail 渠道实现(firetempmail.com)
8
+ #
9
+ # 无认证 REST:建箱无需请求,本地生成 随机词+0-999@<域>(域池与官网一致:
10
+ # offrework.click / service-today.click / jobsdeforyou.sa.com);
11
+ # 读信 GET https://mail.firetempmail.com/mail/get?address=<邮箱 URL 编码>,
12
+ # 必须携带 Header Origin: https://firetempmail.com(否则 403 'Origin not allowed')。
13
+ # 响应形如 {"status":"ok","code":200,"msg":"...","stats":{},"mails":[...]},
14
+ # 邮件字段以 sender/subject/date + content-html/content-text/content-plain 多候选归一。
15
+ module Firetempmail
16
+ CHANNEL = "firetempmail"
17
+ API_BASE = "https://mail.firetempmail.com"
18
+ ORIGIN = "https://firetempmail.com"
19
+ # 官网 JS 中的完整平台域池,顺序与官网一致
20
+ DOMAINS = %w[offrework.click service-today.click jobsdeforyou.sa.com].freeze
21
+
22
+ HEADERS = {
23
+ "Accept" => "application/json",
24
+ "Origin" => ORIGIN,
25
+ "Referer" => "#{ORIGIN}/",
26
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
27
+ "(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0"
28
+ }.freeze
29
+
30
+ module_function
31
+
32
+ # 生成 3-6 位小写随机词(模拟官网 1-5 字母词的观感)
33
+ LETTERS = ("a".."z").to_a
34
+ def random_word
35
+ Array.new(rand(3..6)) { LETTERS.sample }.join
36
+ end
37
+
38
+ # 创建临时邮箱
39
+ # 建箱无需请求,本地随机生成 随机词+0-999@域名;token 复用完整地址
40
+ # @return [EmailInfo]
41
+ def generate_email
42
+ email = "#{random_word}#{rand(0..999)}@#{DOMAINS.sample}"
43
+ EmailInfo.new(channel: CHANNEL, email: email, token: email)
44
+ end
45
+
46
+ # 读取收件箱
47
+ # GET https://mail.firetempmail.com/mail/get?address=<URL 编码完整邮箱>,必带 Origin 头
48
+ # @param email [String] 邮箱地址
49
+ # @param _token [String] 令牌(本渠道忽略,以邮箱为准)
50
+ # @return [Array<Email>]
51
+ def get_emails(email, _token)
52
+ addr = email.to_s.strip
53
+ raise "firetempmail: 邮箱地址为空" if addr.empty?
54
+
55
+ url = "#{API_BASE}/mail/get?address=#{URI.encode_www_form_component(addr)}"
56
+ resp = Http.get(url, headers: HEADERS, timeout: 15)
57
+ resp.raise_for_status
58
+ data = resp.json
59
+ return [] unless data.is_a?(Hash)
60
+
61
+ # 错误与成功共用同一信封:status 非 ok 时抛错
62
+ status = data["status"].to_s
63
+ if !status.empty? && status != "ok"
64
+ raise "firetempmail: #{data["msg"] || "读信失败"}"
65
+ end
66
+
67
+ mails = data["mails"]
68
+ return [] unless mails.is_a?(Array)
69
+
70
+ mails.filter_map do |m|
71
+ next unless m.is_a?(Hash)
72
+
73
+ row = {
74
+ "from" => m["sender"] || m["from"] || m["from_address"],
75
+ "to" => addr,
76
+ "subject" => m["subject"] || m["title"],
77
+ "date" => m["date"] || m["received_at"] || m["created_at"],
78
+ "html" => m["content-html"] || m["html"],
79
+ "text" => m["content-text"] || m["content-plain"] || m["text"]
80
+ }
81
+ Normalize.normalize_email(row, addr)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module TempmailSdk
6
+ module Providers
7
+ # Flybymail 渠道实现(flybymail.com)
8
+ #
9
+ # POST /api/recipients 建箱(空 JSON body,响应 id/email/createdAt/expiresAt,
10
+ # expiresAt 为毫秒时间戳),GET /api/recipients/{email}/emails 读信
11
+ # (按邮箱地址、非 id 查询,响应 {"emails":[...]})。
12
+ # 信件字段:id/from/to/subject/body(纯文本)/htmlBody(HTML 正文)/preview/time/read。
13
+ module Flybymail
14
+ CHANNEL = "flybymail"
15
+ BASE_URL = "https://flybymail.com"
16
+
17
+ HEADERS = {
18
+ "Content-Type" => "application/json",
19
+ "Accept" => "application/json",
20
+ "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " \
21
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
22
+ }.freeze
23
+
24
+ module_function
25
+
26
+ # 创建 flybymail.com 临时邮箱
27
+ # POST /api/recipients(空 JSON body)返回 id/email/createdAt/expiresAt,
28
+ # expiresAt 为毫秒时间戳(约 4 小时),转换为毫秒值供 EmailInfo 统一展示。
29
+ # @return [EmailInfo]
30
+ def generate_email
31
+ resp = Http.post("#{BASE_URL}/api/recipients",
32
+ headers: HEADERS, json: {}, timeout: 15)
33
+ raise "flybymail: 创建邮箱失败 http #{resp.status_code}" unless resp.ok?
34
+
35
+ data = resp.json
36
+ raise "flybymail: 创建响应非对象" unless data.is_a?(Hash)
37
+
38
+ id = data["id"].to_s.strip
39
+ email = data["email"].to_s.strip
40
+ raise "flybymail: 创建邮箱响应缺少必要字段" if id.empty? || email.empty? || !email.include?("@")
41
+
42
+ expires_at = data["expiresAt"].to_i.positive? ? data["expiresAt"].to_i : nil
43
+ EmailInfo.new(channel: CHANNEL, email: email, token: id, expires_at: expires_at)
44
+ end
45
+
46
+ # 获取 flybymail.com 邮件列表
47
+ # GET /api/recipients/{email}/emails(按地址查询)返回 {"emails":[...]}。
48
+ # @param email [String] 邮箱地址
49
+ # @param token [String] 建箱返回的收件人 ID(读信端点按邮箱地址查询,令牌保留)
50
+ # @return [Array<Email>]
51
+ def get_emails(email, token)
52
+ addr = email.to_s.strip
53
+ raise "flybymail: 邮箱地址为空或格式错误" if addr.empty? || !addr.include?("@")
54
+
55
+ uri = "#{BASE_URL}/api/recipients/#{URI.encode_www_form_component(addr)}/emails"
56
+ resp = Http.get(uri, headers: HEADERS, timeout: 15)
57
+ raise "flybymail: 获取邮件列表失败 http #{resp.status_code}" unless resp.ok?
58
+
59
+ data = resp.json
60
+ emails = data.is_a?(Hash) ? data["emails"] : nil
61
+ return [] unless emails.is_a?(Array)
62
+
63
+ emails.filter_map do |raw|
64
+ next unless raw.is_a?(Hash)
65
+
66
+ # id 为数字时按字符串归一,time 为毫秒时间戳时按 timestamp 归一
67
+ row = {
68
+ "id" => raw["id"].to_s.strip,
69
+ "from" => raw["from"],
70
+ "to" => raw["to"],
71
+ "subject" => raw["subject"],
72
+ "text" => raw["body"],
73
+ "html" => raw["htmlBody"],
74
+ "time" => raw["time"],
75
+ "read" => raw["read"],
76
+ "attachments" => raw["attachments"],
77
+ "timestamp" => timestamp_of(raw)
78
+ }
79
+ Normalize.normalize_email(row, addr)
80
+ end
81
+ end
82
+
83
+ # 归一邮件时间:候选 time/date 字段(time 为毫秒时间戳)
84
+ # @param m [Hash]
85
+ # @return [Object, nil]
86
+ def timestamp_of(m)
87
+ return m["time"] if m.key?("time") && !m["time"].nil?
88
+
89
+ m["date"]
90
+ end
91
+ end
92
+ end
93
+ end