読者です 読者をやめる 読者になる 読者になる

量産型エンジニアの憂鬱

きっと僕は何物にもなれない。

GmailをSlackに通知するPerlスクリプトを書いた

Slack perl

チームSlackを導入してしばらくたったのですが、 まだ一部のやり取りはメールで行っています。

この通知をまとめたい場合、SlackにはEmail連携が用意されています
Slack便利。
が、これは有料版でしか使えません。
メールクライアントソフト使えばいいかもしれないんですが、自分は今までメールを開きっぱなしだったモニタの一部分をSlackに置き換えたので、
Slackを開いているとついついメールが来ていることに気づくのが遅くなってしまいます。

メールはGmailなんやし、Gmail APIで取得してSlackのBotに通知させりゃええやん。

f:id:duck8823:20160828134749p:plain
f:id:duck8823:20160828135323p:plain
こんな感じで通知あるとわかりすいですよね。 ってことで、スクリプトを書きました。

作成したスクリプト

use strict;
use warnings FATAL => 'all';

use Google::API::Client;
use Google::API::OAuth2::Client;

use utf8;
use Encode;

use Slack::RTM::Bot;

my $user_id = 'Gmailアカウント(メールアドレス)';
my $client_id = 'Google APIs プロジェクトのクライアントID';
my $client_secret = 'Google APIs プロジェクトのクライアントシークレット';
my $label_regex = qr/Gmailのラベルの正規表現/;

my $slack_api_token = 'Slack Bot のトークン';
my $channel = '通知するSlackのチャンネル';

my $interval = 60;

my $bot = Slack::RTM::Bot->new(
    token => $slack_api_token
);
$bot->start_RTM;

my $auth = Google::API::OAuth2::Client->new({
        auth_uri => "https://accounts.google.com/o/oauth2/auth",
        token_uri => "https://accounts.google.com/o/oauth2/token",
        client_id => $client_id,
        client_secret => $client_secret,
        redirect_uri => "urn:ietf:wg:oauth:2.0:oob",
        auth_doc => {
            oauth2 => {
                scopes => {
                    "https://www.googleapis.com/auth/gmail.readonly"
                    => "gmail read"
                }
            }
        }
    });
print Encode::encode_utf8("以下のURLにアクセスし、表示されるコードを入力してエンターを押してください.\n");
print $auth->authorize_uri . "\ncode: ";
my $code = <stdin>;
$auth->exchange($code);

my $service = Google::API::Client->new()->build('gmail', 'v1');
my $labelIds = [];
my $res = $service->users->labels->list(body => {userId => $user_id})->execute({auth_driver => $auth});
for my $label (@{$res->{labels}}) {
    push @$labelIds, $label->{id} if $label->{name} =~ $label_regex;
}
$auth->refresh;

while(1) {
    my @new_messages;
    for my $labelId (@$labelIds) {
        my $body = {
            userId => $user_id,
            labelIds => $labelId,
            q => 'is:unread'
        };
        $res = $service->users->messages->list( body => $body )->execute( { auth_driver => $auth } );
        for my $message (@{$res->{"messages"}}) {
            $res = $service->users->messages->get( body => { userId => $user_id, id => $message->{id} } )->execute( {auth_driver => $auth } );
            if($res->{internalDate} / 1000 < time() - $interval) {
                last;
            }
            my %headers = ();
            for my $header (@{$res->{payload}->{headers}}) {
                $headers{$header->{name}} = $header->{value};
            }
            my $mes = <<"EOL";
From: $headers{From}
To: $headers{'Delivered-To'}
Date: $headers{Date}
Subject: $headers{Subject}
Snipet: $res->{snippet}
EOL
            push @new_messages, $mes;
        }
        $auth->refresh;
    }
    if (@new_messages > 0) {
        $bot->say(
            channel => $channel,
            text => Encode::encode_utf8(sprintf("%s 件の新規メッセージがあります.\n%s", scalar @new_messages, join("\n\n", @new_messages))))
    }
    sleep $interval;
}

Google APIs プロジェクトの作成

Gmail APIを利用するにはGoogle APIsでプロジェクトを作成する必要があります。
Gmailアカウントにログインしたら、Google APIs ライブラリにアクセスします。

f:id:duck8823:20160828113123p:plain
上部メニューのプロジェクト(すでにプロジェクトがある場合はその名前になっていると思います)をクリックし、プロジェクトを作成をクリックします。

下記のようなウィンドウが表示されるので、利用規約を読んで同意し、作成 をクリックします。
f:id:duck8823:20160828113535p:plain

しばらくしたら、ヘッダが作成したプロジェクトになっています。
f:id:duck8823:20160828113806p:plain

Gmail API の有効化

左メニュー > ダッシュボード
から、 [API を有効にする] をクリックします。
f:id:duck8823:20160828114209p:plain

すると検索フォームが現れるので、 Gmail と入力します。
リストにGmail APIが表示されるので、それをクリックします。 f:id:duck8823:20160828114316p:plain

ページ上部に 有効にする と表示されているので、クリックすることで有効化できます。
f:id:duck8823:20160828114512p:plain

認証情報を作成する

f:id:duck8823:20160828115455p:plain

Gmail APIは認証が必要ですので、このままでは使用できません。
以下のように表示されるので、認証情報を作成します。

左メニュー > 認証情報 > OAuth同意画面
をクリックし、
ユーザーに表示するサービス名を入力し 保存 をクリックします。
サービス名以外は任意です。
f:id:duck8823:20160828121459p:plain

続いて
左メニュー > 認証情報 > 認証情報
から、 認証情報を作成 をクリックし、 OAuth クライアントID をクリックします。
f:id:duck8823:20160828121750p:plain

クライアントIDの作成画面が表示されるのですが、
今回はスクリプトなので、 その他 にしました。
f:id:duck8823:20160828123219p:plain

作成をクリックすると、クライアントIDとクライアントシークレットが表示されるので、最初に紹介したスクリプトをこれで置き換えてください。
f:id:duck8823:20160828122053p:plain

使ったモジュール

Gmail APIGoogle::API::Clientを拝借しました。
こちらの記事を参考にさせていただきました。
Slackへの通知はSlack::RTM::Botを使っています。

使い方

上記スクリプトを実行すると、コンソールに認証URLが表示されます。

> perl script.pl
以下のURLにアクセスし、表示されるコードを入力してエンターを押してください.
https://accounts.google.com/o/oauth2/auth?client_id=Google APIs プロジェクトのクライアントID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/gmail.r
eadonly
code:

表示されるURLにアクセスすると、アプリケーション権限の許可画面になります。
この場合は表示のみのアクセス権です。
f:id:duck8823:20160828201809p:plain

許可をクリックするとコードが表示されるので、コンソールにコピペしてエンターキーを押します(上記スクリプトではコンソールには表示されないようしています)。
f:id:duck8823:20160828203054p:plain

この後は、Ctr + zを押した後に bgコマンドをうつとバックグラウンドに移せます。

Slack::RTM:BotGoogle::API::OAuth2::Clientを組み合わせれば、 SlackのBotにつぶやいて任意のタグの未読メールを取得するなんてことも簡単ですね!

参考

Google Gmail APIでメールを取得する - Qiita
Google::API::Clientを使う(perl) | @knok blog