(第3回)GmailAPIを使用したメールの自動作成

(第3回)GmailAPIを使用したメールの自動作成

目次

振り返り
プログラムの修正
動作確認
まとめ

振り返り

前回は固定パスのファイルをパスワード付きで圧縮し、そのファイルを添付した下書きと圧縮する際に使用したパスワードが記載された下書きを作成するところまで行いました。
今回は汎用的に使用できるようにファイルをドラッグアンドドロップで複数ファイルを圧縮できるように変更したいと思います。

プログラムの修正

下記の2点をできるようにプログラムを修正していきます。

  • ドラッグアンドドロップでファイルのパスを引数で渡す
  • 複数ファイルを圧縮できるようにする

1、importの追加をします。
→引数を受け取る際に使用します。

import sys

2、メール本文の作成をしている「create_message_compress」メソッドにドラッグアンドドロップしたファイルのデータを取得するためのコードを追加します。

# ドラッグアンドドロップした際のファイルのパスを取得 ・・・ ※1
file_paths = sys.argv[1:]

# ドラッグアンドドロップした際のファイルのパスの区切り文字を「/」に変更 ・・・ ※2
for index, value in enumerate(file_paths):
    # ファイルのパスの区切り文字を変更
    file_paths[index] = value.replace("\\", "/")
    # 圧縮ファイル内の階層を追加 ・・・ ※3
    file_depth.append("")

※1:「sys.argv[1:]」でファイルのパスを取得できますが、インデックスの始まりが、「1」となる為
   注意してください。
   ちなみに「0」には実行ファイルのパスが入っております。
※2:引数からパスを取得すると区切り文字が「\」となっています。
    Python上で「\」はエスケープ文字となっており、そのままだとファイルを圧縮する際にエラーとなる為
   注意してください。
※3:ファイルごとに圧縮ファイル内の階層を変更したい場合にはコードを変更してください。

3、圧縮する際にメソッドを変更します。
「compress」→「compress_multiple」

pyminizip.compress_multiple(file_paths, file_depth, path, password, 1)  

引数は下記の通りです。
「compress」の引数とほとんど同じですが、第1と第2が配列もしくはリストとなる点に注意しください。
 第1:圧縮するファイルのパスを配列もしくはリストで指定(ファイル名を含める)
 第2:圧縮フォルダ内の階層を配列もしくはリストで指定
 第3: 出力する際のパスを指定 (ファイル名を含める)
 第4: 圧縮する際のパスワード
 第5:0~9で圧縮率を指定 
→0は無圧縮で数値が大きくなればなるほどに圧縮率が高くなります。

4、これまではコンソールが自動で閉じてしまい、正常終了したか異常終了したかがわからない状態でしたのでエラー処理を追加しようと思います。
メインの関数を下記のように修正します。

if __name__ == '__main__':
    try:
        main()

        # 正常終了の際のメッセージ
        print('\n**********正常終了**********')

        os.system('PAUSE') ・・・ ※1

    except Exception as e:  ・・・ ※2

        # 異常終了の際のメッセージ
        print('**********異常終了**********\n')
        # エラーメッセージの出力
        print(e)      

        os.system('PAUSE') ・・・ ※1

※1:スクリプトの実行後にコンソールが閉じないようにします。
※2:今回は「Excepthion」を指定しているが、特定のエラーのみ処理を変更や特定のエラーのみエラーを出力する際には「Excepthion」の変更や追加をしてください。

動作確認

1、ファイルを複数選択して「quickstart.py」にドラッグアンドドロップします。

2、正常終了し下記のメッセージが表示されます。

3、下書きが作成されます。

4、「手順3」の下書きに添付されているファイルをダウンロードします。

5、圧縮ファイルを展開します。
ドラッグアンドドロップする際に指定していたファイルが確認できます。

6、参考までにエラーで停止した際には下記のメッセージが表示されます。
赤枠がエラーの内容となります。

7、コード全体は下記となります。

from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# クイックスタートに足りない項目のimport
import base64
from email.mime.text import MIMEText
from apiclient import errors
# 今回追加したimport
# メールの本文の内容を格納するクラス
from email.mime.multipart import MIMEMultipart
# メールの添付ファイルのデータを格納するクラス
from email.mime.application import MIMEApplication
# ファイルのパスからファイル名を取得
from os.path import basename
# パスワード付き圧縮するためのライブラリ
import pyminizip
# パスワード生成の乱数生成に使用
import random
import sys
import warnings
warnings.simplefilter("ignore")

# Gmail APIのスコープを設定
SCOPES = ['https://www.googleapis.com/auth/gmail.modify']

# Gmailの下書き作成 
def create_draft(service, user_id, message_body):
  try:
    message = {'message': message_body}
    draft = service.users().drafts().create(userId=user_id, body=message).execute()

    print ('Draft id: %s\nDraft message: %s' % (draft['id'], draft['message']))

    return draft
  except errors.HttpError as error:
    print ('エラー: %s' % error)
    return None

# 添付ファイルのメール本文の作成
def create_message_compress(subject, message_text, password):
    # メールの内容を格納
    message = MIMEMultipart()    
    message['subject'] = subject
    message.attach(MIMEText(message_text))
    
    # ファイルを添付
    path = "C:/GmaiDraft/test.zip"

    # ドラッグアンドドロップした際のファイルのパスを取得
    file_paths = sys.argv[1:]

    # 圧縮ファイル内のパスの指定もfile_pathsと同様インデックスで指定する必要がある為、配列を追加
    file_depth = []

    # ドラッグアンドドロップした際のファイルのパスの区切り文字を「/」に変更
    for index, value in enumerate(file_paths):
        # ファイルのパスの区切り文字を変更
        file_paths[index] = value.replace("\\", "/")
        # 圧縮ファイル内の階層を追加
        file_depth.append("")

    pyminizip.compress_multiple(file_paths, file_depth, path, password, 1)    

    with open(path, "rb") as f:
        part = MIMEApplication(
            f.read(),
            Name=basename(path)
        )
    part['Content-Disposition'] = 'attachment; filename="%s"' % basename(path)
    message.attach(part)

    encode_message = base64.urlsafe_b64encode(message.as_bytes())
    return {'raw': encode_message.decode()}

# パスワード記載のメール本文の作成
def create_message_password(subject, password):
    # メールの内容を格納
    message = MIMEMultipart()    
    message['subject'] = subject
    message.attach(MIMEText(password))
    
    encode_message = base64.urlsafe_b64encode(message.as_bytes())
    return {'raw': encode_message.decode()}

# パスワードの作成
def create_password():
    # パスワードの桁数
    passwordLength = 8
 
    # パスワード
    password = ''
 
    #  パスワードに使う文字列
    passwordPattern = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
 
    # パスワードを生成ループ
    for i in range(0, passwordLength):
        password = password + random.sample(passwordPattern, 1)[0]

    return password

# メインの処理
def main():
    # Google認証の処理
    creds = None
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server()
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    # GmailAPIを実行するオブジェクト作成
    service = build('gmail', 'v1', credentials=creds)

    # パスワードの作成
    password = create_password()

    # 添付ファイル付き下書きメールの作成
    subject = '添付ファイルメール'
    message_text = 'ファイルを添付しています'

    message = create_message_compress(subject, message_text, password)

    # 下書き作成
    create_draft(service, 'me', message)

    # パスワード記載した下書きメールの作成
    subject = '添付ファイルメール'

    message = create_message_password(subject, password)
    
    # 下書き作成
    create_draft(service, 'me', message)

if __name__ == '__main__':
    try:
        main()

        # 正常終了の際のメッセージ
        print('\n**********正常終了**********')
        os.system('PAUSE')

    except Exception as e:

        # 異常終了の際のメッセージ
        print('**********異常終了**********\n')
        print(e)      
        os.system('PAUSE')

まとめ

今回はドラッグアンドドロップにて任意の複数ファイルを圧縮しGmailの下書きに添付することが出来ました。
本記事は今回で終了となります。
今回初めて「Python」を利用し、うまく動作せず苦労などもありましたが、これを機に「Python」を使用した記事を今後も書いていきたいと思います。