GASでGmailのテンプレAddonツールを作る

GAS

どうやらGASにはまだまだ知らない機能があったようで・・・

日本語では最近の記事がヒットしないのですが、CardServiceというメソッドがあります。
これをうまく使うとGmailに宛先、CC、BCC、件名、本文などなどをテンプレとして登録し、一発で呼び出すアドオンを実装できるみたいなので作りました。

スポンサーリンク

完成イメージ

Gmailでメールを新規作成するときに、こんな感じでテンプレを呼び出せるようにします。

定型的なメールをよく使う人には意外と便利そうじゃないでしょうか?

では、具体的なコードを載せていきます。

コード書く前の準備

いつも通り、スプレッドシートを公開しておきます。

Gmailテンプレ

各自でマイドライブにコピーして使ってください。
(たまに編集権限をリクエストされる方がいますが、コピーして使ってくださいね!)

コピーしたらスプレッドシートの拡張機能→AppsScriptを開いて
GASのマニフェストファイルというのを編集できるようにしておきましょう。

コード

まずはコード.gsです。コピペでOKです。

function createTemplete() {
  //テンプレシート
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ss_url = ss.getUrl();
  const sheet = ss.getActiveSheet();
  const sheet_id = sheet.getSheetId();
  const sheet_url = ss_url + '#gid=' + sheet_id;
  //アドオンのボタン設定
  const edit_button = CardService.newTextButton()
    .setText('編集')
    .setTextButtonStyle(CardService.TextButtonStyle.FILLED)
    .setBackgroundColor("#696969")
    .setOpenLink(CardService.newOpenLink()
      .setUrl(sheet_url)
    );
  const buttons = CardService.newCardSection();
  //テンプレシートのデータ取得
  const data = sheet.getDataRange().getValues().filter(function(x){return !(x === null || x === undefined || x === "");});
  const display_name1_idx = 0;
  const display_name2_idx = 1;
  const to_idx = 2;
  const cc_idx = 3;
  const bcc_idx = 4;
  const subject_idx = 5;
  const body_idx = 6;
  //アドオンへテンプレデータを連携
  if(data.length == 1){
    buttons.addWidget('テンプレが未設定です。');
  }else{
    for(let i = 1; i < data.length; i++){
      buttons.addWidget(CardService.newTextButton()
        .setText(data[i][display_name1_idx] + data[i][display_name2_idx])
        .setOnClickAction(CardService.newAction()
          .setFunctionName('addTemplete')
          .setParameters({
            'to': data[i][to_idx],
            'cc': data[i][cc_idx],
            'bcc': data[i][bcc_idx],
            'subject': data[i][subject_idx],
            'body': data[i][body_idx]
          })
        )
      
      )
    }
  }
  const card = CardService.newCardBuilder()
    .addSection(CardService.newCardSection()
      .addWidget(edit_button)
    )
    .addSection(buttons)
    .build();
  return [card];
}

function addTemplete(e){
  //引数から各値を取得
  const to = e.parameters['to'] ? e.parameters['to'].split(',') : [];
  const cc = e.parameters['cc'] ? e.parameters['cc'].split(',') : [];
  const bcc = e.parameters['bcc'] ? e.parameters['bcc'].split(',') : [];
  const subject = e.parameters['subject'] ? e.parameters['subject'] : "";
  const body = e.parameters['body'] ? e.parameters['body'] : "";
  const sp_body = body.split(String.fromCharCode(10)).join('<br />');//HTMLフォーマット変換
  Logger.log("To: " + to + "\nCC: " + cc + "\nbcc: " + bcc + "\n件名: " + subject + "\n本文: \n" + body + "\nHTML: \n" + sp_body);
  //各値をカードサービスで扱えるように準備。to,cc,bccが空白だとエラーが出るので初期値に[{"email": ""}]を設定すること。
  let card_to = CardService.newUpdateDraftToRecipientsAction().addUpdateToRecipients([{"email": ""}]); 
  if(to.length > 0){card_to = CardService.newUpdateDraftToRecipientsAction().addUpdateToRecipients([to]);}
  let card_cc = CardService.newUpdateDraftCcRecipientsAction().addUpdateCcRecipients([{"email": ""}]);
  if(cc.length > 0){card_cc = CardService.newUpdateDraftCcRecipientsAction().addUpdateCcRecipients([cc]);}
  let card_bcc = CardService.newUpdateDraftBccRecipientsAction().addUpdateBccRecipients([{"email": ""}]);
  if(bcc.length > 0){card_bcc = CardService.newUpdateDraftBccRecipientsAction().addUpdateBccRecipients([bcc]);}
  let card_subject = CardService.newUpdateDraftSubjectAction().addUpdateSubject("");
  if(subject != ""){card_subject = CardService.newUpdateDraftSubjectAction().addUpdateSubject(subject);}
  let card_body = CardService.newUpdateDraftBodyAction()
      .addUpdateContent(
        "",
        CardService.ContentType.MUTABLE_HTML
      )
      .setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT);
  if(body != ""){
    card_body = CardService.newUpdateDraftBodyAction()
      .addUpdateContent(
        sp_body,
        CardService.ContentType.MUTABLE_HTML
      )
      .setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT);
  }
  let result = CardService.newUpdateDraftActionResponseBuilder()
      .setUpdateDraftToRecipientsAction(card_to)
      .setUpdateDraftCcRecipientsAction(card_cc)
      .setUpdateDraftBccRecipientsAction(card_bcc)
      .setUpdateDraftSubjectAction(card_subject)
      .setUpdateDraftBodyAction(card_body)
      .build(); 
  return result;
}

続いて、マニフェストファイルを編集しましょう。
全体をコピペで大丈夫です。

{
  "timeZone": "Etc/GMT-9",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "gmail": {
    "name": "Gmailテンプレート",
    "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/label_googblue_24dp.png",
    "openLinkUrlPrefixes": [
      "https://mail.google.com/"
    ],
    "primaryColor": "#4285F4",
    "secondaryColor": "#0000ff",
    "composeTrigger": {
      "selectActions": [
        {
          "text": "テンプレートを作成",
          "runFunction": "createTemplete"
        }
      ]
    }
  }
}

その後、ctrl + s でプロジェクトを保存してください。

で、画面右上の「デプロイ」から「デプロイをテスト」をクリックしてください。
ポップアップしてきた画面の右下に「インストール」とあるので、インストールをクリック、
完了をクリックで準備完了です。

Gmailを開いてください。
設定を見ると「アドオン」タブに「インストール済みのデベロッパーアドオン」というのが確認できると思います。
確認できない場合はアドオンを有効化し再度インストールしてみてください。

さらに、Gmailのサイドバーに下記画像のようなアイコンが増えていると思います。

で、肝心の機能の箇所ですが、
新規メールを作成してみてください。

下記画像のように青いインデックスの画像が出てきていると思います。
クリックして「アクセスを承認」を進めてください。

そうすると「Gmailテンプレート」というのが出てくると思います。
スプレッドシートで設定したテンプレが選択できますので、表示名をクリックしてテンプレを適用してみてください。

下書きにテンプレ内容が入力されれば無事機能追加完了です。

ちなみに、件名と本文は必須にしています。
TO、CC、BCCは空白許可するコードになっていますが、他の穴あきでエラーが起きた場合はご愛嬌です。

情シスが厳しい会社だったらChrome拡張機能が使えないと思うので

自前で作った機能なのでセキュリティ等々はクリアできているはずです。
機能を実行するためにどこにもデータ送信しませんから。

Chrome拡張機能は便利なものが多いですが、他所の人が作ったものですので情シス的には信用できないのです。
特に既に審査通った拡張機能を誰かが買収したりして悪意のあるコードを埋め込んでアップデート、なんかがあるとストア審査も潜り抜けたりするらしいので。

機能としてはシンプルですが刺さる人には刺さるのではないでしょうか。

コメント

  1. やまかん より:

    コメントさせて頂きます。
    GmailテンプレートGAS、あっという間に実装できすばらしいの一言です。

    これだけでも十分活用できるのですが、ちょっとリクエストというか、ご教授頂きたいのですがこちらのGASには検索機能なども実装可能でしょうか?
    テンプレートがたくさん増えてきたときに、選択画面上で検索機能があったら・・・と。

    プログラミングの知見が無く、急に不躾なお話となってしまい申し訳ないです。

    • たいぼん より:

      なるほど・・・
      数が増えると検索ほしくなりますよね。
      自分の手札には検索機能実装のイメージがないのですが、スプシの順番や名前にプレフィックスを付けることで少しは工夫になるかな?というところでしょうか・・・
      ちょっと考えてみます!

  2. やまかん より:

    たいぼん様
    ご返信ありがとうございます!
    Noやプレフィックスが一番すぐできて分かりやすいですね!

    他の記事も参考にさせていただいています。
    本当にありがとうございますm(_ _)m

タイトルとURLをコピーしました