受信したメールをslackのgeneralに自動転送したい．無料で


# 背景

本研究室では昔から使用しているグループメール（googlegroups）がありました．そして数年後，slackが導入されたのです．

slackは便利ですね，なんでもslackで連絡したくなります．generalチャンネルを使えば全体への通知も簡単ですし．

ところが我が研究室のボスは，諸事情から重要な連絡はグループメールを使っているのです．slackのgeneralに投げてほしいなあと思いますが，まあ色々な考えがあるのでしょう．

とはいってもグループメールはslackのgeneralでも確認したいのです．つまりメールをslackのgeneralに自動転送する仕組みが欲しいのです．しかしネットで調べても，基本的にはslackのEmaliのアプリ（slackの料金プランが有料以上）を使用するだったり，自分のslackbotに送るだったり，何とも微妙なのです．

ということで，Gmail (Google Apps Script)とSlack (Slack Bot)を組み合わせて，届いたメールをslackのgeneralに（無料で）転送する仕組みを作った話をします．

# アイデアと手続き

インターネットを調べた感じ，Slackのボットをまず作って，そのボットを他のスクリプトから操作する，みたいな感じでいけそうでした．

Slackボットを操作するスクリプトとしてはGoogle Apps Scriptが妥当そうです．なぜならば，Google Apps ScriptにはSlackを操作するライブラリがあり，かつGmailとの連携により，メールボックスを確認することも可能だからです．

そのため手続きとしては以下になります．

1. Slackのボットを作る
1. Google Apps Scriptを作成，ScriptからSlackボットを通じてメッセージを送る
1. 上Scriptを定期的に実行させる

# Slackのボットを作る

以下のページを参考にしました．このままやればできます．

https://auto-worker.com/blog/?p=2904

基本的には，アプリ（ボット）を作る，ワークスペースにアプリをインストールする，アプリがメッセージを送信できるように設定する，アプリをGoogle Apps Scriptから操作するためのトークンを取得する，といった感じです．

Google Apps Scriptの作り方，Slackライブラリの追加も上リンクに書いてあるので，そちらを参照で．

# Google Apps Scriptを作成，ScriptからSlackボットを通じてメッセージを送る

最終的には以下のscriptを作成しました．`checkMailBox()`がエントリポイントです．

```javascript
function postSlackbot( message ) {
  let token = "YOUR TOKEN";
  let slackApp = SlackApp.create( token );

  const channelId = "#general";
  slackApp.postMessage( channelId, message );
}

function formatDate( date ) {
  const formated = Utilities.formatDate( date, "Asia/Tokyo", "yyyy-MM-dd HH:mm:ss" );
  return formated;
}

function checkMailBox() { // Step 1
  const start = 0;
  const max = 5;
  const query = "from:(xxx@gmail.com)"; // Step 2
 
  const threads = GmailApp.search( query, start, max );
  const messagesForThreads = GmailApp.getMessagesForThreads( threads );
 
  for( const messages of messagesForThreads ){
    const message = messages[0];

    const subject = message.getSubject();
    const body = message.getPlainBody();
    const numAttatchments = message.getAttachments().length;
    const numAttatchmentsAsStr = Utilities.formatString( "*%d オリジナルのメールを確認してください*", numAttatchments );
    const attatchmentStr = numAttatchments > 0 ? numAttatchmentsAsStr : "0";
    const date = formatDate( message.getDate() );

    if( !message.isUnread() ) { // Step 3
      console.log( Utilities.formatString( "%s is already read", subject ) );
      continue;
    }

    const txts = [ // Step 4
      "xxxにメールが届きました．generalに転送します",
      Utilities.formatString( "送信日: %s 添付ファイルの数: %s", date, attatchmentStr ),
      Utilities.formatString( "*%s*", subject ),
      body
    ];

    const txt = txts.join( "\n\n" );
    console.log( txt.substr(0, 200) );
    message.markRead(); // Step 5

    postSlackbot( txt ); // Step 6
  }

}
```

流れとしては以下のような感じです．
Step 1: スクリプトが走るGoogleアカウントのメールボックスを確認
Step 2: 変数`query`に従って，取り出すメールを検索
Step 3: 取り出されたメールが既読だったら処理をしない（未読のメールをSlackに投げたいので）．
Step 4: メールのデータを適当に整形する
Step 5: メールを既読にする
Step 6: slackに投げる

簡単ですね．

ちなみにこのスクリプトはメールを新着5件までしか検索しません．またメールのスレッドの先頭に対してしか仕事をしません．必要に応じて適当に作り替えてください．

作成したスクリプトはトリガーを使用して，定周期に実行しておきます．サーバにあまり負荷をかけると申し訳ないですし，さほど即時性を求められるものではないので，一時間に一回などでよいのではないでしょうか．

# 実行結果
ちょっと黒塗りしすぎてわかりにくいですが，自分で作ったslackのアプリ（`GroupMail2General`）が`***-all`から送られたメールを転送してくれてる感じがわかると思います．

![mail2slack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319806/d933f0eb-d48a-9f36-ca99-0006d7a92208.png)


# 終わりに
とりあえずできて良かったです．

より良い方法を知っている人がいたら教えてください．