tempmail_sdk 1.3.3

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +116 -0
  3. data/lib/tempmail_sdk/channels.rb +289 -0
  4. data/lib/tempmail_sdk/channels_data.rb +289 -0
  5. data/lib/tempmail_sdk/client.rb +193 -0
  6. data/lib/tempmail_sdk/config.rb +104 -0
  7. data/lib/tempmail_sdk/html_utils.rb +42 -0
  8. data/lib/tempmail_sdk/http.rb +225 -0
  9. data/lib/tempmail_sdk/logger.rb +38 -0
  10. data/lib/tempmail_sdk/normalize.rb +193 -0
  11. data/lib/tempmail_sdk/providers/anonbox.rb +248 -0
  12. data/lib/tempmail_sdk/providers/anonymmail.rb +92 -0
  13. data/lib/tempmail_sdk/providers/byom.rb +48 -0
  14. data/lib/tempmail_sdk/providers/catchmail.rb +110 -0
  15. data/lib/tempmail_sdk/providers/cleantempmail.rb +49 -0
  16. data/lib/tempmail_sdk/providers/devmail_uk.rb +58 -0
  17. data/lib/tempmail_sdk/providers/dropmail.rb +133 -0
  18. data/lib/tempmail_sdk/providers/dropmail_click.rb +81 -0
  19. data/lib/tempmail_sdk/providers/dropmail_me.rb +163 -0
  20. data/lib/tempmail_sdk/providers/duckmail.rb +63 -0
  21. data/lib/tempmail_sdk/providers/eyepaste.rb +119 -0
  22. data/lib/tempmail_sdk/providers/fake_email_site.rb +48 -0
  23. data/lib/tempmail_sdk/providers/fake_legal.rb +109 -0
  24. data/lib/tempmail_sdk/providers/fmail.rb +87 -0
  25. data/lib/tempmail_sdk/providers/freecustom.rb +135 -0
  26. data/lib/tempmail_sdk/providers/getnada.rb +146 -0
  27. data/lib/tempmail_sdk/providers/gonebox_email.rb +89 -0
  28. data/lib/tempmail_sdk/providers/guerrillamail.rb +62 -0
  29. data/lib/tempmail_sdk/providers/guerrillamail_mirrors.rb +81 -0
  30. data/lib/tempmail_sdk/providers/harakirimail.rb +84 -0
  31. data/lib/tempmail_sdk/providers/haribu.rb +176 -0
  32. data/lib/tempmail_sdk/providers/inboxes.rb +110 -0
  33. data/lib/tempmail_sdk/providers/inboxkitten.rb +90 -0
  34. data/lib/tempmail_sdk/providers/linshiyou.rb +157 -0
  35. data/lib/tempmail_sdk/providers/lroid.rb +170 -0
  36. data/lib/tempmail_sdk/providers/m2u.rb +126 -0
  37. data/lib/tempmail_sdk/providers/mail10s.rb +59 -0
  38. data/lib/tempmail_sdk/providers/mail123.rb +82 -0
  39. data/lib/tempmail_sdk/providers/mail_cx.rb +133 -0
  40. data/lib/tempmail_sdk/providers/mail_sunls.rb +68 -0
  41. data/lib/tempmail_sdk/providers/mail_tm.rb +99 -0
  42. data/lib/tempmail_sdk/providers/mailcatch.rb +91 -0
  43. data/lib/tempmail_sdk/providers/maildrop.rb +92 -0
  44. data/lib/tempmail_sdk/providers/maildrop_cc.rb +110 -0
  45. data/lib/tempmail_sdk/providers/mailforspam.rb +96 -0
  46. data/lib/tempmail_sdk/providers/mailhole_de.rb +70 -0
  47. data/lib/tempmail_sdk/providers/mailinator.rb +182 -0
  48. data/lib/tempmail_sdk/providers/mailmomy.rb +108 -0
  49. data/lib/tempmail_sdk/providers/mailnesia.rb +141 -0
  50. data/lib/tempmail_sdk/providers/mffac.rb +101 -0
  51. data/lib/tempmail_sdk/providers/moakt.rb +296 -0
  52. data/lib/tempmail_sdk/providers/neighbours.rb +140 -0
  53. data/lib/tempmail_sdk/providers/neighbours_sh.rb +117 -0
  54. data/lib/tempmail_sdk/providers/nimail.rb +100 -0
  55. data/lib/tempmail_sdk/providers/ockito.rb +163 -0
  56. data/lib/tempmail_sdk/providers/one_sec_mail.rb +46 -0
  57. data/lib/tempmail_sdk/providers/restmail_net.rb +60 -0
  58. data/lib/tempmail_sdk/providers/rootsh.rb +167 -0
  59. data/lib/tempmail_sdk/providers/shitty_email.rb +84 -0
  60. data/lib/tempmail_sdk/providers/smailpro.rb +103 -0
  61. data/lib/tempmail_sdk/providers/ta_easy.rb +53 -0
  62. data/lib/tempmail_sdk/providers/temp_mail_io.rb +67 -0
  63. data/lib/tempmail_sdk/providers/temp_mail_now.rb +103 -0
  64. data/lib/tempmail_sdk/providers/temp_mail_org.rb +89 -0
  65. data/lib/tempmail_sdk/providers/tempemail_co.rb +142 -0
  66. data/lib/tempmail_sdk/providers/tempemail_info.rb +121 -0
  67. data/lib/tempmail_sdk/providers/tempemails_net.rb +159 -0
  68. data/lib/tempmail_sdk/providers/tempfastmail.rb +76 -0
  69. data/lib/tempmail_sdk/providers/tempgmailer.rb +126 -0
  70. data/lib/tempmail_sdk/providers/tempgo_email.rb +74 -0
  71. data/lib/tempmail_sdk/providers/tempinbox.rb +70 -0
  72. data/lib/tempmail_sdk/providers/tempmail.rb +66 -0
  73. data/lib/tempmail_sdk/providers/tempmail365.rb +119 -0
  74. data/lib/tempmail_sdk/providers/tempmail_fish.rb +89 -0
  75. data/lib/tempmail_sdk/providers/tempmail_fyi.rb +124 -0
  76. data/lib/tempmail_sdk/providers/tempmail_lol.rb +42 -0
  77. data/lib/tempmail_sdk/providers/tempmail_lol_v2.rb +57 -0
  78. data/lib/tempmail_sdk/providers/tempmail_plus.rb +80 -0
  79. data/lib/tempmail_sdk/providers/tempmailc.rb +80 -0
  80. data/lib/tempmail_sdk/providers/tempmailpro.rb +89 -0
  81. data/lib/tempmail_sdk/providers/tempmailten.rb +150 -0
  82. data/lib/tempmail_sdk/providers/temporam.rb +95 -0
  83. data/lib/tempmail_sdk/providers/tempp_mails.rb +150 -0
  84. data/lib/tempmail_sdk/providers/tempy_email.rb +73 -0
  85. data/lib/tempmail_sdk/providers/ten_minute_mail_net.rb +125 -0
  86. data/lib/tempmail_sdk/providers/tenminute_one.rb +255 -0
  87. data/lib/tempmail_sdk/providers/throwawaymail.rb +80 -0
  88. data/lib/tempmail_sdk/providers/tmail_link.rb +98 -0
  89. data/lib/tempmail_sdk/providers/uncorreotemporal.rb +84 -0
  90. data/lib/tempmail_sdk/providers/webmailtemp.rb +108 -0
  91. data/lib/tempmail_sdk/providers/xkx_me.rb +125 -0
  92. data/lib/tempmail_sdk/providers/zhujump.rb +256 -0
  93. data/lib/tempmail_sdk/registry.rb +1097 -0
  94. data/lib/tempmail_sdk/retry.rb +91 -0
  95. data/lib/tempmail_sdk/telemetry.rb +134 -0
  96. data/lib/tempmail_sdk/types.rb +164 -0
  97. data/lib/tempmail_sdk/version.rb +6 -0
  98. data/lib/tempmail_sdk/webui.rb +360 -0
  99. data/lib/tempmail_sdk.rb +76 -0
  100. metadata +142 -0
@@ -0,0 +1,360 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "thread"
5
+ require "json"
6
+
7
+ module TempmailSdk
8
+ # 嵌入式 WebUI HTTP 服务器
9
+ # 通过 TEMPMAIL_WEBUI=true/1/yes 激活,TEMPMAIL_WEBUI_PORT 指定端口(未设置则随机)
10
+ # 仅依赖 Ruby 标准库,不引入任何外部 gem
11
+ module WebUI
12
+ module_function
13
+
14
+ # SSE 客户端队列列表与互斥锁
15
+ @sse_clients = []
16
+ @sse_mutex = Mutex.new
17
+ @server_mutex = Mutex.new
18
+ @server = nil
19
+ @port = nil
20
+
21
+ class << self
22
+ attr_reader :port, :host
23
+
24
+ # 启动 WebUI(幂等)
25
+ def start(host: nil, port: nil)
26
+ @server_mutex.synchronize do
27
+ return @port if @server
28
+
29
+ bind_host = host || _resolve_host
30
+ bind_port = port || _resolve_port
31
+ @server = TCPServer.new(bind_host, bind_port)
32
+ @host = bind_host
33
+ @port = @server.addr[1]
34
+
35
+ # 挂接日志处理器
36
+ _attach_log_handler
37
+
38
+ Thread.new { _serve }
39
+ Log.logger.info("WebUI 已启动: http://#{@host}:#{@port}")
40
+ @port
41
+ end
42
+ end
43
+
44
+ # 广播日志条目到所有 SSE 连接
45
+ def broadcast(entry)
46
+ data = JSON.generate(entry)
47
+ @sse_mutex.synchronize { @sse_clients.dup }.each do |q|
48
+ q.push(data) rescue nil
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def _resolve_host
55
+ raw = (ENV["TEMPMAIL_WEBUI_HOST"] || "").strip
56
+ raw.empty? ? "127.0.0.1" : raw
57
+ end
58
+
59
+ def _resolve_port
60
+ raw = (ENV["TEMPMAIL_WEBUI_PORT"] || "").strip
61
+ raw.match?(/\A\d+\z/) ? raw.to_i : 0
62
+ end
63
+
64
+ def _attach_log_handler
65
+ orig_formatter = Log.logger.formatter
66
+ Log.logger.formatter = proc do |severity, time, progname, msg|
67
+ entry = {
68
+ time: time.strftime("%H:%M:%S"),
69
+ level: _severity_to_level(severity),
70
+ channel: nil,
71
+ msg: msg.to_s
72
+ }
73
+ broadcast(entry)
74
+ orig_formatter ? orig_formatter.call(severity, time, progname, msg) : "#{severity} #{msg}\n"
75
+ end
76
+ # 确保 logger 级别足够低以捕获 debug
77
+ Log.logger.level = Logger::DEBUG if Log.logger.level > Logger::DEBUG
78
+ end
79
+
80
+ def _severity_to_level(sev)
81
+ case sev.to_s.upcase
82
+ when "ERROR", "FATAL" then "error"
83
+ when "WARN" then "warn"
84
+ when "INFO" then "info"
85
+ else "debug"
86
+ end
87
+ end
88
+
89
+ def _serve
90
+ loop do
91
+ client = @server.accept rescue break
92
+ Thread.new(client) { |c| _handle(c) }
93
+ end
94
+ end
95
+
96
+ def _handle(socket)
97
+ line = socket.gets&.chomp || ""
98
+ method, path, = line.split(" ")
99
+ # 消费请求头
100
+ loop do
101
+ h = socket.gets
102
+ break if h.nil? || h.chomp.empty?
103
+ end
104
+
105
+ path = (path || "/").split("?", 2).first
106
+
107
+ case [method, path]
108
+ when ["GET", "/"]
109
+ _send_html(socket, _rendered_html)
110
+ when ["GET", "/api/info"]
111
+ _send_json(socket, _build_info)
112
+ when ["GET", "/api/channels"]
113
+ _send_json(socket, _build_channels)
114
+ when ["GET", "/api/logs/stream"]
115
+ _handle_sse(socket)
116
+ else
117
+ socket.write "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"
118
+ end
119
+ rescue StandardError
120
+ # 忽略单连接异常,不影响服务器主循环
121
+ ensure
122
+ socket.close rescue nil
123
+ end
124
+
125
+ def _send_html(socket, html)
126
+ body = html.encode("UTF-8")
127
+ socket.write "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n" \
128
+ "Content-Length: #{body.bytesize}\r\nConnection: close\r\n\r\n#{body}"
129
+ end
130
+
131
+ def _send_json(socket, payload)
132
+ body = JSON.generate(payload)
133
+ socket.write "HTTP/1.1 200 OK\r\nContent-Type: application/json; charset=utf-8\r\n" \
134
+ "Content-Length: #{body.bytesize}\r\nConnection: close\r\n\r\n#{body}"
135
+ end
136
+
137
+ def _handle_sse(socket)
138
+ q = Queue.new
139
+ @sse_mutex.synchronize { @sse_clients << q }
140
+ socket.write "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream; charset=utf-8\r\n" \
141
+ "Cache-Control: no-cache\r\nConnection: keep-alive\r\nX-Accel-Buffering: no\r\n\r\n"
142
+ socket.write ": connected\n\n"
143
+ socket.flush
144
+ loop do
145
+ data = q.pop
146
+ socket.write "data: #{data}\n\n"
147
+ socket.flush
148
+ end
149
+ rescue StandardError
150
+ # 客户端断开
151
+ ensure
152
+ @sse_mutex.synchronize { @sse_clients.delete(q) }
153
+ end
154
+
155
+ def _build_info
156
+ cfg = Config.get_config
157
+ te = cfg.telemetry_enabled
158
+ te = true if te.nil?
159
+ {
160
+ language: "Ruby",
161
+ version: VERSION,
162
+ host: @host,
163
+ port: @port,
164
+ proxy: cfg.proxy || "",
165
+ timeout: cfg.timeout,
166
+ config: { telemetry: te == true, insecure: cfg.insecure == true }
167
+ }
168
+ end
169
+
170
+ def _build_channels
171
+ Registry::REGISTRY.map { |s| { channel: s.channel, name: s.name, website: s.website } }
172
+ end
173
+
174
+ def _rendered_html
175
+ @_rendered_html ||= HTML_TEMPLATE.sub("<!-- PLACEHOLDER_SCRIPT -->", APP_SCRIPT)
176
+ end
177
+ end
178
+
179
+ # 自动检查环境变量并启动
180
+ def auto_start
181
+ flag = (ENV["TEMPMAIL_WEBUI"] || "").strip.downcase
182
+ WebUI.start if %w[1 true yes on].include?(flag)
183
+ end
184
+
185
+ # rubocop:disable Layout/LineLength
186
+ HTML_TEMPLATE = <<~'HTML'
187
+ <!DOCTYPE html>
188
+ <html lang="zh-CN">
189
+ <head>
190
+ <meta charset="UTF-8">
191
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
192
+ <title>TempMail SDK - WebUI</title>
193
+ <script src="https://cdn.tailwindcss.com"></script>
194
+ <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
195
+ <style>
196
+ [v-cloak]{display:none}
197
+ .log-debug{color:#6b7280}.log-info{color:#3b82f6}.log-warn{color:#f59e0b}.log-error{color:#ef4444}
198
+ .fade-enter-active{transition:opacity .3s}.fade-enter-from{opacity:0}
199
+ #log-container{max-height:60vh;overflow-y:auto;scroll-behavior:smooth}
200
+ </style>
201
+ </head>
202
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
203
+ <div id="app" v-cloak>
204
+ <header class="bg-gray-800 border-b border-gray-700 px-6 py-4 flex items-center justify-between">
205
+ <div class="flex items-center gap-3">
206
+ <h1 class="text-xl font-bold">TempMail SDK</h1>
207
+ <span class="text-sm text-gray-400">{{ sdkInfo.language }} · v{{ sdkInfo.version }}</span>
208
+ </div>
209
+ <div class="flex items-center gap-4 text-sm">
210
+ <span class="px-2 py-1 rounded" :class="connected ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'">
211
+ {{ connected ? '已连接' : '已断开' }}
212
+ </span>
213
+ <span class="text-gray-400">端口 {{ sdkInfo.port }}</span>
214
+ </div>
215
+ </header>
216
+ <nav class="bg-gray-800 border-b border-gray-700 px-6">
217
+ <div class="flex gap-1">
218
+ <button v-for="tab in tabs" :key="tab.id" @click="activeTab=tab.id"
219
+ class="px-4 py-2 text-sm rounded-t transition-colors"
220
+ :class="activeTab===tab.id ? 'bg-gray-900 text-white' : 'text-gray-400 hover:text-gray-200'">
221
+ {{ tab.label }}
222
+ </button>
223
+ </div>
224
+ </nav>
225
+ <main class="p-6">
226
+ <section v-show="activeTab==='overview'">
227
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
228
+ <div class="bg-gray-800 rounded-lg p-4">
229
+ <div class="text-gray-400 text-sm">渠道总数</div>
230
+ <div class="text-2xl font-bold">{{ channels.length }}</div>
231
+ </div>
232
+ <div class="bg-gray-800 rounded-lg p-4">
233
+ <div class="text-gray-400 text-sm">代理</div>
234
+ <div class="text-lg font-mono">{{ sdkInfo.proxy || '未设置' }}</div>
235
+ </div>
236
+ <div class="bg-gray-800 rounded-lg p-4">
237
+ <div class="text-gray-400 text-sm">超时</div>
238
+ <div class="text-lg">{{ sdkInfo.timeout }}s</div>
239
+ </div>
240
+ </div>
241
+ <div class="bg-gray-800 rounded-lg p-4">
242
+ <h3 class="text-sm text-gray-400 mb-2">配置</h3>
243
+ <pre class="text-xs font-mono text-gray-300 whitespace-pre-wrap">{{ JSON.stringify(sdkInfo.config, null, 2) }}</pre>
244
+ </div>
245
+ </section>
246
+ <section v-show="activeTab==='channels'">
247
+ <div class="mb-4">
248
+ <input v-model="channelSearch" type="text" placeholder="搜索渠道..."
249
+ class="bg-gray-800 border border-gray-600 rounded px-3 py-2 text-sm w-64 focus:outline-none focus:border-blue-500">
250
+ </div>
251
+ <div class="bg-gray-800 rounded-lg overflow-hidden">
252
+ <table class="w-full text-sm">
253
+ <thead class="bg-gray-750">
254
+ <tr class="border-b border-gray-700">
255
+ <th class="px-4 py-2 text-left text-gray-400">#</th>
256
+ <th class="px-4 py-2 text-left text-gray-400">渠道标识</th>
257
+ <th class="px-4 py-2 text-left text-gray-400">名称</th>
258
+ <th class="px-4 py-2 text-left text-gray-400">网站</th>
259
+ </tr>
260
+ </thead>
261
+ <tbody>
262
+ <tr v-for="(ch, i) in filteredChannels" :key="ch.channel"
263
+ class="border-b border-gray-700/50 hover:bg-gray-700/30">
264
+ <td class="px-4 py-2 text-gray-500">{{ i + 1 }}</td>
265
+ <td class="px-4 py-2 font-mono">{{ ch.channel }}</td>
266
+ <td class="px-4 py-2">{{ ch.name }}</td>
267
+ <td class="px-4 py-2"><a :href="'https://'+ch.website" target="_blank" class="text-blue-400 hover:underline">{{ ch.website }}</a></td>
268
+ </tr>
269
+ </tbody>
270
+ </table>
271
+ </div>
272
+ </section>
273
+ <section v-show="activeTab==='logs'">
274
+ <div class="flex items-center gap-3 mb-4">
275
+ <select v-model="logLevel" class="bg-gray-800 border border-gray-600 rounded px-2 py-1 text-sm">
276
+ <option value="all">全部</option>
277
+ <option value="debug">Debug</option>
278
+ <option value="info">Info</option>
279
+ <option value="warn">Warn</option>
280
+ <option value="error">Error</option>
281
+ </select>
282
+ <button @click="logs=[]" class="text-sm text-gray-400 hover:text-white">清空</button>
283
+ <label class="text-sm text-gray-400 flex items-center gap-1">
284
+ <input type="checkbox" v-model="autoScroll"> 自动滚动
285
+ </label>
286
+ <span class="text-xs text-gray-500 ml-auto">{{ logs.length }} 条</span>
287
+ </div>
288
+ <div id="log-container" ref="logContainer" class="bg-gray-950 rounded-lg p-4 font-mono text-xs">
289
+ <div v-for="(log, i) in filteredLogs" :key="i" class="py-0.5" :class="'log-'+log.level">
290
+ <span class="text-gray-600">{{ log.time }}</span>
291
+ <span class="px-1">[{{ log.level.toUpperCase() }}]</span>
292
+ <span v-if="log.channel" class="text-purple-400">[{{ log.channel }}]</span>
293
+ {{ log.msg }}
294
+ </div>
295
+ <div v-if="filteredLogs.length===0" class="text-gray-600">暂无日志</div>
296
+ </div>
297
+ </section>
298
+ </main>
299
+ </div>
300
+ <!-- PLACEHOLDER_SCRIPT -->
301
+ </body>
302
+ </html>
303
+ HTML
304
+
305
+ APP_SCRIPT = <<~'JS'
306
+ <script>
307
+ const {createApp, ref, computed, onMounted, onUnmounted, nextTick} = Vue
308
+ createApp({
309
+ setup() {
310
+ const tabs = [{id:'overview',label:'概览'},{id:'channels',label:'渠道'},{id:'logs',label:'日志'}]
311
+ const activeTab = ref('overview')
312
+ const connected = ref(false)
313
+ const sdkInfo = ref({language:'',version:'',port:'',proxy:'',timeout:30,config:{}})
314
+ const channels = ref([])
315
+ const logs = ref([])
316
+ const channelSearch = ref('')
317
+ const logLevel = ref('all')
318
+ const autoScroll = ref(true)
319
+ const logContainer = ref(null)
320
+ let evtSource = null
321
+ const filteredChannels = computed(() => {
322
+ if (!channelSearch.value) return channels.value
323
+ const q = channelSearch.value.toLowerCase()
324
+ return channels.value.filter(c =>
325
+ c.channel.includes(q) || c.name.toLowerCase().includes(q) || c.website.includes(q))
326
+ })
327
+ const filteredLogs = computed(() => {
328
+ if (logLevel.value === 'all') return logs.value
329
+ return logs.value.filter(l => l.level === logLevel.value)
330
+ })
331
+ async function fetchInfo() {
332
+ try { const r = await fetch('/api/info'); if (r.ok) sdkInfo.value = await r.json() } catch(e) {}
333
+ }
334
+ async function fetchChannels() {
335
+ try { const r = await fetch('/api/channels'); if (r.ok) channels.value = await r.json() } catch(e) {}
336
+ }
337
+ function connectSSE() {
338
+ evtSource = new EventSource('/api/logs/stream')
339
+ evtSource.onopen = () => { connected.value = true }
340
+ evtSource.onmessage = (e) => {
341
+ try {
342
+ const entry = JSON.parse(e.data)
343
+ logs.value.push(entry)
344
+ if (logs.value.length > 5000) logs.value.splice(0, 500)
345
+ if (autoScroll.value) nextTick(() => { const el = logContainer.value; if (el) el.scrollTop = el.scrollHeight })
346
+ } catch(err) {}
347
+ }
348
+ evtSource.onerror = () => { connected.value = false; setTimeout(connectSSE, 3000) }
349
+ }
350
+ onMounted(() => { fetchInfo(); fetchChannels(); connectSSE() })
351
+ onUnmounted(() => { if (evtSource) evtSource.close() })
352
+ return {tabs,activeTab,connected,sdkInfo,channels,logs,channelSearch,logLevel,
353
+ autoScroll,logContainer,filteredChannels,filteredLogs}
354
+ }
355
+ }).mount('#app')
356
+ </script>
357
+ JS
358
+ # rubocop:enable Layout/LineLength
359
+ end
360
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # 临时邮箱 SDK (Ruby)
4
+ # 聚合 279 个第三方临时邮箱渠道,所有渠道返回统一标准化格式。
5
+ # 与 Go / npm / Rust / Python / C / PHP 各端共享相同的渠道标识与顺序。
6
+
7
+ require_relative "tempmail_sdk/version"
8
+ require_relative "tempmail_sdk/types"
9
+ require_relative "tempmail_sdk/config"
10
+ require_relative "tempmail_sdk/logger"
11
+ require_relative "tempmail_sdk/html_utils"
12
+ require_relative "tempmail_sdk/normalize"
13
+ require_relative "tempmail_sdk/http"
14
+ require_relative "tempmail_sdk/retry"
15
+ require_relative "tempmail_sdk/telemetry"
16
+ require_relative "tempmail_sdk/channels"
17
+ require_relative "tempmail_sdk/registry"
18
+ require_relative "tempmail_sdk/client"
19
+ require_relative "tempmail_sdk/webui"
20
+
21
+ # 顶层命名空间:聚合各端一致的临时邮箱 SDK 能力
22
+ module TempmailSdk
23
+ module_function
24
+
25
+ # 创建临时邮箱(无状态入口,支持渠道 fallback)
26
+ # @param options [GenerateEmailOptions, nil]
27
+ # @return [EmailInfo, nil]
28
+ def generate_email(options = nil)
29
+ Client.generate_email(options)
30
+ end
31
+
32
+ # 获取邮件列表(无状态入口)
33
+ # @param info [EmailInfo]
34
+ # @param options [GetEmailsOptions, nil]
35
+ # @return [GetEmailsResult]
36
+ def get_emails(info, options = nil)
37
+ Client.get_emails(info, options)
38
+ end
39
+
40
+ # 获取所有支持的渠道列表(有序)
41
+ # @return [Array<ChannelInfo>]
42
+ def list_channels
43
+ Client.list_channels
44
+ end
45
+
46
+ # 获取指定渠道的详细信息
47
+ # @param channel [String]
48
+ # @return [ChannelInfo, nil]
49
+ def channel_info(channel)
50
+ Client.channel_info(channel)
51
+ end
52
+
53
+ # 设置 SDK 全局配置
54
+ def set_config(config = nil, **kwargs)
55
+ Config.set_config(config, **kwargs)
56
+ end
57
+
58
+ # 获取当前全局配置
59
+ # @return [SDKConfig]
60
+ def config
61
+ Config.get_config
62
+ end
63
+
64
+ # 设置日志级别
65
+ def set_log_level(level)
66
+ Log.set_log_level(level)
67
+ end
68
+
69
+ # @return [String] SDK 版本号
70
+ def sdk_version
71
+ VERSION
72
+ end
73
+ end
74
+
75
+ # 加载后按环境变量自动启动 WebUI(默认不启动)
76
+ TempmailSdk::WebUI.auto_start
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tempmail_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.3
5
+ platform: ruby
6
+ authors:
7
+ - tempmail-sdk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-07-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 五端(Go/npm/Rust/Python/C)之外的 Ruby 版临时邮箱 SDK,共享相同的渠道标识与顺序,提供统一的 Email 结构、渠道
14
+ fallback、代理/超时/TLS/遥测配置。
15
+ email:
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/tempmail_sdk.rb
22
+ - lib/tempmail_sdk/channels.rb
23
+ - lib/tempmail_sdk/channels_data.rb
24
+ - lib/tempmail_sdk/client.rb
25
+ - lib/tempmail_sdk/config.rb
26
+ - lib/tempmail_sdk/html_utils.rb
27
+ - lib/tempmail_sdk/http.rb
28
+ - lib/tempmail_sdk/logger.rb
29
+ - lib/tempmail_sdk/normalize.rb
30
+ - lib/tempmail_sdk/providers/anonbox.rb
31
+ - lib/tempmail_sdk/providers/anonymmail.rb
32
+ - lib/tempmail_sdk/providers/byom.rb
33
+ - lib/tempmail_sdk/providers/catchmail.rb
34
+ - lib/tempmail_sdk/providers/cleantempmail.rb
35
+ - lib/tempmail_sdk/providers/devmail_uk.rb
36
+ - lib/tempmail_sdk/providers/dropmail.rb
37
+ - lib/tempmail_sdk/providers/dropmail_click.rb
38
+ - lib/tempmail_sdk/providers/dropmail_me.rb
39
+ - lib/tempmail_sdk/providers/duckmail.rb
40
+ - lib/tempmail_sdk/providers/eyepaste.rb
41
+ - lib/tempmail_sdk/providers/fake_email_site.rb
42
+ - lib/tempmail_sdk/providers/fake_legal.rb
43
+ - lib/tempmail_sdk/providers/fmail.rb
44
+ - lib/tempmail_sdk/providers/freecustom.rb
45
+ - lib/tempmail_sdk/providers/getnada.rb
46
+ - lib/tempmail_sdk/providers/gonebox_email.rb
47
+ - lib/tempmail_sdk/providers/guerrillamail.rb
48
+ - lib/tempmail_sdk/providers/guerrillamail_mirrors.rb
49
+ - lib/tempmail_sdk/providers/harakirimail.rb
50
+ - lib/tempmail_sdk/providers/haribu.rb
51
+ - lib/tempmail_sdk/providers/inboxes.rb
52
+ - lib/tempmail_sdk/providers/inboxkitten.rb
53
+ - lib/tempmail_sdk/providers/linshiyou.rb
54
+ - lib/tempmail_sdk/providers/lroid.rb
55
+ - lib/tempmail_sdk/providers/m2u.rb
56
+ - lib/tempmail_sdk/providers/mail10s.rb
57
+ - lib/tempmail_sdk/providers/mail123.rb
58
+ - lib/tempmail_sdk/providers/mail_cx.rb
59
+ - lib/tempmail_sdk/providers/mail_sunls.rb
60
+ - lib/tempmail_sdk/providers/mail_tm.rb
61
+ - lib/tempmail_sdk/providers/mailcatch.rb
62
+ - lib/tempmail_sdk/providers/maildrop.rb
63
+ - lib/tempmail_sdk/providers/maildrop_cc.rb
64
+ - lib/tempmail_sdk/providers/mailforspam.rb
65
+ - lib/tempmail_sdk/providers/mailhole_de.rb
66
+ - lib/tempmail_sdk/providers/mailinator.rb
67
+ - lib/tempmail_sdk/providers/mailmomy.rb
68
+ - lib/tempmail_sdk/providers/mailnesia.rb
69
+ - lib/tempmail_sdk/providers/mffac.rb
70
+ - lib/tempmail_sdk/providers/moakt.rb
71
+ - lib/tempmail_sdk/providers/neighbours.rb
72
+ - lib/tempmail_sdk/providers/neighbours_sh.rb
73
+ - lib/tempmail_sdk/providers/nimail.rb
74
+ - lib/tempmail_sdk/providers/ockito.rb
75
+ - lib/tempmail_sdk/providers/one_sec_mail.rb
76
+ - lib/tempmail_sdk/providers/restmail_net.rb
77
+ - lib/tempmail_sdk/providers/rootsh.rb
78
+ - lib/tempmail_sdk/providers/shitty_email.rb
79
+ - lib/tempmail_sdk/providers/smailpro.rb
80
+ - lib/tempmail_sdk/providers/ta_easy.rb
81
+ - lib/tempmail_sdk/providers/temp_mail_io.rb
82
+ - lib/tempmail_sdk/providers/temp_mail_now.rb
83
+ - lib/tempmail_sdk/providers/temp_mail_org.rb
84
+ - lib/tempmail_sdk/providers/tempemail_co.rb
85
+ - lib/tempmail_sdk/providers/tempemail_info.rb
86
+ - lib/tempmail_sdk/providers/tempemails_net.rb
87
+ - lib/tempmail_sdk/providers/tempfastmail.rb
88
+ - lib/tempmail_sdk/providers/tempgmailer.rb
89
+ - lib/tempmail_sdk/providers/tempgo_email.rb
90
+ - lib/tempmail_sdk/providers/tempinbox.rb
91
+ - lib/tempmail_sdk/providers/tempmail.rb
92
+ - lib/tempmail_sdk/providers/tempmail365.rb
93
+ - lib/tempmail_sdk/providers/tempmail_fish.rb
94
+ - lib/tempmail_sdk/providers/tempmail_fyi.rb
95
+ - lib/tempmail_sdk/providers/tempmail_lol.rb
96
+ - lib/tempmail_sdk/providers/tempmail_lol_v2.rb
97
+ - lib/tempmail_sdk/providers/tempmail_plus.rb
98
+ - lib/tempmail_sdk/providers/tempmailc.rb
99
+ - lib/tempmail_sdk/providers/tempmailpro.rb
100
+ - lib/tempmail_sdk/providers/tempmailten.rb
101
+ - lib/tempmail_sdk/providers/temporam.rb
102
+ - lib/tempmail_sdk/providers/tempp_mails.rb
103
+ - lib/tempmail_sdk/providers/tempy_email.rb
104
+ - lib/tempmail_sdk/providers/ten_minute_mail_net.rb
105
+ - lib/tempmail_sdk/providers/tenminute_one.rb
106
+ - lib/tempmail_sdk/providers/throwawaymail.rb
107
+ - lib/tempmail_sdk/providers/tmail_link.rb
108
+ - lib/tempmail_sdk/providers/uncorreotemporal.rb
109
+ - lib/tempmail_sdk/providers/webmailtemp.rb
110
+ - lib/tempmail_sdk/providers/xkx_me.rb
111
+ - lib/tempmail_sdk/providers/zhujump.rb
112
+ - lib/tempmail_sdk/registry.rb
113
+ - lib/tempmail_sdk/retry.rb
114
+ - lib/tempmail_sdk/telemetry.rb
115
+ - lib/tempmail_sdk/types.rb
116
+ - lib/tempmail_sdk/version.rb
117
+ - lib/tempmail_sdk/webui.rb
118
+ homepage: https://github.com/tempmail-sdk/tempmail-sdk
119
+ licenses:
120
+ - GPL-3.0-only
121
+ metadata:
122
+ rubygems_mfa_required: 'false'
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.4.19
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: 临时邮箱 SDK,聚合 279 个第三方临时邮箱渠道,返回统一标准化格式
142
+ test_files: []