Ruby on RailsでGmailAPI経由でGmailを取得する方法、、めっさムズイ。。

## 背景

RailsでGmailを大量に取り込んで解析みたいなアプリを作る必要があった。

で便利なGemがあるみたいなのだが、
本家の**google-api-client**以外だとGmailの設定で**安全性の低いアプリからのアカウントへのアクセスを許可する**というのをやらんといかんらしい。

で、本家の**google-api-client**がムズイムズイ。

結局[HOWTO access the Gmail API with Ruby](https://readysteadycode.com/howto-access-the-gmail-api-with-ruby)にお世話になった。

英語、、、なので、ちょっと日本語でその雰囲気を書いていきます。

## まずはGmailAPIを有効化

[Googleデベロッパーコンソール](https://console.developers.google.com/)でGmailAPIを有効化。
それで、**Client ID**と**Client secret**をゲットする。

またリダイレクトURIは`http://XXXXXX.XXX/gmail/callback`とかにしておく。


このあたりまでは、ググってなんとかイケる。

## gem 'google-api-client'の導入

ここも普通に`Gemfile`に書き込んで`bundle`

## Authorization CodeとAccess Token

そしてムズイのがこれ。

Gmailを取得するには、

1. まず**Authorization Code**を取得して、
2. **Authorization Code**をつかって**Access Token**を取得して
3. **Access Token**をつかってメールを取得

せねばならない。
これをコントローラーに落とし込んでいくのだ。

## コントローラの全体像

先ほどのリダイレクトURIである`http://XXXXXX.XXX/gmail/callback`の**gmail**コントローラを作成。

```app/controllers/gmail_controller.rb
class GmailController < ApplicationController
end
```

で、

1. 最初のアクションである`redirect`アクションを作成し
2. `callback`アクションを作成し（ここは先ほどのリダイレクトURIである`http://XXXXXX.XXX/gmail/callback`に合わせる）
3. 最後に`getmail`アクションを作成する

```app/controllers/gmail_controller.rb
class GmailController < ApplicationController
  def redirect
  end

  def callback
  end

  def getmail
  end
end
```

## `redirect`アクションにて**Authorization Code**を取得して`callback`アクションにリダイレクト

```app/controllers/gmail_controller.rb
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**を取得

```app/controllers/gmail_controller.rb
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でメッセージを取得します。

```app/controllers/gmail_controller.rb
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からコントローラーに呼び出していいかは分からんが、とりあえず呼び出したった。

```app/helpers/gmail_helper.rb
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`にメールが入ってます。

## ルーティング

ルーティングも忘れずに設定しましょう。

```config/routes.rb
Rails.application.routes.draw do
  get '/gmail/redirect'
  get '/gmail/callback'
  get '/gmail/getmail'
end
```

むずかった。ほんま。