Gmail APIを使ってサービス運用に応用してみる

GRIPHONE Advent Calendar 2018 21日目の記事を担当しました、Jenkinsおじさんこと鑓水です。

今回はなんと、Gmail APIをサービスの運用で使ってみたというお話です。

※この記事はGRIPHONE Advent Calendar 2018 21日目の記事です。
https://adventar.org/calendars/3147
https://qiita.com/advent-calendar/2018/griphone

みなさんGmail APIは使っていますか?

一見面白そうなAPIですが、実際使うとなると使いどころが難しいのがこのAPI。

サービス運用のちょっとしたところで使ってみたので所感を書きたいと思います。

 

Jenkinsのビルド完了通知

はい、やっぱりJenkinsのお話です笑。

今回はJenkinsのビルド完了通知をGmail APIを使ってやってみました。

なぜあえてGmail APIを用いたかというと、以前このブログで書かれた記事

「デプロイ完了を声で通知する」仕組みを作るためです。

仕組みとしては以下の流れになります。

  1. Jenkinsのビルド後の処理でE-mail通知を設定する
  2. ビルドの結果を指定のGmailアカウントに通知する
  3. ローカルのマシンからGmail APIを用いてビルド結果を取得する
  4. ビルド結果内容に応じてローカルマシンで通知する

今回は3について説明したいと思います。

 

Gmail APIの妙

Gmail APIのリファレンスはコチラ

Gmail APIを使おうと思った時にまず躓くのがOAuth2.0認証です。

しかしながらその点に関しては世の中の親切な方により多くの記事が公開されていますので

そちらを参照してください。この記事では活用例のみ記載します。

ローカルのマシンからGmail APIを叩くスクリプトのサンプルは以下です。今回はシェルスクリプトで書いています。

※ Gmail APIのレスポンスがJson形式のためjqコマンドを使用しています。

#!/bin/sh#!/bin/sh
while true ; do
REFRESH_TOKEN="XXXXXXXXXXXXX"
ACCESS_TOKEN_TMP=`curl -d "client_id=XXXXXXX.apps.googleusercontent.com&client_secret=XXXXXXXXX&refresh_token=$REFRESH_TOKEN&grant_type=refresh_token" https://accounts.google.com/o/oauth2/token |jq '.access_token'`
ACCESS_TOKEN=`echo $ACCESS_TOKEN_TMP |sed -e 's/"//g'`
RESULT=`curl -H "Authorization: Bearer $ACCESS_TOKEN" https://www.googleapis.com/gmail/v1/users/me/messages?q="is:unread"`
COUNT=$( echo $RESULT |jq '.resultSizeEstimate')

if [ $COUNT != 0 ] ; then 
 MESSAGES=$( echo $RESULT |jq '.messages') 
 #最新のメールだけ取得
 MESSAGE_ID=`echo $RESULT |jq '.messages[0]|.id' |sed -e 's/"//g'`
 MAIL=`curl -H "Authorization: Bearer $ACCESS_TOKEN" https://www.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID`  
 FROM=$( echo $MAIL |jq '.payload |.headers[]|select(.name == "From")|.value'|sed -e 's/"//g') #echo $FROM

 if [ $FROM == "griphone-sample@gmail.com" ] ; then 
  TARGET=$( echo $MAIL|jq '.payload |.headers[]|select(.name == "Subject")|.value'|sed -e 's/"//g'|cut -f1 -d ' ') 
  STATUS=$( echo $MAIL|jq '.payload |.headers[]|select(.name == "Subject")|.value'|sed -e 's/"//g'|cut -f7 -d ' ') 
  if [ $STATUS == "Successful!" ] ; then 
   say "マスターデプロイが成功しました"
   curl -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE https://www.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID;; 
  elif
   say "マスターデプロイに失敗しました" 
   curl -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE https://www.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID;;  
  fi 
 fi
fi
sleep 20
done

順を追ってみていきましょう。やっていることは単純です。

Google Developpers Consoleから取得したアクセストークンを保持しておきます。

まず最新の未読のメールIDを取得します。

RESULT=curl -H "Authorization: Bearer $ACCESS_TOKEN" https://www.googleapis.com/gmail/v1/users/me/messages?q="is:unread";

メールのIDを取得したのち、それをパラメーターにメールの内容取得APIを叩きます。

MESSAGE_ID=`echo $RESULT |jq '.messages[0]|.id' |sed -e 's/"//g'`
MAIL=`curl -H "Authorization: Bearer $ACCESS_TOKEN" https://www.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID`

Jenkinsからのメールかどうかをチェックします。Jenkinsのジョブ通知専用のプロジェクトを作成するのがベターだと思います。今回は念の為チェックしておきます。

FROM=$( echo $MAIL |jq '.payload |.headers[]|select(.name == "From")|.value'|sed -e 's/"//g')
if [ $FROM == "griphone-sample@gmail.com" ] ; then 

タイトルや本文(今回はタイトル)にジョブ名やビルド情報が含まれているのでそれを取得します。

TARGET=$( echo $MAIL|jq '.payload |.headers[]|select(.name == "Subject")|.value'|sed -e 's/"//g'|cut -f1 -d ' ')
STATUS=$( echo $MAIL|jq '.payload |.headers[]|select(.name == "Subject")|.value'|sed -e 's/"//g'|cut -f7 -d ' ')

ここまでくればあとはやりたい放題です。ジョブやビルド状況ごとに応じて通知内容を変更します。

if [ $STATUS == "Successful!" ] ; 
 then say "マスターデプロイが成功しました"

最後に対象のメールを削除します。削除しないと未読メールがたまり続け、欲しいメールが取得しにくくなってしまいます。

curl -H "Authorization: Bearer $ACCESS_TOKEN" -X DELETE https://www.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID;;

これはGmail APIに既読処理APIがないため泣く泣くこうした処理を入れています。

※調べてみると力技ですが、未読ラベルを削除して更新したら既読にできるようです。

あとはローカルのPCからcronなりで実行するだけです。

APIの制限に引っかからないようにsleepも忘れずに添えておきます。

sleep 20

まとめ

今回紹介した事例は実際にサービス開発の現場で使用しているものです。

使ってみた所感としては、Gmailを使っていれば社内のコミュニケーションツールの変動に惑わされない仕組みで構築できるのが良いと思います。(ChatworkとかSlackとかはたまたYammerとか色々ツールが変わることありますよね笑)

Gmail APIの使い方がわからない、使ってみたいが何に使えるかわからないと言う方の参考になれば幸いです。

それでは!