PythonでGmailの下書きを作成する 

<b>作成日は2020年9月26日です。</b>


##環境
```
Windows10 home
Python 3.8.3
google-auth-oauthlib 0.4.1
google-api-python-client 1.12.2
```

## やりたいこと
ローカル環境でPythonを動かし、GmailにAPI経由で下書きを作りたい。

この記事では必要最低限だけのエラーハンドリングもクソもないコードを書きます。
悪しからず。


## 手順
大まかな手順は以下のようになっています。

1. GCPでプロジェクトの作成
2. GCPで認証情報の作成
3. Pythonスクリプトの作成

## 1. GCPでプロジェクトの作成〜 2. 認証情報の作成
1と2に関しては記事→「[Python を使い、Gmail API 経由で Gmail の送受信を行う](https://qiita.com/muuuuuwa/items/822c6cffedb9b3c27e21)」
が大変にわかりやすいです。


基本的に記事に従っていけば問題はないはずですが、自分の場合<b>「VivaldiでGCPにアクセスをすると`client_<id>.json`がダウンロード出来ない」</b>というバグがありました。
これはChromeを使用することで回避出来ました。



## 3. Pythonスクリプトの作成
流れとしては、
OAuth認証のフローに従ってアクセストークンを取得
↓
送るメールのデータを作成
↓
Gmail APIを叩いて下書きを作成

という感じです。

### 1. アクセストークンの取得
アクセストークン取得をする必要最低限の関数は以下のような感じです。
参考→[API の認証と呼び出し(Google Cloudのガイド)](https://cloud.google.com/bigquery/docs/authentication/end-user-installed?hl=ja#authenticating-and-calling-the-api)

```python
from google_auth_oauthlib.flow import InstalledAppFlow
#APIのスコープを設定(どのAPIを使うのかの設定)
SCOPES = ["https://www.googleapis.com/auth/gmail.modify"]

def get_credential():
    launch_browser = True
    flow = InstalledAppFlow.from_client_secrets_file("client_id.json", SCOPES)
    flow.run_local_server()
    cred = flow.credentials
    return cred
```
`InstalledAppFlow.from_client_secrets_file`にGCPから落としてきたJSONファイルと、使用したいAPIの情報を入れ`Flowインスタンス`を作成し、`run_local_server()`をするとブラウザが立ち上がりお馴染みの許可画面が出てきます。
![スクリーンショット 2020-09-26 170859.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/f65cf76b-8caf-e653-d831-000ad20da7c9.jpeg)



これで許可を押すとアクセストークンが手に入ります。

因みに、このまではプログラムの実行毎に許可画面が立ち上がるので、アクセストークンをpickle化して保存するのが実用上は簡便でよさそうです。

### 2. メールの下書きの作成
```py

from email.mime.text import MIMEText
import base64

def create_message(sender, to, subject, message_text):
    enc = "utf-8"
    message = MIMEText(message_text.encode(enc), _charset=enc)
    message["to"] = to
    message["from"] = sender
    message["subject"] = subject
    encode_message = base64.urlsafe_b64encode(message.as_bytes())
    return {"raw": encode_message.decode()}
```
Gmail APIドキュメントの[Creating draft messages](https://developers.google.com/gmail/api/guides/drafts#creating_draft_messages)に載っているものですが、ドキュメントの場合、`create_message`関数の最後の行が

```py

return {'raw': base64.urlsafe_b64encode(message.as_string())}
```
となっています。
しかし、`base64.urlsafe_b64encode()`は入力として文字列ではなくbyteを入れる必要があるため、

```py
encode_message = base64.urlsafe_b64encode(message.as_bytes())
```
と変更し、後の下書きに保存する過程ではstr型が求められるので

```py
return {"raw": encode_message.decode()}
```
とデコードします。

### 3. Gmail APIで作成したメールのデータを下書きに保存する
先ほど作成したメールのデータを下書きに追加します。

```python

def create_draft(service, user_id, message_body):
    message = {'message':message_body}
    draft = service.users().drafts().create(userId=user_id, body=message).execute()
    return draft
```
この中で使われている`service`はGmail APIを使う時の親玉みたいなやつで、[Gmail APIのReference](https://developers.google.com/gmail/api/reference/rest)に載っている関数が入ったインスタンスです。
これは以下のコードで作ります。

```py

from googleapiclient.discovery import build

service = build("gmail", "v1", credentials=creds, cache_discovery=False)
```

以上をまとめて一つのプログラムにすると以下のような感じになります。

```py

from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build

import base64
from email.mime.text import MIMEText

SCOPES = ["https://www.googleapis.com/auth/gmail.compose",]


def get_credential():
    launch_browser = True
    flow = InstalledAppFlow.from_client_secrets_file("client_id.json", SCOPES)
    flow.run_local_server()
    cred = flow.credentials
    return cred


def create_message(sender, to, subject, message_text):
    enc = "utf-8"
    message = MIMEText(message_text.encode(enc), _charset=enc)
    message["to"] = to
    message["from"] = sender
    message["subject"] = subject
    encode_message = base64.urlsafe_b64encode(message.as_bytes())
    return {"raw": encode_message.decode()}


def create_draft(service, user_id, message_body):
    message = {'message':message_body}
    draft = service.users().drafts().create(userId=user_id, body=message).execute()
    return draft


def main(sender, to, subject, message_text):
    creds = get_credential()
    service = build("gmail", "v1", credentials=creds, cache_discovery=False)
    message = create_message(sender, to, subject, message_text)
    create_draft(service, "me", message)


if __name__ == "__main__":

    sender = "メールの送り主のアドレス"
    to = "送信先のアドレス"
    subject = "件名"
    message_text = "本文"

    main(sender=sender, to=to, subject=subject, message_text=message_text)
```

これを実行すれば、Gmailに下書きが追加されます。
やったね！(･∀･)

## 参考
・一番お世話になった記事
https://qiita.com/muuuuuwa/items/822c6cffedb9b3c27e21

・FlowクラスやInstalledAppFlowクラスのドキュメント
[google_auth_oauthlib.flow module](https://google-auth-oauthlib.readthedocs.io/en/latest/reference/google_auth_oauthlib.flow.html#google_auth_oauthlib.flow.Flow)

・googleapiclient.discovery.buildのドキュメント
https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build