Python Gmailデータ取得

## 前提
以前作成した下記記事の環境からスタート

https://qiita.com/sh19982580/items/11a918da6d1a03ddf265

## GCP設定
クレデンシャルを作成
GCPのコンソール上で`APIとサービス` > `認証情報`
OAuth クライアント IDの作成
アプリケーションの種類：デスクトップ

→ JSONをダウンロードして、appと同じ階層に`client_id.json`として作成

## アクセス許可

gmail.py

    import json
    from oauth2client import client
    from oauth2client import tools
    from oauth2client.file import Storage
    import httplib2

    SCOPES = 'https://www.googleapis.com/auth/gmail.readonly'
    CLIENT_SECRET_FILE = 'client_id.json'
    USER_SECRET_FILE = 'credentials-gmail.json'

    def create_service():
        store = Storage(USER_SECRET_FILE)
        credentials = store.get()
        if not credentials:
            flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
            flow.user_agent = 'Python Gmail API'
            credentials = tools.run_flow(flow, store, None)
            print('認証結果を保存しました:' + USER_SECRET_FILE)
            print(json.dumps(credentials.to_json()))
        elif credentials.invalid:
            credentials.refresh(httplib2.Http())
            print(json.dumps(credentials.to_json()))
        return credentials

app.py

    import os
    from flask import Flask
    import gmail

    app = Flask(__name__)

    @app.route("/")
    def test ():
        gmail.create_service()
        return "ok"

    if __name__ == "__main__":
        app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

#### 確認
1. ターミナルで`python3 app.py`を実行
1. 別ターミナルで`curl http://localhost:8080`を実行
→ Gmailのアクセスを許可するかブラウザが起動する
→ 許可
→ `credentials-gmail.json`がappと同じ階層に作成されていればOK！！

## コード
先ほど作成した`create_service`関数の下に`get_messages`の関数を作成

#### 全体取得

    def get_messages():
        credentials = create_service()
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        messages = service.users().messages()
        msg_list = messages.list(userId='me', maxResults=1).execute()
        for msg in msg_list['messages']:
            topid = msg['id']
            msg = messages.get(userId='me', id=topid).execute()
            print(msg)

※どんなデータが取得できるか見れる

#### 件名取得

    def get_messages():
        credentials = create_service()
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        messages = service.users().messages()
        msg_list = messages.list(userId='me', maxResults=1).execute()
        for msg in msg_list['messages']:
            topid = msg['id']
            msg = messages.get(userId='me', id=topid).execute()
        #  件名の取得
        for msg in msg_list['messages']:
            topid = msg['id']
            msg = messages.get(userId='me', id=topid).execute()
            for header in msg['payload']['headers']:
                if header['name'] == "Subject": 
                    print(header['value'])

#### 本文取得

    def get_messages():
        credentials = create_service()
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        messages = service.users().messages()
        msg_list = messages.list(userId='me', maxResults=1).execute()
        for msg in msg_list['messages']:
            topid = msg['id']
            msg = messages.get(userId='me', id=topid).execute()
            # 本文の取得
            if(msg["payload"]["body"]["size"]!=0):
                decoded_bytes = base64.urlsafe_b64decode(
                    msg["payload"]["body"]["data"])
                decoded_message = decoded_bytes.decode("UTF-8")
                print(decoded_message)
            else:
                #メールによっては"parts"属性の中に本文がある場合もある
                decoded_bytes = base64.urlsafe_b64decode(
                    msg["payload"]["parts"][0]["body"]["data"])
                decoded_message = decoded_bytes.decode("UTF-8")
                print(decoded_message)

#### 要約取得

    def get_messages():
        credentials = create_service()
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        messages = service.users().messages()
        msg_list = messages.list(userId='me', maxResults=1).execute()
        for msg in msg_list['messages']:
            topid = msg['id']
            msg = messages.get(userId='me', id=topid).execute()
            # 要約の取得
            print(msg['snippet'])

#### 添付ファイル取得(Excel)

downloadフォルダを作成しておく

    def get_messages():
        row_list = []
        credentials = create_service()
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        messages = service.users().messages()
        msg_list = messages.list(userId='me', maxResults=1).execute()
        for msg in msg_list['messages']:
            topid = msg['id']
            msg = messages.get(userId='me', id=topid).execute()
            
            for part in msg['payload']['parts']:
                if 'filename' in part and part['filename'] and 'attachmentId' in part['body']:
                    msgId = msg['id']
                    att_id = part['body']['attachmentId']
                    att = service.users().messages().attachments().get(userId='me',messageId=msgId,id=att_id).execute()
                    data = att['data']
                    file_info = base64.urlsafe_b64decode(data.encode('UTF-8'))
                    excel = pd.ExcelFile(file_info)
                    sheet = excel.parse("シート1", header=None)
                    for row in sheet.iterrows():
                        row_str = ",".join(map(str, row))
                        row_list.append(row_str)
                    row_data = '\n'.join(row_list)
                    # csvの形になっているか確認
                    with open("downloadフォルダ「パスのコピー」/test.csv", mode='w') as f:
                        f.buffer.write(str.encode(row_data))

requirements.txtの追記

    flask
    oauth2client
    google-api-python-client

app.pyの変更
`gmail.create_service()` →　`gmail.get_messages()`

- ターミナル1で`python3 app.py`
- ターミナル2で`curl http://localhost:8080`
先ほど作成したdownloadフォルダにtest.csvとして格納されていればOK！

## 最後に

コード > 全体取得の部分で`print(msg)`を見た時、かなり複雑なデータになっているなと感じました。
また、ボットから送られてくるメールだとデータ構造が違うということが起きるので作成したコードでもデータ取得できないことがあります。
メール内にある添付ファイル取得する処理も追記しましたが、これもデータを見てからではないと取れないことがあります。


## 参考文献

https://news.mynavi.jp/techplus/article/zeropython-22/

https://100webdesign.jp/services/web_knowhow/gmail-api/web_knowhow-22940/