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,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TempmailSdk
4
+ # 通用重试工具
5
+ # 提供请求重试、超时控制、指数退避等错误恢复机制
6
+ module Retry
7
+ # with_retry_with_attempts 的返回值封装
8
+ class AttemptsResult
9
+ attr_reader :ok, :attempts, :value, :error
10
+
11
+ def initialize(ok:, attempts:, value: nil, error: nil)
12
+ @ok = ok
13
+ @attempts = attempts
14
+ @value = value
15
+ @error = error
16
+ end
17
+
18
+ def ok?
19
+ @ok
20
+ end
21
+ end
22
+
23
+ # 网络级别错误关键字
24
+ NETWORK_KEYWORDS = [
25
+ "connection", "timeout", "timed out", "dns", "eof",
26
+ "broken pipe", "network is unreachable", "refused", "reset"
27
+ ].freeze
28
+
29
+ module_function
30
+
31
+ # 判断错误是否应该重试
32
+ # 触发重试:网络错误、429 限流、HTTP 4xx/5xx;仅参数校验类错误不重试
33
+ # @param error [Exception]
34
+ # @return [Boolean]
35
+ def should_retry?(error)
36
+ msg = error.message.to_s.downcase
37
+ return true if NETWORK_KEYWORDS.any? { |kw| msg.include?(kw) }
38
+ return true if msg.include?("429") || msg.include?("too many requests") || msg.include?("rate limit")
39
+ return true if msg.include?(": 4") || msg.include?(": 5")
40
+
41
+ # Net::HTTP 底层网络异常类型
42
+ case error
43
+ when Timeout::Error, Errno::ECONNREFUSED, Errno::ECONNRESET,
44
+ SocketError, EOFError, IOError
45
+ true
46
+ else
47
+ false
48
+ end
49
+ end
50
+
51
+ # 带重试的操作执行器(不抛异常版本)
52
+ # @param config [RetryConfig, nil]
53
+ # @yield 要执行的操作
54
+ # @return [AttemptsResult]
55
+ def with_retry_with_attempts(config = nil)
56
+ cfg = config || RetryConfig.new
57
+ logger = Log.logger
58
+ last_error = nil
59
+
60
+ (0..cfg.max_retries).each do |attempt|
61
+ attempts = attempt + 1
62
+ begin
63
+ result = yield
64
+ logger.info("第 #{attempt + 1} 次尝试成功") if attempt.positive?
65
+ return AttemptsResult.new(ok: true, attempts: attempts, value: result)
66
+ rescue StandardError => e
67
+ last_error = e
68
+ if attempt >= cfg.max_retries || !should_retry?(e)
69
+ return AttemptsResult.new(ok: false, attempts: attempts, error: e)
70
+ end
71
+
72
+ delay = [cfg.initial_delay * (2**attempt), cfg.max_delay].min
73
+ logger.warn("请求失败 (#{e.message}),#{format('%.1f', delay)}s 后第 #{attempt + 2} 次重试...")
74
+ sleep(delay)
75
+ end
76
+ end
77
+
78
+ AttemptsResult.new(ok: false, attempts: cfg.max_retries + 1, error: last_error)
79
+ end
80
+
81
+ # 带重试的操作执行器(失败抛异常版本)
82
+ # @param config [RetryConfig, nil]
83
+ # @yield 要执行的操作
84
+ def with_retry(config = nil, &block)
85
+ r = with_retry_with_attempts(config, &block)
86
+ return r.value if r.ok?
87
+
88
+ raise r.error
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "net/http"
5
+ require "uri"
6
+
7
+ module TempmailSdk
8
+ # 匿名用量遥测
9
+ # 默认开启,可通过配置或环境变量关闭;批量异步上报,失败静默忽略
10
+ module Telemetry
11
+ DEFAULT_URL = "https://sdk-1.openel.top/v1/event"
12
+ MAX_BATCH = 32
13
+ FLUSH_SEC = 2.0
14
+ EMAIL_RE = /[^\s@]{1,64}@[^\s@]{1,255}/.freeze
15
+ # 主机信息在进程内不变,预取为常量避免每次 flush 重复读取 RbConfig
16
+ HOST_OS = (RbConfig::CONFIG["host_os"] || "unknown").freeze
17
+ HOST_CPU = (RbConfig::CONFIG["host_cpu"] || "unknown").freeze
18
+
19
+ @queue = []
20
+ @lock = Mutex.new
21
+ @flush_thread = nil
22
+
23
+ class << self
24
+ # 上报一条遥测事件
25
+ # rubocop:disable Metrics/ParameterLists
26
+ def report(operation:, channel:, success:, attempt_count:, channels_tried:, error:)
27
+ return unless telemetry_on?
28
+
29
+ ensure_periodic
30
+
31
+ ev = {
32
+ "operation" => operation,
33
+ "channel" => channel,
34
+ "success" => success,
35
+ "attempt_count" => attempt_count,
36
+ "ts_ms" => (Time.now.to_f * 1000).to_i
37
+ }
38
+ ev["channels_tried"] = channels_tried if channels_tried.positive?
39
+ err = sanitize(error)
40
+ ev["error"] = err unless err.empty?
41
+
42
+ n = 0
43
+ @lock.synchronize do
44
+ @queue << ev
45
+ n = @queue.size
46
+ end
47
+
48
+ flush_batch if n >= MAX_BATCH
49
+ end
50
+ # rubocop:enable Metrics/ParameterLists
51
+
52
+ # @return [String] SDK 版本号
53
+ def sdk_version
54
+ VERSION
55
+ end
56
+
57
+ private
58
+
59
+ # 脱敏:邮箱替换为占位符,截断到 400 字符
60
+ def sanitize(msg)
61
+ return "" if msg.nil? || msg.empty?
62
+
63
+ msg.gsub(EMAIL_RE, "[redacted]")[0, 400]
64
+ end
65
+
66
+ def resolve_url
67
+ u = (Config.get_config.telemetry_url || "").strip
68
+ u.empty? ? DEFAULT_URL : u
69
+ end
70
+
71
+ def telemetry_on?
72
+ v = Config.get_config.telemetry_enabled
73
+ v.nil? ? true : !!v
74
+ end
75
+
76
+ # 启动周期性刷新线程(守护线程,进程退出即结束)
77
+ def ensure_periodic
78
+ @lock.synchronize do
79
+ return if @flush_thread&.alive?
80
+
81
+ @flush_thread = Thread.new do
82
+ loop do
83
+ sleep(FLUSH_SEC)
84
+ flush_batch
85
+ end
86
+ end
87
+ @flush_thread.abort_on_exception = false
88
+ end
89
+ end
90
+
91
+ # 刷新队列,异步 POST 上报
92
+ def flush_batch
93
+ events = nil
94
+ @lock.synchronize do
95
+ return if @queue.empty?
96
+
97
+ events = @queue.dup
98
+ @queue.clear
99
+ end
100
+
101
+ unless telemetry_on?
102
+ return
103
+ end
104
+
105
+ batch = {
106
+ "schema_version" => 2,
107
+ "sdk_language" => "ruby",
108
+ "sdk_version" => VERSION,
109
+ "os" => HOST_OS,
110
+ "arch" => HOST_CPU,
111
+ "events" => events
112
+ }
113
+ body = JSON.generate(batch)
114
+ Thread.new { post_body(resolve_url, body) }
115
+ end
116
+
117
+ # 实际发送(失败静默)
118
+ def post_body(url, body)
119
+ uri = URI.parse(url)
120
+ http = Net::HTTP.new(uri.host, uri.port)
121
+ http.use_ssl = (uri.scheme == "https")
122
+ http.open_timeout = 8
123
+ http.read_timeout = 8
124
+ req = Net::HTTP::Post.new(uri.request_uri)
125
+ req["Content-Type"] = "application/json; charset=utf-8"
126
+ req["User-Agent"] = "tempmail-sdk-ruby/#{VERSION}"
127
+ req.body = body
128
+ http.request(req)
129
+ rescue StandardError
130
+ nil
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TempmailSdk
4
+ # 创建临时邮箱后返回的邮箱信息
5
+ # Token 等认证信息由 SDK 内部维护,不对外暴露(token 通过私有读取器访问)
6
+ class EmailInfo
7
+ # @return [String] 创建该邮箱所使用的渠道
8
+ attr_reader :channel
9
+ # @return [String] 临时邮箱地址
10
+ attr_accessor :email
11
+ # @return [Integer, nil] 邮箱过期时间(毫秒时间戳)
12
+ attr_accessor :expires_at
13
+ # @return [Object, nil] 邮箱创建时间
14
+ attr_accessor :created_at
15
+
16
+ # @param channel [String] 渠道标识
17
+ # @param email [String] 邮箱地址
18
+ # @param token [String, nil] 认证令牌,SDK 内部维护
19
+ # @param expires_at [Integer, nil] 过期时间(毫秒时间戳)
20
+ # @param created_at [Object, nil] 创建时间
21
+ def initialize(channel:, email:, token: nil, expires_at: nil, created_at: nil)
22
+ @channel = channel
23
+ @email = email
24
+ @token = token
25
+ @expires_at = expires_at
26
+ @created_at = created_at
27
+ end
28
+
29
+ # 允许在同一 provider 派生多个渠道别名时覆写渠道标识
30
+ # @param value [String] 新的渠道标识
31
+ attr_writer :channel
32
+
33
+ # SDK 内部使用的令牌读取器(对外语义上不暴露,仅内部 dispatch 使用)
34
+ # @return [String, nil]
35
+ def token
36
+ @token
37
+ end
38
+
39
+ def to_s
40
+ "#<EmailInfo channel=#{@channel.inspect} email=#{@email.inspect} " \
41
+ "expires_at=#{@expires_at.inspect} created_at=#{@created_at.inspect}>"
42
+ end
43
+ alias inspect to_s
44
+ end
45
+
46
+ # 邮件附件信息
47
+ class EmailAttachment
48
+ attr_accessor :filename, :size, :content_type, :url
49
+
50
+ def initialize(filename: "", size: nil, content_type: nil, url: nil)
51
+ @filename = filename
52
+ @size = size
53
+ @content_type = content_type
54
+ @url = url
55
+ end
56
+
57
+ def to_h
58
+ { filename: @filename, size: @size, content_type: @content_type, url: @url }
59
+ end
60
+ end
61
+
62
+ # 标准化的邮件对象
63
+ class Email
64
+ attr_accessor :id, :from_addr, :to, :subject, :text, :html, :date, :is_read, :attachments
65
+
66
+ # rubocop:disable Metrics/ParameterLists
67
+ def initialize(id: "", from_addr: "", to: "", subject: "", text: "", html: "",
68
+ date: "", is_read: false, attachments: nil)
69
+ @id = id
70
+ @from_addr = from_addr
71
+ @to = to
72
+ @subject = subject
73
+ @text = text
74
+ @html = html
75
+ @date = date
76
+ @is_read = is_read
77
+ @attachments = attachments || []
78
+ end
79
+ # rubocop:enable Metrics/ParameterLists
80
+
81
+ def to_h
82
+ {
83
+ id: @id, from_addr: @from_addr, to: @to, subject: @subject,
84
+ text: @text, html: @html, date: @date, is_read: @is_read,
85
+ attachments: @attachments.map { |a| a.respond_to?(:to_h) ? a.to_h : a }
86
+ }
87
+ end
88
+ end
89
+
90
+ # 获取邮件列表的结果
91
+ class GetEmailsResult
92
+ attr_accessor :channel, :email, :emails, :success
93
+
94
+ def initialize(channel: "", email: "", emails: nil, success: true)
95
+ @channel = channel
96
+ @email = email
97
+ @emails = emails || []
98
+ @success = success
99
+ end
100
+ end
101
+
102
+ # 重试配置
103
+ class RetryConfig
104
+ attr_accessor :max_retries, :initial_delay, :max_delay, :timeout
105
+
106
+ # @param max_retries [Integer] 最大重试次数(不含首次请求),默认 2
107
+ # @param initial_delay [Float] 初始重试延迟(秒),默认 1.0
108
+ # @param max_delay [Float] 最大重试延迟(秒),默认 5.0
109
+ # @param timeout [Float] 请求超时(秒),默认 15.0
110
+ def initialize(max_retries: 2, initial_delay: 1.0, max_delay: 5.0, timeout: 15.0)
111
+ @max_retries = max_retries
112
+ @initial_delay = initial_delay
113
+ @max_delay = max_delay
114
+ @timeout = timeout
115
+ end
116
+ end
117
+
118
+ # 创建临时邮箱的选项
119
+ class GenerateEmailOptions
120
+ attr_accessor :channel, :duration, :domain, :retry_config,
121
+ :max_channels_tried, :total_timeout, :suffix, :domains
122
+
123
+ # rubocop:disable Metrics/ParameterLists
124
+ def initialize(channel: nil, duration: 30, domain: nil, retry_config: nil,
125
+ max_channels_tried: 20, total_timeout: 60.0, suffix: nil, domains: nil)
126
+ @channel = channel # 指定渠道,不指定则随机选择
127
+ @duration = duration # tempmail 渠道的有效期(分钟)
128
+ @domain = domain # 部分渠道指定接入域名
129
+ @retry_config = retry_config # 重试配置
130
+ @max_channels_tried = max_channels_tried # 最大尝试渠道数
131
+ @total_timeout = total_timeout # 整体超时时间(秒)
132
+ @suffix = suffix # 邮箱后缀筛选
133
+ @domains = domains # 多个目标域名
134
+ end
135
+ # rubocop:enable Metrics/ParameterLists
136
+ end
137
+
138
+ # 获取邮件的选项(Channel/Email/Token 由 SDK 从 EmailInfo 自动获取)
139
+ class GetEmailsOptions
140
+ attr_accessor :retry_config
141
+
142
+ def initialize(retry_config: nil)
143
+ @retry_config = retry_config
144
+ end
145
+ end
146
+
147
+ # 渠道信息
148
+ class ChannelInfo
149
+ attr_accessor :channel, :name, :website
150
+
151
+ def initialize(channel: "", name: "", website: "")
152
+ @channel = channel
153
+ @name = name
154
+ @website = website
155
+ end
156
+
157
+ def to_h
158
+ { channel: @channel, name: @name, website: @website }
159
+ end
160
+ end
161
+
162
+ # provider 尚未实现真实逻辑时抛出的错误(渠道仍可正常枚举)
163
+ class NotImplementedProviderError < StandardError; end
164
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TempmailSdk
4
+ # SDK 版本号
5
+ VERSION = "1.3.3"
6
+ end