求指导:不依赖库或Gem,用Ruby开发Gmail命令行客户端
纯Ruby实现Gmail命令行客户端核心思路
1. 手动实现OAuth2认证(无第三方Gem)
Gmail API要求OAuth2认证,基于Ruby标准库Net::HTTP和JSON即可完成流程:
- 先在Google Cloud Console创建项目,启用Gmail API,生成桌面应用类型的OAuth2客户端ID和密钥。
- 构造授权URL引导用户获取授权码:
client_id = "你的客户端ID" redirect_uri = "urn:ietf:wg:oauth:2.0:oob" # 桌面应用专用回调 scope = "https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.send" auth_url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=#{client_id}&redirect_uri=#{redirect_uri}&scope=#{URI.encode_www_form_component(scope)}&response_type=code" puts "请访问以下URL授权:\n#{auth_url}" print "输入授权码:" code = gets.chomp - 用授权码交换access token和refresh token:
token_uri = URI("https://oauth2.googleapis.com/token") params = { client_id: client_id, client_secret: "你的客户端密钥", code: code, redirect_uri: redirect_uri, grant_type: "authorization_code" } response = Net::HTTP.post_form(token_uri, params) token_data = JSON.parse(response.body) access_token = token_data["access_token"] refresh_token = token_data["refresh_token"] - 补充token刷新逻辑:当access token过期时,用refresh token请求新的access token。
2. 读取/接收邮件
通过Gmail REST API获取邮件列表与详情,解析MIME内容:
- 获取最近N封邮件列表:
def list_messages(access_token, max_results = 10) uri = URI("https://gmail.googleapis.com/gmail/v1/users/me/messages?maxResults=#{max_results}") req = Net::HTTP::Get.new(uri) req["Authorization"] = "Bearer #{access_token}" res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) } JSON.parse(res.body)["messages"] || [] end - 解析单封邮件的主题、发件人、正文:
def get_message(access_token, message_id) uri = URI("https://gmail.googleapis.com/gmail/v1/users/me/messages/#{message_id}?format=full") req = Net::HTTP::Get.new(uri) req["Authorization"] = "Bearer #{access_token}" res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) } msg_data = JSON.parse(res.body) # 提取并解码主题 subject_header = msg_data["payload"]["headers"].find { |h| h["name"] == "Subject" }["value"] subject = subject_header.start_with?("=?UTF-8?B?") ? Base64.decode64(subject_header.split("?")[3]) : subject_header # 提取纯文本正文(简化处理,可扩展支持HTML) body = if msg_data["payload"]["body"]["size"] > 0 Base64.urlsafe_decode64(msg_data["payload"]["body"]["data"]) else plain_part = msg_data["payload"]["parts"].find { |p| p["mimeType"] == "text/plain" } Base64.urlsafe_decode64(plain_part["body"]["data"]) end { subject: subject, body: body, from: msg_data["payload"]["headers"].find { |h| h["name"] == "From" }["value"] } end
3. 发送邮件
构造符合RFC 2822标准的邮件内容,通过API发送:
def send_email(access_token, to, subject, body) # 构造标准邮件格式 email_content = <<~EMAIL From: 你的邮箱地址 To: #{to} Subject: #{subject} Content-Type: text/plain; charset="UTF-8" #{body} EMAIL # 转换为API要求的base64url编码 encoded_email = Base64.urlsafe_encode64(email_content).gsub("\n", "") uri = URI("https://gmail.googleapis.com/gmail/v1/users/me/messages/send") req = Net::HTTP::Post.new(uri) req["Authorization"] = "Bearer #{access_token}" req["Content-Type"] = "application/json" req.body = JSON.dump({ raw: encoded_email }) res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) } res.is_a?(Net::HTTPSuccess) end
4. 命令行交互逻辑
用ARGV解析用户输入的命令,实现基础交互:
# 先从本地文件读取已保存的token(需实现持久化逻辑) access_token = "你的有效access token" case ARGV[0] when "list" messages = list_messages(access_token) messages.each_with_index do |msg, idx| puts "#{idx+1}. 邮件ID: #{msg['id']}" end when "read" message_id = ARGV[1] || (puts "请指定邮件ID"; exit) msg = get_message(access_token, message_id) puts "发件人: #{msg[:from]}" puts "主题: #{msg[:subject]}" puts "正文:\n#{msg[:body]}" when "send" to = ARGV[1] || (puts "请指定收件人"; exit) subject = ARGV[2] || (puts "请指定主题"; exit) body = ARGV[3..-1].join(" ") || (puts "请输入正文"; exit) send_email(access_token, to, subject, body) ? puts("邮件发送成功") : puts("邮件发送失败") else puts "支持的命令:\n- list:列出最近10封邮件\n- read <邮件ID>:查看指定邮件\n- send <收件人> <主题> <正文>:发送邮件" end
额外优化点
- 把token信息持久化到本地文件(如
~/.gmail_client_token.json),避免每次启动重新授权。 - 增加API错误处理,比如token过期自动刷新、网络请求失败重试。
- 扩展邮件解析逻辑,支持HTML正文、附件解析。
内容的提问来源于stack exchange,提问作者Saiyam-19
相关产品推荐
相关产品推荐

