GmailとBacklogをAPIで連携してみた

こんにちは。Backlog テクニカルサポートの立石です。

テクニカルサポートというとあまり聞きなれないかもしれませんが、主にカスタマーサポートと一緒にお客様のサポートを行なったり、サポートの運用がスムーズにできるようサポートで使う管理システムの改善を行なったり、お客様に少しでもお役に立てるよう API を使ったツールを作ったりしています。

私のエンドユーザーはお客様やカスタマーサポートになるのですが、ツールを作る時には、その方の負担を少しでも減らすことで、少しでも幸せになれないかと思いながら作っています。

今回のブログもその助力の一端になればと思いますので、ぜひお付き合いください。

お客様の業務をBacklog APIで効率化

お客様をサポートする中で、「サイトの問い合わせや顧客から直接来たメールを Backlog に手で起票しているが、それを自動起票できないか」というお声をいただくことがあります。

その時には メールによる課題登録Backlog API をご案内することがあります。しかし、API だとプログラムを書かなければいけなかったり、そのプログラムを動かすために AWS LambdaHubot など実行環境を用意したり、そもそも API とはなんぞやなどと、なかなかハードルが高くなることがあります。

そこで、今回は少しでも API のことをわかっていただき、そのハードルを少しでも低くできないかと思って書かせていただきます。

Backlog API とは?

お客様とBacklogをプログラミングでつなぐもの

API はアプリケーション・プログラミング・インタフェースの略になります。 なんだかこれだけ言われてもわかりにくいですよね。

インターフェースとは「何か」と「何か」をつなぐという意味ですが、ここでは「アプリケーション」と「プログラミング」をつなぐものという意味になります。そのつなぐものとなるのが API と呼ばれるものになります。 アプリケーションにつなぐための口と思っていただけるとイメージしやすいかと思います。

つまり Backlog では、 Backlog というアプリケーションをプログラムから API を通して操作しようぜ〜ということができます。これが Backlog API です。

ここまででどうでしょうか? なんだ API ってそんなものなんだ、と感じてくれるといいなと思います。

ではちょっと難しくなってきますが、次に具体的な API の中身について説明したいと思います。

繰り返しの同じ作業や決まった定型作業を自動化する

Backlog の API では普段ブラウザから操作している事柄の大部分ができるようになっており、その操作毎に URL が用意されています。その URL を呼び出すことで Backlog を操作することができるようになっています。

つまりその URL を使って呼び出すことさえできれば普段の操作をプログラムから機械的に呼び出すことができます。例えば繰り返し同じ作業を実行したり、決まった定型作業を人の手を使わず行うことも可能になります。

なんだかこれだけ聞くだけだと便利そうじゃないですか? 何かに使えるかな?とか、ふと思ったりしました?

では、次は実際に API を使った例を挙げてみようと思います。

Backlog APIを使ってみる

せっかくなので先ほど紹介した「メールで届いた内容を Backlog の課題に登録する方法」を例に実践していきたいと思います。

Gmailの内容をGASとBacklog APIで課題登録する

今回は Gmail に届いたメールを Google Apps Script ( 以下 GAS ) と Backlog API を使って、Backlog に課題を登録する方法について紹介します。

GAS はビジネスアプリケーションを作成したり動かしたりできるアプリケーション開発のプラットフォームのことです。Google が提供しているプラットホームなので Gmail や Googleスプレッドシートなど関連する他のサービスと連携できます。もちろんそれ以外のアプリケーションをつなぐ用途にも使うことができます。またプログラムを作成し、その場で簡単に動作させることができるので、慣れていない方にも気軽にお試しできるのも特徴です。

今回は以下のような構成で進めてみようと思います。

なんか思ったより用意するものが少なくないですか? これだけでメールに届いた内容を課題にすることができるのです。

では重要なところを切り分けて順に説明していきます。

課題を登録してみよう

まず最初に GAS を使って Backlog へ課題を登録することをやってみましょう。 実は課題の登録だけであればとても簡単なのです。

GAS にはインターネットを介して他のホストと通信するため UrlFetchApp というユーティリティが用意されています。今回は、そのユーティリティを使って 課題追加の API の URL を呼び出し、課題を登録したいと思います。

実行する時は登録する内容を連想配列にしたパラメーターを URL と一緒にポストします。言ってしまえばそれだけで課題を登録することができるのです。

以下が GAS に書いた内容です。

function myFunction() {
  let parameters = {
    'projectId' : '34521',
    'issueTypeId' : '7231',
    'priorityId' : '3',
    'summary' : '今日のランチ',
    'description' : 'カレーとサラダとスープ、たまに福神漬け'
  }

  let options = {
    'method' : 'post',
    'contentType' : 'application/x-www-form-urlencoded',
    'payload' : parameters,
    'muteHttpExceptions' : true
  }
  UrlFetchApp.fetch("https://<スペースID>.backlog.com/api/v2/issues?apiKey=<あなたのAPIキー>", options);
}

上ではプロジェクト、種別、優先度、件名、文章の必要最低限な情報だけをポストした時の例になりますが、他にも課題に登録できる項目もありますので 課題追加の API のページ のパラメーターを参考に追加ください。

  • projectId に数字が入っていますが、これは Backlog のプロジェクトが持っている一意の ID になります。プロジェクト情報を取得する API を使って取得することもできますが、ブラウザの画面からも確認することができます。ブラウザで対象プロジェクトのプロジェクト設定画面に移動するとブラウザのアドレスバーに URL が表示されます。そちらに「project.id=34521」と出力されていますのでその値に置き換えていただくだけになります。
  • issueTypeId は種別の ID になります。こちらも projectId と同様にプロジェクト設定から種別一覧画面に移動し、対象の種別を選択すると同じく URL に「issueType.id=7231」と出力されるのでその値に置き換えるだけとなります。
  • priorityId は 2 が「高」で、3 が「中」、4 が「低」と固定になりますので、この中から選んでいただければと思います。
  • <スペースID> にはご利用のスペースのスペースIDに置き換えてください。詳しくは スペースIDとは とはのヘルプを参考にしてください。
  • <あなたのAPIキー> はご利用のアカウントの API に置き換えてください。詳しくは APIキーのヘルプ を参考にしてください。

登録だけだと、そんなに難しくはないと思いませんか? あとはこれをベースにメールの件名や本文に差し替えていくだけになります。

Gmail からメールのデータを受け取ろう

受信したメールのデータをプログラム側で受け取るには2通りの方法があります。

  • メールを受信したタイミングでメーラーがデータをプログラムに送る方法
  • プログラムで定期的にメールのデータを取得する方法

 

それぞれメリットやデメリットがあるのですが、今回の構想では Gmail側がデータの流入口となっているため、一度に何百通と大量に来た場合、受け手側の GAS や Backlog で捌けないこともあるかもしれないので、今回は後者のプログラムで定期的にメールのデータを取得するようにし、一定間隔でデータの流入量をコントロールできるようにしたいと思います。

では具体的にどのようにして定期的にメールのデータを取得するか?ですが、GAS で Gmail の受信ボックスを定期的に監視するようにし、必要なメールのデータのみを取得するようにしたいと思います。

Gmail の受信ボックスからメールのデータを取得しよう

早速どうやってメールのデータを取得するかですが、ここは GAS が用意してくれている Google の API を使えば簡単に取得できます。ここでも API が出てきましたね。Gmail も謂わば1つのアプリケーションですので API が用意されていてもおかしくありません。ここでの API は Google の提供するサービス(アプリケーション)と GAS をつなぐための専用の API と考えていただければと思います。

例えば Gmail の場合、Gmail専用の API がありますが、そちらを使って簡単にメールのデータを取得することができます。また条件をクエリーとして指定することで、取得したいデータを絞って取得することも可能です。例えば受信ボックスなら in:inbox とクエリーを指定することで受信ボックスにあるデータを取得できますし、is:unread を条件にすると未読のメールを取得することができます。クエリーの指定方法 は Gmail 内のメールを検索する時にも使えるので知っておくと便利です。

今回は特定のラベル(例: 「new inquiry mail」)がついたメールを取得するようにしたいと思います。Gmail のラベルは Gmail のフィルタ機能を使えば特定のルールに従ってメールに付けることができます。メールを分類したい時などに使用すると便利です。

ラベルは Gmail の設定から追加できます。またラベルを付けるためのフィルタも設定から行うことができますので、課題に登録したいパターンのメールをラベリングするようにしてもらえばと思います。

以下は特定のクエリーで取得した時のコードになります。

let query = "label:new-inquiry-mail";
let threads = GmailApp.search(query);

この2行だけで「new inquiry mail」というラベルが付いたメールのデータを取得することができます。

  • クエリーでラベルを指定する時はラベルの半角スペースはハイフンに置き換える必要があります。

取得したメールのデータはスレッドという単位で複数のデータ群で取得されます。スレッドという聞き慣れない名前になっているかと思いますが、Gmail の API で取得したメールのデータは、メール1件1件を独立したデータとして取得するのではなく、メールをスレッドという単位でまとめたものを1つのデータとして取得します。

例えばですが、メールに対して返信を行うとそのメールの返信のメールが下に連なりますが、その連なりのことをスレッドと言います。またその返信に対して更に返信した場合もそのスレッドに取り込まれます。 ただし、返信などがなく最初に送ったメール1件だけだとしても1スレッドとして数えます。

あとはこの取得したメールのデータを解析し、先に説明した課題登録のプログラムと合体させると当初の目的を達成することができます。

それでは次はこのスレッドのデータ群を解析してみましょう。

Gmail のメールのデータを解析してみよう

早速、メールのデータを解析してみます。

先ほどのスレッドと呼ばれるデータ群を解析していきます。データは複数件ありますので、for を使って繰り返しながらデータを取り出していきます。

let query = "label:new-inquiry-mail";
let threads = GmailApp.search(query);

for (let th in threads) {
  let thread = threads[th];
  let messages = thread.getMessages();

  for (let msg in messages) {
    let mail = messages[msg];

    let subject = mail.getSubject();
    let body = mail.getPlainBody();
    :
    :
  }
}

スレッドの中には messages という形でメール1件1件がデータとして格納されています。それを更に for で分解することでメールの内容を取得していきます。

メールにはさまざまな情報がありますが、ここではメールの件名と本文を使用することにします。件名は getSubject() で、本文は getPlainBody() で取得します。PlainBodyで取得している理由としてはメールは HTML形式で来る場合もあり、それをそのまま Backlog に登録すると HTML のタグまで Backlog に登録されるので純粋にテキストだけを抽出するようにしています。

あとはこの取得したデータを課題のパラメーターに入れて登録するだけなのですが、課題として登録したいのは最初に来たメールだけですので、以下のような条件文を入れて、最初のメールが来た時だけを処理するようにしたい思います。

if (thread.getMessageCount() === 1) { … }

getMessageCount() は thread の中にある message の件数を取得しますが、それが 1件の時のみ、つまり最初に来たメールだけのスレッドの時のみ処理を行うことにします。

また課題に登録しても「new inquiry mail」のラベルが付いたままだと、次の間隔で取得した時にも、また同じスレッドを取得してしまうので、登録したものや既に確認が終わったものについては以下のコードで「new inquiry maill」のラベルを外すようにします。

let label = GmailApp.getUserLabelByName("new inquiry mail");
thread.removeLabel(label);

これらをまとめると以下のようになります。

function myFunction() {
  let query = "label:new-inquiry-mail";
  let threads = GmailApp.search(query);

  for (let th in threads) {
    let thread = threads[th];
    let messages = thread.getMessages();

    if (thread.getMessageCount() === 1) {
      for (let msg in messages) {
        let mail = messages[msg];

        let subject = mail.getSubject();
        let body = mail.getPlainBody();
         :
         :

        removeLabel(thread);
      }
    } else {
      removeLabel(thread);
    }
  }
}

function removeLabel(thread) {
  let label = GmailApp.getUserLabelByName("new inquiry mail");
  thread.removeLabel(label);
}
  • 「new inquiry maill」のラベルを外す処理は何度も使うので removeLabel というメソッドにします。

これで Gmail のデータを取得する部分は終わりです。

課題の登録処理と Gmail のデータ取得処理を1つにしよう

課題の登録部分と Gmail のメールのデータの取得部分ができましたね。 あとは2つを1つにまとめるだけになります。

まとめたものが以下になります。

function myFunction() {
  let query = "label:new-inquiry-mail";
  let threads = GmailApp.search(query);

  for (let th in threads) {
    let thread = threads[th];
    let mails = thread.getMessages();

    if (thread.getMessageCount() === 1) {
      for (let ml in mails) {
        let mail = mails[ml];

        let subject = mail.getSubject();
        let body = mail.getPlainBody();

        let parameters = {
          'projectId' : '34521',
          'issueTypeId' : '7231',
          'priorityId' : '3',
          'summary' : subject,
          'description' : body
        }

        let options = {
          'method' : 'post',
          'contentType' : 'application/x-www-form-urlencoded',
          'payload' : parameters,
          'muteHttpExceptions' : true
        }

        let res = UrlFetchApp.fetch("https://<スペースID>.backlog.com/api/v2/issues?apiKey=<あなたのAPIキー>", options);
        Logger.log(res.getResponseCode());
        if (res.getResponseCode() < 200 || res.getResponseCode() > 299) {
          Logger.log(res.getContentText());
          break;
        }
        removeLabel(thread);
      }
    } else {
      removeLabel(thread);
    }
  }
}

function removeLabel(thread) {
  let label = GmailApp.getUserLabelByName("new inquiry mail");
  thread.removeLabel(label);
}

これでプログラミングは終了になります。残すは実行だけになります。

動かしてみよう

GAS の実行ですが、実行は自身でボタンを押して手動で行うこともできますが、スケジューリングして決まった時間や決まった感覚でプログラムを動作させることもできます。今回はその中のスケジューリングの機能を使ってメールの受信ボックスを監視したいと思います。

スケジュールの間隔は自身で決めることができますが、今回は受信したメールを課題登録するのが目的なのでメールを受け取ってからの時間が大きくずれないように 5分間隔で実行したいと思います。

GAS のページの左側のメニューに時計のアイコンがありますので、そちらからスケジュールを登録します。 時計のアイコンを押すとトリガーという画面が開きますので、右下にある「+トリガーを追加」からスケジュールの設定画面を開きます。 「時間ベースのトリガーのタイムを選択」で「分ベースのタイマー」を選び、その下の「時間の間隔を選択(分)」で「5分おき」を選択し、あとは保存してください。

これでスケジュールの設定は終わりです。 あとは 5分間隔で指定のラベルが付いたメールが順に課題に登録されていきます。

さいごに

どうだったでしょうか?

プログラムと言っても 50行もないんですよね。これでメールを課題に登録することができるんです。意外とこんなもので作ることができるのかという気がしませんか?

またメールからだと他にもやれることがあります。例えばですが、メールに添付されたファイルも課題に登録するということもできます。カテゴリーやマイルストーンなどもつければ更に業務に添ったツールにすることができると思います。

アイデア次第で大きく変えられるのも API の強みになります。 もしよかったらチャレンジしてみてくださいね。

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる