【GAS】取得したGmailの下書きにテンプレートが混入する謎仕様の検証

## 経緯

日報など、定型メールのひな形を以下のようなSpreadシートにまとめてGASでGmailの下書きを自動生成するツールを作った。

| to | cc | subject | body |
|:---|:---|:--------|:-----|
|test@example.com||作業計画|各位 お疲れ様です ---| 


チームに共有したところ、コードでは触れていないはずのテンプレートに関して謎のエラーが報告されたので確認してみる。

結論としては

- `GmailApp.getDrafts()`にはテンプレート（返信定型文）が含まれる
- 宛先の有無で判別するやり方で実用上はなんとかなりそう



なお、本記事において**テンプレート**はひな形を意味する一般名詞ではなく、Gmailのテンプレート（返信定型文）機能をさす。

## エラーの内容
テンプレート内にテンプレートと同名の下書きがあった場合に下書きが生成されない、上書きする場合は返信テンプレートが削除される。

ツールの仕様として、すでに作成済みの下書きと重複を避ける目的で、同名の既存の下書きが存在した場合にはスキップもしくは上書き（削除）するという処理をしているので、その辺が怪しい。

## 仮定

既存の下書きの確認は具体的には`getDrafts()`で下書きの一覧を取得し、作成中のメールと件名で照合をする形で行っている。
この時点で考えうるのは`getDrafts()`にテンプレートが含まれるのではないかということ。

## 検証1: getDrafts()にテンプレートが含まれるのか

### 関数
`GmailApp.getDrafts()`で取得した`[GmailDraft]`の一覧を確認する

以下の関数で一覧を取得できる。

```
function showDrafts() {
  const drafts = GmailApp.getDrafts();
  for( const draft of drafts){
    Logger.log(draft.getMessage().getSubject());
  }
}
```

### 条件
検証時点では下書き、およびテンプレートは複数存在していた。

なお、実際の業務用のメールを乗せるのははばかられるのと、単純にわかりにくいため、件名は以下のように差し替えている。

- 下書き
  - 下書き1
  - 下書き2
  - （中略）
  - 下書きn
- テンプレート
  - テンプレート1
  - テンプレート2
  - （中略）
  - テンプレートn


### 結果

```:ログ
[略] 下書き1
[略] 下書き2
（中略）
[略] 下書きn
[略] テンプレート1
[略] テンプレート2
（中略）
[略] テンプレート3
```

やはり`getDrafts()`に取得できるデータには下書きに加えテンプレートが含まれているらしい。
署名もそうだが、GASでGmailのすべてを操作できるわけではないため、仕様といってしまえば仕様なのだろうか…。

## 検証2: deleteDraft()でのテンプレートの削除

`GmailDraft.deleteDraft()`で削除してみる。

以下削除用の関数
面倒なので今回は下書きとテンプレートを全てを対象に`deleteDraft()`する

```javascript
function deleteAllDrafts() {
  const drafts = GmailApp.getDrafts();
  for( const draft of drafts){
    draft.deleteDraft();
  }
}
```

### 結果

before
![before.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400984/8ada4281-cd63-b569-39b6-568db4903817.png)

after
![after.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400984/ed09ebc5-4996-bb26-3490-48ee5136b089.png)


下書きは当然として、テンプレートも消えてしまっているのがわかる。

これを見る限り、テンプレートはGmailのUI上に表示されていないだけで、GAS上では普通に`GmailDraft`クラスの1インスタンスとして扱われているらしい。

## 課題: どうやって区別するのか
結論としては現時点では宛先の有無での区別が確実ではないにしろ現実的な手段だろうか

### isTemplate()的な関数が無い
`GmailMessage`クラスにある`isDraft()`のように、テンプレートを区別する`isTemplate()`メソッドがあればいいのだけれど、リファレンスを見る限り、[GmailDraft](https://developers.google.com/apps-script/reference/gmail/gmail-draft)にも[GmailMessage](https://developers.google.com/apps-script/reference/gmail/gmail-message)にも見当たらない。

テンプレートは割と新しい機能だった気がするので、GASがまだテンプレートに対応していないのかもしれない。

### To
テンプレートには宛先が含まれない。（それが不便だったからこそわざわざツールを作成したわけで…。）
それなら宛先の有無で完全ではないにしろ見分けがつくのではないか？
ということで確認してみる。

## 検証3: 宛先で区別ができるかの確認

`showDrafts()`に`to`を含むよう改修。

```javascript
function showDrafts2() {
  const drafts = GmailApp.getDrafts();
  for( const draft of drafts){
    Logger.log( "subject: " + draft.getMessage().getSubject() + "; to: " +  draft.getMessage().getTo() + ";");
  }
}
```

### 手順
1. 新規で下書きを作成する（宛先まで埋める）
2. このメールをもとにテンプレートを作成する
3. showDrafts2()を実行

### 結果
```:ログ
[略] subject: test; to: test.example.com;
[略] subject: test; to: ;
```
期待度売り、テンプレートの宛先は（作成元の宛先にかかわらず）空白になる模様。

定型メールに限らず、宛先を決めずにメールを作成することは通常まずないだろうから、実用上はこの区別方法で問題なさそう。

## その他試したこと
### テンプレートとGmailDraft.update()

テンプレートに対し`update()`で内容を書き換えると、下書き扱いになり、テンプレートのリストからは消える。
やっぱりGAS的にはテンプレートをいじるのは想定外な感じがする…。
いつか対応するんだろうか…。