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

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

目次

振り返り
ライブラリのインストール
パスワード圧縮処理を前回のコードにマージ
まとめ

振り返り

前回はGmailAPIを下書きを作成するところまで作成しました。
今回は添付ファイルをパスワード付き圧縮し、そのファイルを添付した下書きとその圧縮する際に使用したパスワードが記載された下書きを作成します。

ライブラリのインストール

Pythonの標準関数でzipの圧縮や、パスワード付き圧縮ファイルの解凍はできるのですが、パスワード付き圧縮ができません。
パスワード付き圧縮するためには「pyminizip」というライブラリをインストールする必要があります。

1、インストールを実施。
Visual Studio Codeのターミナルを開き以下のコードを入力します。

pip install pyminizip

2、動作の確認をします。

# 「pyminizip」のimport
import pyminizip

def main():
    # パスワード付き圧縮を実施
    pyminizip.compress("C:/GmaiDraft/test.txt", "", "C:/GmaiDraft/test.zip", "abc123", 1)

if __name__ == '__main__':
    main()

※引数は下記の通りです。
第1:圧縮するファイルのパスを指定(ファイル名を含める)
第2:圧縮フォルダ内の階層を指定
第3: 出力する際のパスを指定 (ファイル名を含める)
第4: 圧縮する際のパスワード
第5:0~9で圧縮率を指定 
→0は無圧縮で数値が大きくなればなるほどに圧縮率が高くなります。

3、パスワードを作成するコードを追加します。

import pyminizip
import random

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():
    # パスワードを生成
    password = create_password()

    # コンソールにパスワードを表示
    print(password)

    # 圧縮の実行
    pyminizip.compress("C:/GmaiDraft/test.txt", "", "C:/GmaiDraft/test.zip", password, 1)

if __name__ == '__main__':
    main()

4、実行します。下記のパスワードが表示されました。
パスワード:3MpzD3vH

5、圧縮ファイルが作成されました。

6、先ほど出力されたパスワード「3MpzD3vH」を入力して解凍します。

7、問題なく解凍することが出来ました。

パスワード圧縮処理を前回のコードにマージ

1、インポートするライブラリの追加

# メールの本文の内容を格納するクラス
from email.mime.multipart import MIMEMultipart
# メールの添付ファイルのデータを格納するクラス
from email.mime.application import MIMEApplication
# ファイルのパスからファイル名を取得
from os.path import basename
# パスワード付き圧縮するためのライブラリ
import pyminizip
# パスワード生成の乱数生成に使用
import random

2、メールの本文作成する関数を編集
※添付ファイル付きの関数をパスワード記載のメールの関数を分けています。
 
 ■添付ファイル付きメール本文作成関数

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

    path = "C:/GmaiDraft/test.zip"
    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()}

3、メイン関数の修正

# メインの処理
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)

4、参考までにコード全体を記載します。

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

# 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))
    
    # ファイルを添付
    pyminizip.compress("C:/GmaiDraft/test.txt", "", "C:/GmaiDraft/test.zip", password, 1)    

    path = "C:/GmaiDraft/test.zip"
    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__':
    main()

5、実際に実行して動作を確認します。

6、2件の下書きが作成されて想定通りの内容で作成されました。

  • パスワード付き圧縮されたファイルが添付されている下書き
  • 圧縮する際に設定したパスワードが記載されているメール

まとめ

今回、想定通りのプログラムが作成できました。
ですが、まだ1つのファイルしか指定できなかったり、パスが固定のパスのみの対応となっている為、次回はそういった部分を汎用的に使用できるように修正したいと思います。