Nishiki-Hub

国内外のPC/PCパーツ/スマホ/Appleなどの最新情報を取り上げています

【GAS】Gmailを受信したらWebhook経由でDiscordに通知するようにした

本日の内容

GAS(Google App Script)は使用用途によっては便利らしいという話で、今回はGmailを受信したらWebhook経由でDiscordに通知するようにしたという記事です。

仕様

雑に仕様を書くと、5分ごとにGASを動かして受信メールを確認します。このとき、検索機能を使って「checked」というラベルがついていないものをすべてWebhookを使ってDiscordに飛ばします。

そして、飛ばしたメールには「checked」ラベルを付与します。

簡単に言えば、新たに受信したメールをDiscordに送信するというもので、送信したかしてないかの確認は「checked」というラベルを用いるという話。

コード

function sendWebhook(message){

  const url = "https://discord.com/api/webhooks/xxxxxxxxxxxTOKENxxxxxx"
  const webhookMsg = {
    "username": "Gmail自動投稿",
    "tts": false,
    "embeds": [
      {
        "title": message.getSubject(),
        "description": message.getPlainBody(),
        "color": 0x3ea8ff,
      }
    ]
  }

  const param = {
    "method": "POST",
    "headers": { 'Content-type': "application/json" },
    "payload": JSON.stringify(webhookMsg)
  }

  UrlFetchApp.fetch(url, param);

}

function getGmail() {
  // 「checked」というラベルを取得(なければ作成)
  var checkedLabel = GmailApp.getUserLabelByName("checked");
  if (!checkedLabel) {
    checkedLabel = GmailApp.createLabel("checked");
  }

  // ラベルがついていないメールスレッドを取得
  var threads = GmailApp.search("-label:checked");

  // スレッドを処理
  for (var i = 0; i < threads.length; i++) {
    var thread = threads[i];

    // スレッドを出力(スレッド内の最初のメールの件名と内容を取得)
    var message = thread.getMessages()[0];
    sendWebhook(message);

    // 「checked」ラベルを付ける
    thread.addLabel(checkedLabel);
  }
}

多少ChatGPTのちからを借りつつ書きましたが、リファレンス読みながら頑張りました。とりあえず、処理の仕組みをざっと解説していきます。

実行するのはgetGmail関数です。

まず、GmailApp.getUserLabelByName("checked")でラベルがあるか確認しています。なければGmailApp.createLabelで作成しています。これは誤って誰かがラベルごと消したとき用の処理ですが、まあ、消したら全部のメールをDiscordに送りつけてくるので、これやるなら「いつ以降のメールだけ送る」という処理を追加すべきですね。

そして、GmailApp.searchを用いてcheckedラベルがついていないメールを検索し、ヒットしたメール(スレッド)をthreads配列に突っ込んでいます。

forループでは、配列の中身をWebhookで送る用のsendWebhook関数に投げています。具体的には、スレッドはメールの返信を含めた一連の流れが格納されている構造体なので、スレッドの最初のメール(message)だけを取り出して、sendWebhook関数に投げています。

そして、sendWebhookが完了すれば、addLabelでそのスレッドにcheckedのラベルを付与しています。

では、sendWebhookの中身ですが、こちらは至って単純です。DiscordでWebhookのトークン(URL)を発行して、そこにめがけてJSONを送りつけるだけです。スレッドも構造体ですが、メッセージも構造体なので、メッセージからgetSubjectでタイトルとgetPlainBodyで本文を抜き取って、それぞれDiscordのEmbedのTitleとDescriptionに格納しています。

ちなみにgetPlainBodyではHTMLコンテツを取得しません。

他にメッセージから取り出せる内容は以下のとおりです。

関数 機能
getCc() CCをカンマ区切りで取得する
getDate() メッセージの日時を取得する
getFrom() 送信者を取得する
getHeader(name) nameで指定したヘッダー名の値を取得する
getRawContent() メッセージの生(未加工)の情報を取得する
getAttachments() メッセージのすべての添付ファイルを取得する

ちょっとした問題点

基本的にこのメアドにメールがそんなに届くことがないのに、時折届くメールはそこそこ重要であり、サークルの人たちにも共有しないといけないのでこのスクリプトを作ったという経緯があります。メールが届いていることを把握させればいいので問題は無いのですが、このスクリプト、返信などは無視するはずです。

もし、返信も受け付けたいとか、ラベルで管理は避けたいのであれば、例えば、タイムスタンプで前回の実行からの差分だけを出力するようにしたり、スレッドの更新も受け付けれるようにしてみてください。気が向いたら改良します。