GoogleAppsScriptでGmailの下書きを作成する方法

GoogleAppsScript（以後、GAS）は非常に便利です。ウェブ上で完結できるスクリプト環境としては一番のお気に入りです。

今回は、GASでできるGmailの操作について紹介したいと思います。あくまで個人的な覚書き程度に試したものですが、まとめていきます。


# 目的と概要
　Gmailで下書きを作成する（添付ファイル付き含む）

　参考にしたのは次の記事です。
[Create a Gmail draft with attachments via Google Apps Script #gas #gmail](https://gist.github.com/oshliaer/7e96514c3cb3075dde02)
　ぶっちゃけ、このサイトで紹介されているテクニックを、自分なりのコーディングに置き換えたメモ書き程度の紹介です。他の方も同内容で投稿されているでしょうし、まずは本家記事を参考にされたほうがよいでしょう。

　GASでは標準サービスの機能として、Gmailを操作する **GmailApp** およびメールを送信する **MailApp**があります。
これらのサービスに **sendMail** メソッドというメール送信機能がありますが、これはあくまでもその場でメール送信するためのもので、下書きを作成できるわけではありません。

　標準の機能では下書きを作成することはできそうにないとわかったため、Googleが汎用的に提供しているAPIを使って実現したいと思います。
　普通にプログラミング言語を準備してGoogleのAPIを使用するよりも、GASではAPIの利用も比較的手軽に使えるのがメリットでしょう。

# 準備
　GASの一通りの操作ができることを前提としています。

1. GASのプロジェクトを新規作成する
Googleドライブを開き、「作成」→「その他」→「Google Apps Script」と辿って選択します。

※標準では使える状態になっていないため、接続（インストールのようなもの）をする必要があります。
その場合、「作成」→「その他」→「アプリを追加」と辿って選択肢、Google Apps Scriptを検索して接続してください。

1. GASのエディタ画面に切り替わったら、「リソース」→「Googleの拡張サービス」と辿り、選択します。

2. 「Googleの拡張サービス」の中から「Gmail API」を探し、右端のトグルスイッチを切り替えて有効にします。
![win8cap0090a.png](https://qiita-image-store.s3.amazonaws.com/0/38416/b490905a-173b-c1a6-a3af-7a880ff88e93.png)
※なお、別途Google API コンソールでも有効にする必要があるため、同ウィンドウの下にある「Google API コンソール」のリンクをクリックしてください。
3. Google APIのダッシュボードが開きますので、画面上部の中央付近にある「APIを有効にする」のリンクをクリックします。
4. 様々なサービスのAPIが列挙されるので、「G Suite APIs」の欄から「Gmail API」のリンクをクリックします。
![win8cap0090b.png](https://qiita-image-store.s3.amazonaws.com/0/38416/de7ae62b-dd58-c8fc-d38f-e4fce8d4e1f3.png)

5. 画面上部中央付近にある「APIを有効にする」をクリックします。
これでGmail APIを利用する準備ができました。以後、この画面ではAPIの利用状況を確認できます。「割り当て」を見ていただくとわかると思いますが、使用に際する制限も、GASのGmailの制限とは比べ物にならないほど緩く、大量に使えるようになります。

6. 上記にある参考サイトから次のファイルをダウンロードします。
 - quoted-printable.js
 - utf8.js

※この二つは、GASのエディタ画面にて、「ファイル」→「新規作成」→「スクリプトファイル」と辿り、新しく開かれたエディタ部分にコピペして貼り付けます。スクリプトファイル自体の保存名はなんでもかまいません。

これで準備完了です。APIコンソールを開いているタブおよびウィンドウを閉じ、GASのエディタ画面に戻ってください。

# コーディング
下記、スクリプト全文です。
なお、参考記事のコードとは若干異なります。

```gas:draft.gs
function nonASCII(str) {
  return '=?UTF-8?B?' + Utilities.base64Encode(str, Utilities.Charset.UTF_8) + '?=';
}
function draftsend(data) {
  var uid = "me";
  var thid = ""; 
  var separator = "\n";
  var boundary = "m293049p2923s45"; //適当に
  Logger.log("data object=").log(data);
  var dr2 = Gmail.newDraft();
  var msg2 = Gmail.newMessage();
  var bodytext = data.body;//.replace(/\r/g,"");
  var rfcstr = [
    "MIME-Version: 1.0",
    "Subject:" + nonASCII(data.subject) ,
    "To: " + data.to,
    'From: ' + data.from
  ];
  if (data.cc != "") rfcstr.push("Cc: " + data.cc);
  if (data.bcc != "") rfcstr.push("Bcc: " + data.bcc);
  
  rfcstr.push('Content-Type: multipart/mixed; boundary=' + boundary + separator);
  rfcstr.push("--" + boundary);
  rfcstr.push("Content-Type: text/plain; charset=UTF-8");
  rfcstr.push("Content-Transfer-Encoding: quoted-printable");
  rfcstr.push(quotedPrintable.encode(utf8.encode(bodytext)));
  //rfcstr.push(separator);
  //---添付ファイル設定開始
  for (var i = 0; i < data.attachments.length; i++) {
    var item = data.attachments[i];
    var bb = Utilities.newBlob(item.data);
    rfcstr.push("--" + boundary);
    rfcstr.push("Content-Type: " + item.opt.type + "; charset=" + item.opt.encoding + "; name=" + item.opt.name);
    rfcstr.push('Content-Disposition: attachment; filename="' + item.opt.name + '"');
    rfcstr.push('Content-Transfer-Encoding: base64' + separator);
    rfcstr.push(Utilities.base64Encode(bb.getBytes()));
    
  }
  rfcstr.push('--' + boundary + '--');
  Logger.log(rfcstr.join(separator));
  var b64str = Utilities.base64EncodeWebSafe(rfcstr.join(separator),Utilities.Charset.UTF_8);
  Logger.log(b64str);
  msg2.raw = b64str;
  
  //---返信の場合、返信メールのURLからスレッドID切り出し
  if (data.replyurl != "") {
    var replyarr = data.replyurl.split("/");
    if (replyarr.length > 0) {
      //---安全のため、httpsで、mail.google.comがURLに含まれる場合のみ取得
      if ((replyarr.indexOf("https:") > -1) && (replyarr.indexOf("mail.google.com") > -1)) {
        //---スレッドIDは現状、ほぼ確実にURLの最後部分？
        msg2.threadId = replyarr[replyarr.length-1];
      }
    }
  }
  dr2.message = msg2;
  Logger.log(dr2);
  
  
  var finaldr = Gmail.Users.Drafts.create(dr2, uid);
  return JSON.stringify(finaldr);
}
```

　基本的にはMIMEを構築すべく、一行一定義とする配列「rfcstr」にひたすら push していくだけです。
　本文は、そのままだったりGASで使用可能なエンコードしても無駄なので、今回拝借した、「quotedPrintable」と「utf8」を使います。

　添付ファイルを付ける場合は、GASのUtilitiesにある「newBlob」と「base64Encode」がささやかながら活躍です。
　「Utilities.newBlob」でBlob化した添付ファイルを、MIMEの各パートの定義の後に push します。ここでは「Utilities.base64Encode」でその名の通りエンコードします。受け渡す引数はBlob自体ではなく、getBytes（）でバイト化したものなので、間違えないように注意したいものです。

　サンプルでは返信時の下書きにも対応させています。この場合は、受け渡す引数の中に返信元のメールのスレッドIDを忍び込ませておく必要があります。

　最後に、GmailAPIの「Gmail.Users.Drafts.create」を呼び出せば下書き完了です。作業時のGoogleアカウントでGmailを開くと、下書きのメールが保存されているはずです。

# 展開例

　私の場合、GASでウェブアプリ化するのが好きなので、同プロジェクトでHTMLを作成し、そこに画面のためのHTMLとjavascript等を用意し、ウェブアプリ化します。
　あとはdoGet()やdoPost()関数をあらかじめ準備し、javascript側で「google.script.run.*****」でGAS側の目的の関数を呼び出せば、専用の簡易メール作成画面も作れます。
（GASを試し始めた2～3年前よりも着実にGASの動作速度は速くなっていると実感できるので、安心して使えます）


# 終わりに
　G Suiteを入れている今の仕事場でメールセキュリティに関する要件をもらった際、標準で使えるGmail / Google Drive / GASでもここまでできるよと作ってプレゼンしたサンプルの一部で使ったのが今回の下書き保存です。
　残念ながら目的の要件では無事（？）にサードパーティ製のクラウドサービスを使うことになりお蔵入りしましたが、汎用的に使えそうなテクニックとして社内でまとめています。