Ruby Gmail API 获取邮件时正文为空,如何读取?
数据小许
结论
邮件正文不一定在 payload.body.data 中。Gmail API 会根据 MIME 结构返回邮件内容:单部分邮件的正文通常在 payload.body.data,多部分邮件的正文可能在 payload.parts 的子部分中。body.data 使用 Base64URL 编码,读取前需要先解码。
raw 字段保存的是原始邮件数据。调用 messages.get 时,指定 format: 'raw' 才会读取该字段;要获取完整解析后的邮件结构,则使用 format: 'full'。因此,puts updated_message.raw 输出为空,不能说明邮件没有正文。
请求完整邮件结构
请求时可以指定 full 格式。下面使用 Google Ruby API 客户端常见的选项哈希写法;具体传参方式请以你使用的客户端版本为准:
message = gmail.get_user_message('me', message_id, format: 'full')
拿到消息后,检查 message.payload.mime_type、message.payload.body.data 和 message.payload.parts。如果消息是 multipart/alternative 或其他 multipart 类型,正文通常在 parts 中,而不是顶层的 body。
遍历 MIME parts 并解码正文
下面的示例递归遍历各部分,优先提取 text/plain,并用 Ruby 的 Base64.urlsafe_decode64 解码 Gmail 返回的数据:
require 'base64'
def collect_text_parts(part, mime_type, result)
if part.mime_type == mime_type && part.body&.data
result << Base64.urlsafe_decode64(part.body.data)
end
Array(part.parts).each do |child|
collect_text_parts(child, mime_type, result)
end
end
messages.each do |listed_message|
message = gmail.get_user_message('me', listed_message.id, format: 'full')
payload = message.payload
plain_text = []
collect_text_parts(payload, 'text/plain', plain_text)
if plain_text.empty?
html = []
collect_text_parts(payload, 'text/html', html)
puts html.join("\n")
else
puts plain_text.join("\n")
end
end
如果只需要查看原始 RFC 822 邮件内容,可以请求 raw 格式,再解码 raw 字段:
message = gmail.get_user_message('me', message_id, format: 'raw')
raw_email = Base64.urlsafe_decode64(message.raw)
puts raw_email
raw 包含完整的原始邮件内容,可能包括邮件头、MIME 分隔符和编码后的正文。它不是提取好的纯文本正文。
检查事项
- 确认请求使用的是
full还是raw,并检查返回的payload.mime_type和payload.parts。 - 如果正文是 HTML,示例会输出
text/html部分。需要以纯文本展示时,还要自行转换 HTML。 - 如果某个 MIME part 只有
body.attachment_id,没有body.data,需要按照 Gmail API 的附件读取方式另行获取该部分内容。
备注:内容仅供参考。
