Module: TempmailSdk::Normalize
- Defined in:
- lib/tempmail_sdk/normalize.rb
Overview
邮件数据标准化模块 将各提供商返回的原始邮件数据(Hash,键为字符串)标准化为统一的 Email 格式
Constant Summary collapse
- ID_KEYS =
各字段的候选键顺序(frozen 常量,避免每次调用重复分配数组)
%w[id eid _id mailboxId messageId mail_id].freeze
- FROM_KEYS =
%w[from_addr from_address fromAddress mail_sender sender address_from from_email from messageFrom].freeze
- TO_KEYS =
%w[to to_address toAddress name_to email_address address].freeze
- SUBJECT_KEYS =
%w[subject e_subject mail_title].freeze
- TEXT_KEYS =
%w[text text_body preview_text mail_body_text body content body_text text_content description].freeze
- HTML_KEYS =
%w[html html_body html_content body_html mail_body_html].freeze
- DATE_STR_KEYS =
%w[received_at receivedAt created_at createdAt date].freeze
- DATE_NUM_KEYS =
%w[timestamp e_date].freeze
- IS_READ_BOOL_KEYS =
%w[seen read isRead].freeze
- IS_READ_MIXED_KEYS =
%w[is_read is_seen].freeze
- TRAILING_Z_RE =
日期解析用预编译正则(避免方法内每次新建 Regexp)
/Z\z/.freeze
Class Method Summary collapse
-
.get_str(raw, *keys) ⇒ Object
从 Hash 中按优先级顺序提取字符串值.
-
.get_str_keys(raw, keys) ⇒ Object
从 Hash 中按给定候选键数组(可复用 frozen 常量)提取字符串值.
-
.html_content?(content) ⇒ Boolean
检测内容是否为 HTML(只取前 200 字符).
-
.normalize_attachments(attachments) ⇒ Object
提取并标准化附件列表.
-
.normalize_date(raw) ⇒ Object
提取并统一日期格式为 ISO 8601.
-
.normalize_email(raw, recipient_email = "") ⇒ Email
将各提供商返回的原始邮件数据标准化为统一的 Email 格式 不同渠道字段名各异,此函数通过多字段候选策略统一映射.
- .normalize_from(raw) ⇒ Object
- .normalize_html(raw) ⇒ Object
- .normalize_id(raw) ⇒ Object
-
.normalize_is_read(raw) ⇒ Object
提取已读状态,支持 bool / int(0|1) / str('0'|'1').
- .normalize_subject(raw) ⇒ Object
- .normalize_text(raw) ⇒ Object
- .normalize_to(raw, recipient_email) ⇒ Object
-
.parse_date_value(val) ⇒ Object
解析单个日期值(字符串/秒/毫秒时间戳).
-
.stringify_keys(raw) ⇒ Object
将 Hash 的符号键统一转为字符串键(浅层).
Class Method Details
.get_str(raw, *keys) ⇒ Object
从 Hash 中按优先级顺序提取字符串值
80 81 82 |
# File 'lib/tempmail_sdk/normalize.rb', line 80 def get_str(raw, *keys) get_str_keys(raw, keys) end |
.get_str_keys(raw, keys) ⇒ Object
从 Hash 中按给定候选键数组(可复用 frozen 常量)提取字符串值
85 86 87 88 89 90 91 |
# File 'lib/tempmail_sdk/normalize.rb', line 85 def get_str_keys(raw, keys) keys.each do |key| val = raw[key] return val.to_s unless val.nil? end "" end |
.html_content?(content) ⇒ Boolean
检测内容是否为 HTML(只取前 200 字符)
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/tempmail_sdk/normalize.rb', line 67 def html_content?(content) prefix = content[0, 200].to_s.strip.downcase return true if prefix.start_with?("<!doctype html", "<html", "<body") trimmed = content.strip.downcase return true if trimmed.include?("<div") && trimmed.include?("</div>") return true if trimmed.include?("<table") && trimmed.include?("</table>") return true if trimmed.include?("<p") && trimmed.include?("</p>") && trimmed.include?("<") false end |
.normalize_attachments(attachments) ⇒ Object
提取并标准化附件列表
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/tempmail_sdk/normalize.rb', line 177 def () return [] unless .is_a?(Array) .filter_map do |a| a = stringify_keys(a) next unless a.is_a?(Hash) EmailAttachment.new( filename: a["filename"] || a["name"] || "", size: a["size"] || a["filesize"], content_type: a["contentType"] || a["content_type"] || a["mimeType"] || a["mime_type"], url: a["url"] || a["download_url"] || a["downloadUrl"] ) end end |
.normalize_date(raw) ⇒ Object
提取并统一日期格式为 ISO 8601
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/tempmail_sdk/normalize.rb', line 119 def normalize_date(raw) DATE_STR_KEYS.each do |key| val = raw[key] next if val.nil? return parse_date_value(val) end DATE_NUM_KEYS.each do |key| val = raw[key] next unless val.is_a?(Numeric) && val.positive? secs = key == "timestamp" && val < 1e12 ? val : val / 1000.0 return Time.at(secs).utc.iso8601 end "" end |
.normalize_email(raw, recipient_email = "") ⇒ Email
将各提供商返回的原始邮件数据标准化为统一的 Email 格式 不同渠道字段名各异,此函数通过多字段候选策略统一映射
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/tempmail_sdk/normalize.rb', line 33 def normalize_email(raw, recipient_email = "") raw = stringify_keys(raw) text = normalize_text(raw) html = normalize_html(raw) # 修正 text/html 错配 if !text.empty? && html.empty? && html_content?(text) html = text text = "" end text = HtmlUtils.html_to_text(html) if text.empty? && !html.empty? html = "<html><body><pre>#{HtmlUtils.escape(text)}</pre></body></html>" if !text.empty? && html.empty? Email.new( id: normalize_id(raw), from_addr: normalize_from(raw), to: normalize_to(raw, recipient_email), subject: normalize_subject(raw), text: text, html: html, date: normalize_date(raw), is_read: normalize_is_read(raw), attachments: (raw["attachments"]) ) end |
.normalize_from(raw) ⇒ Object
97 98 99 |
# File 'lib/tempmail_sdk/normalize.rb', line 97 def normalize_from(raw) get_str_keys(raw, FROM_KEYS) end |
.normalize_html(raw) ⇒ Object
114 115 116 |
# File 'lib/tempmail_sdk/normalize.rb', line 114 def normalize_html(raw) get_str_keys(raw, HTML_KEYS) end |
.normalize_id(raw) ⇒ Object
93 94 95 |
# File 'lib/tempmail_sdk/normalize.rb', line 93 def normalize_id(raw) get_str_keys(raw, ID_KEYS) end |
.normalize_is_read(raw) ⇒ Object
提取已读状态,支持 bool / int(0|1) / str('0'|'1')
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/tempmail_sdk/normalize.rb', line 158 def normalize_is_read(raw) IS_READ_BOOL_KEYS.each do |key| val = raw[key] return val if val == true || val == false end IS_READ_MIXED_KEYS.each do |key| val = raw[key] next if val.nil? return val if [true, false].include?(val) return val.to_i != 0 if val.is_a?(Numeric) return val == "1" if val.is_a?(String) end false end |
.normalize_subject(raw) ⇒ Object
106 107 108 |
# File 'lib/tempmail_sdk/normalize.rb', line 106 def normalize_subject(raw) get_str_keys(raw, SUBJECT_KEYS) end |
.normalize_text(raw) ⇒ Object
110 111 112 |
# File 'lib/tempmail_sdk/normalize.rb', line 110 def normalize_text(raw) get_str_keys(raw, TEXT_KEYS) end |
.normalize_to(raw, recipient_email) ⇒ Object
101 102 103 104 |
# File 'lib/tempmail_sdk/normalize.rb', line 101 def normalize_to(raw, recipient_email) result = get_str_keys(raw, TO_KEYS) result.empty? ? recipient_email : result end |
.parse_date_value(val) ⇒ Object
解析单个日期值(字符串/秒/毫秒时间戳)
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/tempmail_sdk/normalize.rb', line 139 def parse_date_value(val) if val.is_a?(String) && !val.empty? begin return Time.iso8601(val.sub(TRAILING_Z_RE, "+00:00")).iso8601 rescue ArgumentError begin return Time.strptime("#{val} UTC", "%Y-%m-%d %H:%M:%S %Z").utc.iso8601 rescue ArgumentError return val end end elsif val.is_a?(Numeric) && val.positive? secs = val > 1e12 ? val / 1000.0 : val return Time.at(secs).utc.iso8601 end "" end |
.stringify_keys(raw) ⇒ Object
将 Hash 的符号键统一转为字符串键(浅层)
60 61 62 63 64 |
# File 'lib/tempmail_sdk/normalize.rb', line 60 def stringify_keys(raw) return {} unless raw.is_a?(Hash) raw.each_with_object({}) { |(k, v), h| h[k.to_s] = v } end |