You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby脚本调用Gmail API插入邮件异常:空邮件无发件人主题

解决Gmail API插入邮件无发件人、无主题的问题

问题根源

代码核心问题出在Base64编码处理和Mail gem生成的邮件格式兼容性上:

  1. Base64.urlsafe_encode64默认会每60个字符插入换行符,而Gmail API要求raw字段是无换行的连续Base64URL编码字符串,换行会导致Gmail无法正确解析邮件头。
  2. Mail gem生成的邮件头未显式指定UTF-8编码,可能导致Gmail解析时丢失主题、发件人等关键信息。

修复方案

1. 修正Base64编码逻辑

移除编码后的换行符,确保raw字段为连续字符串:

raw = Base64.urlsafe_encode64(message.to_s).gsub("\n", "")

2. 显式设置邮件字符编码

在Mail构建块中添加UTF-8编码声明,确保邮件头和正文的编码兼容性:

message = Mail.new do
  from    sender
  to      to
  subject subject
  charset 'UTF-8' # 全局字符集声明
  text_part do
    body plain_text
    charset 'UTF-8' # 纯文本部分编码
  end
  html_part do
    content_type 'text/html; charset=UTF-8'
    body html_content
    charset 'UTF-8' # HTML部分编码
  end
end

3. 确认Service Account配置

虽然Python版本正常运行,仍需验证:

  • Service Account已启用域范围委派
  • Google Admin控制台中已为该账号授权https://www.googleapis.com/auth/gmail.insert权限
  • 被模拟的用户邮箱属于你的G Suite/Workspace域

修改后的完整代码

require 'google/apis/gmail_v1'
require 'googleauth'
require 'base64'
require 'mail'

class GmailServiceAccount
  SCOPES = ['https://www.googleapis.com/auth/gmail.insert']

  def initialize(service_account_file)
    @service_account_file = service_account_file
    @token_cache = {}
  end

  def get_service(user_email)
    return @token_cache[user_email] if @token_cache.key?(user_email)

    credentials = Google::Auth::ServiceAccountCredentials.make_creds(
      json_key_io: File.open(@service_account_file),
      scope: SCOPES
    ).dup
    credentials.sub = user_email

    service = Google::Apis::GmailV1::GmailService.new
    service.authorization = credentials
    @token_cache[user_email] = service
    service
  end

  def create_html_message(sender, to, subject, html_content, plain_text = nil)
    plain_text ||= "Please use an HTML capable email client to view this message."

    message = Mail.new do
      from    sender
      to      to
      subject subject
      charset 'UTF-8'
      text_part do
        body plain_text
        charset 'UTF-8'
      end
      html_part do
        content_type 'text/html; charset=UTF-8'
        body html_content
        charset 'UTF-8'
      end
    end

    puts "Constructed Message:\n#{message}"

    raw = Base64.urlsafe_encode64(message.to_s).gsub("\n", "")
    { raw: raw }
  end

  def insert_html_email(user_email, sender, subject, html_template_path, template_variables = {})
    begin
      html_content = File.read(html_template_path, encoding: 'utf-8')

      template_variables.each do |key, value|
        html_content.gsub!("{{ #{key} }}", value.to_s)
      end

      service = get_service(user_email)
      message = create_html_message(sender, user_email, subject, html_content)

      puts "Encoded Raw Message:\n#{message[:raw]}"

      message_body = {
        raw: message[:raw],
        labelIds: ['INBOX', 'UNREAD']
      }

      result = service.insert_user_message(user_email, message_body)

      { user: user_email, status: 'success', message_id: result.id }
    rescue => e
      { user: user_email, status: 'error', error: e.message }
    end
  end
end

# Command-line execution
if __FILE__ == $0
  service_account_file = 'path/to/your/service-account-key.json'
  user_email = 'recipient@example.com'
  sender = 'sender@example.com'
  subject = 'Test Email'
  html_template_path = 'email_template.html'
  template_variables = { 'name' => 'John Doe' }

  gmail_service = GmailServiceAccount.new(service_account_file)
  result = gmail_service.insert_html_email(user_email, sender, subject, html_template_path, template_variables)

  puts result
end

验证步骤

  1. 运行代码后,检查Debug输出的Constructed Message是否包含完整的From、To、Subject头和正文内容。
  2. 确认Encoded Raw Message是无换行的连续字符串。
  3. 查看收件箱,验证邮件是否正常显示发件人、主题和内容。

内容的提问来源于stack exchange,提问作者Nacio-Félix Laubressac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:40:01