かずきち。の日記

サーバサイドエンジニアのつぶやき

こんなに簡単だったの?GoogleAppsScriptのたった2つのファイルでpdf作成Gmailのサイドバーを作成していく!

Gmailのサイドバーにはサイドバーアプリがある

Gmailはみなさんがお使いのメーラーです。
しかし、拡張機能というものがあり、「…」ボタンを押すとアプリの追加ができます。
ここにはDropboxEvernoteといった追加機能があると思います。
チェーンのマークが今回自作したアプリになります。
今回はこのGmail拡張機能の作り方について紹介します。

今回はこのGmailの追加拡張機能を自作で作っていくことを目標とします。
このコードがしていることはGmailで受信したメールをpdfとして、一発でGoogleドライブに保存するという代物です。

ファイル構成

appscript.json
コード.gs
の2つのファイルだけで拡張機能が作れます。

appscript.json

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.addons.execute",
    "https://www.googleapis.com/auth/gmail.readonly",
    "https://www.googleapis.com/auth/gmail.modify",
    "https://mail.google.com/",
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/userinfo.email"
  ],
  "gmail": {
    "name": "メール保存アドオン",
    "logoUrl": "https://img.icons8.com/ios/38/link--v1.png",
    "contextualTriggers": [
      {
        "unconditional": {},
        "onTriggerFunction": "buildAddOn"
      }
    ],
    "openLinkUrlPrefixes": [
      "https://mail.google.com/"
    ],
    "primaryColor": "#f5f5f5",
    "secondaryColor": "#4285F4",
    "version": "TRUSTED_TESTER_V1"
  },
  "runtimeVersion": "V8",
  "exceptionLogging": "NONE",
  "dependencies": {
    "enabledAdvancedServices": [
      {
        "userSymbol": "Drive",
        "version": "v2",
        "serviceId": "drive"
      }
    ]
  },
  "timeZone": "Asia/Tokyo"
}

コード.gs

 * マニフェスト 'onTriggerFunction' フィールドで指定されたアドオン起動トリガー
 * 
 * @param {Object} イベントオブジェクト
 * @return {Card} カードオブジェクト
 */
function buildAddOn(e){
    var accessToken = e.messageMetadata.accessToken;
    GmailApp.setCurrentMessageAccessToken(accessToken);

    var messageId = e.messageMetadata.messageId;
    var message = GmailApp.getMessageById(messageId);
    var subject = message.getSubject();                 // 件名
    var from = message.getFrom();                       // 送信元
    var attachments = message.getAttachments();         // 添付ファイル

    // UI を作る
    var buttonSet = CardService.newButtonSet();
    var exportButton = CardService.newTextButton()
        .setText('Drive Export')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('driveExport')
            .setParameters({'messageId': messageId}));

    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader()
            .setTitle(subject))
        .addSection(CardService.newCardSection()
            .addWidget(CardService.newKeyValue()
                .setTopLabel('送信元')
                .setContent(from))
            .addWidget(CardService.newKeyValue()
                .setTopLabel('添付ファイル数')
                .setContent(attachments.length + ' 個'))
                            .addWidget(CardService.newKeyValue()
                .setTopLabel('本拡張機能使い方')
                            .setContent('本拡張機能は受信したメールをpdf化し、<br>ご自身のGoogleドライブに保存します'))
                            .addWidget(exportButton))
        .build();

    return card;
}

/**
 * 指定されたメッセージ識別子に対応するメール本文と添付ファイルを Google ドライブに格納する
 * 
 * @param {Object} イベントオブジェクト
 */
function driveExport(e){
    var messageId = e.parameters['messageId'];
    var message = GmailApp.getMessageById(messageId);

    var driveFolder = 'Gmail Export';
    var folders = DriveApp.getFoldersByName(driveFolder);
    var folder = folders.hasNext() ? folders.next() : DriveApp.createFolder(driveFolder);

    html = 'あああ';
    html += 'From: ' + message.getFrom() + '<br />';
    html += 'To: ' + message.getTo() + '<br />';
    html += 'Date: ' + message.getDate() + '<br />';
    html += 'Subject: ' + message.getSubject() + '<br />';
    html += '<hr />';
    html += message.getBody().replace(/<img[^>]*>/g, '');
    html += '<hr />';

    var attachments = [];
    var atts = message.getAttachments();
    for ( var i = 0; i < atts.length; i++ ) attachments.push(atts[i]);

    if ( attachments.length > 0 ) {
        var footer = '<ul><a href="https://mori-building.cybozu.com/k/#/portal">業務関連リンク</a>';
        for ( var i = 0; i < attachments.length; i++ ) {
            var file = folder.createFile(attachments[i]);
            footer += '<li><a href="' + file.getUrl() + '">' + file.getName() + '</a></li>';
        }
        html += footer + '</ul>';
    }

    var tempFile = DriveApp.createFile('temp.html', html, 'text/html');
    folder.createFile(tempFile.getAs('application/pdf')).setName(message.getSubject() + '.pdf');
//  tempFile.setTrashed(true);
    deleteFile(tempFile.getId());
}

/**
 * 指定したファイルを Google ドライブから完全削除する
 * 
 * @param {String} ファイル ID
 */
function deleteFile(fileId){
    var token = ScriptApp.getOAuthToken();
    var response = UrlFetchApp.fetch(Utilities.formatString('https://www.googleapis.com/drive/v3/files/%s', fileId), {
        method: 'delete',
        headers: {
            'Authorization': 'Bearer ' + token
        },
        muteHttpExceptions: true
    });
}

ここまでコードをかけたら完成です。
あとはディプロイしていきます。

エディタ右上にディプロイボタンがあるかと思います。
これでコードを実際のGmailに配置します。

新しいディプロイ→ディプロイをテストを選択します。
Application(s):Gmailをインストールします。
これで自身のGmailにコードを流し込み、改造することができます。

エディタ右上にディプロイボタンがあるかと思います。
これでコードを実際のGmailに配置します。

新しいディプロイ→ディプロイをテストを選択します。
Application(s):Gmailをインストールします。
これで自身のGmailにコードを流し込み、改造することができます。