背景
RailsでGmailを大量に取り込んで解析みたいなアプリを作る必要があった。
で便利なGemがあるみたいなのだが、
本家のgoogle-api-client以外だとGmailの設定で安全性の低いアプリからのアカウントへのアクセスを許可するというのをやらんといかんらしい。
で、本家のgoogle-api-clientがムズイムズイ。
結局HOWTO access the Gmail API with Rubyにお世話になった。
英語、、、なので、ちょっと日本語でその雰囲気を書いていきます。
まずはGmailAPIを有効化
GoogleデベロッパーコンソールでGmailAPIを有効化。
それで、Client IDとClient secretをゲットする。
またリダイレクトURIはhttp://XXXXXX.XXX/gmail/callback
とかにしておく。
このあたりまでは、ググってなんとかイケる。
gem 'google-api-client'の導入
ここも普通にGemfile
に書き込んでbundle
Authorization CodeとAccess Token
そしてムズイのがこれ。
Gmailを取得するには、
- まずAuthorization Codeを取得して、
- Authorization CodeをつかってAccess Tokenを取得して
- Access Tokenをつかってメールを取得
せねばならない。
これをコントローラーに落とし込んでいくのだ。
コントローラの全体像
先ほどのリダイレクトURIであるhttp://XXXXXX.XXX/gmail/callback
のgmailコントローラを作成。
class GmailController < ApplicationController
end
で、
- 最初のアクションである
redirect
アクションを作成し -
callback
アクションを作成し(ここは先ほどのリダイレクトURIであるhttp://XXXXXX.XXX/gmail/callback
に合わせる) - 最後に
getmail
アクションを作成する
class GmailController < ApplicationController
def redirect
end
def callback
end
def getmail
end
end
redirect
アクションにてAuthorization Codeを取得してcallback
アクションにリダイレクト
class GmailController < ApplicationController
def redirect
client = Signet::OAuth2::Client.new({
client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'),
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
scope: Google::Apis::GmailV1::AUTH_GMAIL_READONLY,
client.redirect_uri = url_for(action: :callback)
})
redirect_to client.authorization_uri.to_s
end
def callback
end
def getmail
end
end
これで、Googleの認証ページに移動し、Authorization CodeをつかってリダイレクトURIであるhttp://XXXXXX.XXX/gmail/callback
にリダイレクトします。
(あー、わけわからん)
callbackアクションでAccess Tokenを取得
class GmailController < ApplicationController
def redirect
client = Signet::OAuth2::Client.new({
client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'),
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
scope: Google::Apis::GmailV1::AUTH_GMAIL_READONLY,
client.redirect_uri = url_for(action: :callback)
})
redirect_to client.authorization_uri.to_s
end
def callback
client = Signet::OAuth2::Client.new({
client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET')
})
client.token_credential_uri = 'https://www.googleapis.com/oauth2/v3/token'
client.redirect_uri = url_for(action: :callback)
client.code = params[:code]
response = client.fetch_access_token!
session[:access_token] = response['access_token']
redirect_to url_for(action: :getmail)
end
def getmail
end
end
redirect
アクションと同じようにclient
をnewしますが、fetch_access_token!
メソッドでAccess Tokenを取得できます。
こいつをsession
に入れておきます。
そしてgetmail
アクションにリダイレクトします。
Access TokenをつかってGmailAPIでメッセージを取得
最後に、Access TokenをつかってGmailAPIでメッセージを取得します。
class GmailController < ApplicationController
def redirect
client = Signet::OAuth2::Client.new({
client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'),
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
scope: Google::Apis::GmailV1::AUTH_GMAIL_READONLY,
client.redirect_uri = url_for(action: :callback)
})
redirect_to client.authorization_uri.to_s
end
def callback
client = Signet::OAuth2::Client.new({
client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET')
})
client.token_credential_uri = 'https://www.googleapis.com/oauth2/v3/token'
client.redirect_uri = url_for(action: :callback)
client.code = params[:code]
response = client.fetch_access_token!
session[:access_token] = response['access_token']
redirect_to url_for(action: :getmail)
end
include GmailCallbacksHelper
def getmail
token = session[:access_token]
query = "検索キーワード"
@messages = get_messages(token, query)["messages"]
end
end
ちょっと長くなるので、以下のHelper使ってます。
include GmailCallbacksHelper
を忘れないように!
Helperからコントローラーに呼び出していいかは分からんが、とりあえず呼び出したった。
module GmailHelper
def get_messages(token, query)
uri = URI.parse("https://www.googleapis.com/gmail/v1/users/me/messages?q=#{query}")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{token}"
req_options = { use_ssl: uri.scheme == "https" }
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
JSON.parse(response.body)
end
end
@messages
にメールが入ってます。
ルーティング
ルーティングも忘れずに設定しましょう。
Rails.application.routes.draw do
get '/gmail/redirect'
get '/gmail/callback'
get '/gmail/getmail'
end
むずかった。ほんま。