📮

Gmailのメール本文をCosense(旧scrapbox)にインポートするアプリをSveltekitで作ってみました

に公開

前置き

皆さん、普段のナレッジはどうしていますか? そもそもどこまでナレッジとしてアウトプットしていますか?

恐らく大半の人は、インターネットで見つけた有益な情報や記事をどこかに保存したり、ストックしたり、あるいは自分のメモ書きをナレッジとして蓄積していたりすると思います。

私は普段、頭に思い浮かんだすべてのアイディアや気になったこと、世間で話題になっていることに対する自分の考えなどを、Cosense にその都度必ず書き残すようにしています。私にとっては日々の感情もナレッジの一部になります。なので、うっすら記憶にある昔の出来事を思い出したときは、とりあえずCosenseを見に行くような習慣になっています。

前回は SlackのスレッドからCosense(旧Scrapbox)ページを作ってくれるBotを作った話 という記事を投稿し、SlackからCosenseにナレッジを移すアプリを作った話をしたのですが、最近Gmailに保存されている情報がCosenseにないことに気づき、前回の続き第2弾として、Gmailのメール本文をCosense(旧Scrapbox)にインポートするアプリを作ってみました。

完成物

先に完成物をお見せします。
UIはそのうちもう少しきれいにしたいと思っています🙇

Image from Gyazo

Image from Gyazo

必要な情報を登録します。

Image from Gyazo

Gmail側でラベルを作成し、メールにラベルを付けます。

Image from Gyazo

動画です。

Image from Gyazo

同期できたらDiscordにも通知が来ます。

Image from Gyazo

レポジトリはこちら

https://github.com/qaynam/cosense-gmail-integraion

目指したゴール

ゴールとしては以下を目指しています。

  • なるべくコードを触らず、セットアップもできるだけ簡潔で、すぐに動かせるようなアプリにしたい
  • 複数のGmailアカウントから同じCosenseプロジェクトにインポートできるようにしたい
  • 自動でページ作成をしてくれるようにしたい
  • 取り込んだページリストをDiscordに通知したい

実現方法を考えてみる

流れとしては、Gmail APIからデータを取得してCosenseに書き込むだけなので、やり方はいろいろあると思います。

GASを使う

Google Apps Scriptを使ってGmail APIとCosense APIを叩く方法です。GASはGoogleのサービスなので、Gmail APIを叩く際にOAuth認証が不要で、スクリプトエディタから直接Gmail APIを叩けます。手軽に始められ、一番自然だと思います。

しかし、GAS上で動かすとなるとライブラリが自由に使えなかったり、実行時間制限があったり、それぞれのユーザー設定をコード内に書く必要があったりと拡張性に欠けるため、今回は見送りました。

Pub/Subを使ってトリガーする

GmailはGoogleのサービスなので、GCPのインフラを使えばとても自然に組み合わせられます。しかし、Pub/Subを使うとなるとGCP側の設定がいろいろ必要で、私が目指している「なるべくコードを触らずにセットアップも簡潔にしてすぐ動かせるアプリ」というゴールからは外れてしまうので、これも見送りました。

自前でアプリを作る

いろいろ考えた結果、自前でアプリを作り、cronで定期実行してメールをインポートする方法をとりました。

アプリの構成

  • フレームワーク: SvelteKit + TypeScript
  • UIフレームワーク: Tailwind CSS
  • デプロイ: Vercel
  • データベース: Upstash
  • 認証: Google OAuth2 (Arctic)
  • Gmail API: Google APIs Node.js Client
  • 通知: Discord Webhook

フレームワークについては、私はSvelteKitのデータフローがとても好きで、個人のプロジェクトではよく使っているので、今回もSvelteKitを選びました。

機能

  • Googleアカウントでログイン
  • Cosenseプロジェクト名とCosenseのセッションIDを設定
  • DiscordのWebhook URLを設定
  • 一日に一回定期実行
  • Gmailの「cosense」ラベルが付いたメールをインポート

Gmail APIを使うのでOAuth認証が必要になります。そのため、最初の一回だけGoogleアカウントでログインしてアクセストークンを取得し、cronでの定期実行時にそのトークンを使ってメール本文を取得し、Cosenseにインポートするようにしています。

そのため、データを保存するデータベースが必要です。いろいろ検討した結果、手軽に始められるようにVercelのサーバーレス関数と組み合わせて使えるUpstashを採用しました。

本当はステートフルなPostgreSQLの方が確実ですが、個人利用にはオーバースペックに感じたため、Redisを選びました。UpstashはサーバーレスRedisなのでデータが消える心配はなく、公式にもDBとして使えると明言されているため安心して利用できます。

https://upstash.com/docs/redis/features/durability

Image from Gyazo

アプリを使うためのセットアップ

Vercelにデプロイすることを前提に作っているので、ここではVercelを前提に解説します。Cloud Runなど別のインフラで動かしたい場合は自由にforkして使ってください。

必要なもの

  • Googleアカウント
  • Cosenseアカウント
  • Vercelアカウント
  • Upstashアカウント(Redis)
  • GCPのプロジェクト・OAuthクライアントID・シークレット

上の3つのアカウント系については、この記事を読んでいる方は大体持っていると思うので割愛します。

Upstashに登録してRedisを作成

クレジットカードの登録不要でアカウントが作れるので、そのまま登録してDBを作成してください。
Redisを作成したら環境変数を控えておきましょう。

Image from Gyazo

Gmail APIの有効化

Gmail APIを使うには、GCPのプロジェクトを作成し(既存のものでOK)、Gmail APIを有効化してOAuthクライアントIDとシークレットを取得する必要があります。

手順は以下の通りです。

GCPでプロジェクト作成

Image from Gyazo

Gmail APIを有効化

Image from Gyazo

認証情報作成

Image from Gyazo

Google OAuth Platformがない場合は、まず作成する必要があります。

Image from Gyazo

Image from Gyazo

この後は必要な情報を入力していくだけなので割愛します。

Image from Gyazo

OAuthクライアント作成

Google OAuth Platformが登録できたら、OAuthクライアントを作成します。

Image from Gyazo

Image from Gyazo

Image from Gyazo

ここでJSONをダウンロードし、Client IDとClient Secretを控えてください。
中身は以下のようになります。

{
  "web": {
    "client_id": "*******.apps.googleusercontent.com",
    "project_id": "gmail-to-cosense",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "*******",
    "redirect_uris": [
      "http://localhost:5174/login/google/callback",
      "https://yourdomain.vercel.app/login/google/callback"
    ]
  }
}

OAuthクライアントにデータスコープ追加

Image from Gyazo

最低限必要なスコープを追加します。

Image from Gyazo

自分自身をテストユーザーに追加

アプリを公開するか、自分をテストユーザーに追加するかのどちらかをしないと、OAuth認証後にrefreshTokenが取得できません。今回は自分しか使わないので、自分をテストユーザーに追加します。

Image from Gyazo

本番モードにする

審査に出さなくて本番モードにしておくことをおすすめします。
Image from Gyazo

理由はテストモードだとアプリ側でのrefresh_tokenには規制がかかってるようになっているみたいです、3日ぐらいで期限切れてしまい、クローリングが失敗してしまいました。

Vercelにデプロイ

レポジトリ内のREADMEにある Deploy to Vercel ボタンをクリックすれば、そのままVercelにデプロイできます。

Image from Gyazo

Image from Gyazo

Image from Gyazo

環境変数の設定が必要になるので、以下のように設定してください。

GCPのOAuthクライアントIDとシークレット

GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

UpstashのRedis URLとトークン

UPSTASH_REDIS_URL=https://your-redis-url.upstash.io
UPSTASH_REDIS_TOKEN=your_redis_token

refreshトークンを暗号化するためのキー(32文字ランダム文字列)

TOKEN_ENCRYPTION_KEY=your_32_character_encryption_key

Vercelのcronジョブ用のシークレットキー(ランダムなセキュア文字列)

CRON_SECRET=your_random_cron_secret

その他

CosenseのセッションIDは、Cosenseにログインし、DevToolsを開き、cookiesから connect.sid の値を確認してください。

Image from Gyazo

Cosenseの他のAPIについては以下のドキュメントを参考にしてください。

https://scrapbox.io/help-jp/API

後置き

いかがでしたでしょうか?
スピード重視で作ったためテストは書いていません。もしバグなどあれば、issueやPRを立てていただけると助かります。🙇

Discussion