gologiusの巣

プログラミングなどの技術メモです。誰かの役に立てるとうれしいです。

メール監視システムを作る その2(Pythonスクリプト編)

前回サーバー構築と設定をしました。 gologius.hatenadiary.com

今回はメールチェックとメール送信用のスクリプトを書いていきます。

使うスクリプト

GMailAPI を叩くPythonスクリプトです · GitHub

実行環境構築

(1) Google API を有効にしておく(下記URL参照)

スクリプト実行に必要なJSONファイルもDLできるはずです。

ゼロからはじめるPython(22) PythonでGmailのメールを確認しよう | マイナビニュース

(2) 以下のコマンドを実行し、モジュールをインストール

pip3 install google-api-python-client
pip3 install oauth2client
pip3 install httplib2

(3) 認証用関数user_auth()を実行する(1回のみ)

(4) JSONファイルcredentials-gmail.jsonが生成されます

メールの送受信

# -*- coding: utf-8 -*-
import httplib2
import base64
import traceback
from googleapiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
from email.mime.text import MIMEText
from email.utils import formatdate
 
SCOPES = 'https://mail.google.com/' # Gmail権限のスコープを指定
CLIENT_SECRET_FILE = 'client_id.json' # Google AP管理サイトからダウンロードした権限ファイルのパス
USER_SECRET_FILE = 'credentials-gmail.json' # ユーザーごとの設定ファイルの保存パス
USE_ADDR = "test@gmail.com" # 使用するメールアドレス

#認証用(開発環境を整える際に、初回に一回実行する)
def user_auth():
    store = Storage(USER_SECRET_FILE)
    credentials = store.get()

    # ユーザーが認証済みでない場合 新規認証する
    if not credentials or credentials.invalid:
        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)
 
    return credentials

#API使用準備
def get_service():
     credentials = user_auth()
     http = credentials.authorize(httplib2.Http())
     service = discovery.build('gmail', 'v1', http=http)
     return service

#N件メールを取得
def get_messages(maxnum):
    service = get_service()
    messages = service.users().messages()
    msg_list = messages.list(userId='me', maxResults=maxnum).execute()
    print("メールサーバーからの受信完了")
    
    payloads = []
    # 取得したメッセージの一覧を表示
    for msg in msg_list['messages']:
         topid = msg['id']
         payload = messages.get(userId='me', id=topid).execute()
         payloads.append(payload)    
        
         # メール情報を確認 
         item = mail.mail()
         headers = payload['payload']['headers']
         for header in headers:
             if header['name'] == 'Date':
                 print(header['value']) #受信日?
             if header['name'] == 'From':
                 print(header['value']) #from
             if header['name'] == 'To':
                 print(header['value']) #to
             if header['name'] == 'Cc':
                 print(header['value']) #cc
             if header['name'] == 'Subject':
                 print(header['value']) #件名
        
         print(payload['snippet']) #本文の概要(※全文は入らない)
         
    return

# メールを送信する
def send_message(to, subject, body):
    
    #メール作成
    message = MIMEText(body)
    message["from"] = USE_ADDR
    message["to"] = to
    message["subject"] = subject
    message["Date"] = formatdate(localtime=True)

    byte_msg = message.as_string().encode(encoding="UTF-8")
    byte_msg_b64encoded = base64.urlsafe_b64encode(byte_msg)
    str_msg_b64encoded = byte_msg_b64encoded.decode(encoding="UTF-8")
    rawdata =  {"raw": str_msg_b64encoded}
    
    #送信
    service = get_service()
    try:
        service.users().messages().send(
            userId="test@gmail.com",
            body=rawdata
        ).execute()            
        print("メール送信完了")
    except:
        print("メール送信エラー")
        traceback.print_exc()
        
    return 
    

gmail_mailbox.py

  • get_messages()でメール情報を取得できます
  • send_message()でメール送信できます

受信できれば後は好きに弄れば、メール監視スクリプトの完成です。

main.pyを叩くようなバッチを作成し(start.sh)、crontab -eにてそのバッチを叩くように設定します(前回記事参照)。

# -*- coding: utf-8 -*-
# main.py

import datetime

import gmail_mailbox

def job():
    # メール取得+チェック
    mails = gmail_mailbox.get_messages(40)
    print('メール取得完了')
    
    isError = checkError(mails) #適当にチェック
    
    # 現在時間と一緒に、処理結果を表示
    nowtime = datetime.datetime.now();
    timestr = nowtime.strftime('%Y/%m/%d %H:%M:%S')   
    body = u"<チェック結果>\n"
    body += u"isError " + str(isError) + "\n"    
    
    if (isError) == True:
        print("")
        print("【結果】 [" + timestr + "] 何か検知しています")
        print("")
        
        gmail_mailbox.send_message(u"example@gmail.com", u"システムエラー", body) 
        
    else:
        print("")
        print("【結果】 [" + timestr + "] 何もありませんでした")
        print("")
    
    return

job()
#!/bin/sh
cd  `dirname ${0}`
date
datestr=`date '+%Y%m%d'`

echo begin mail checker
python3 main.py >> log/${datestr}.log 2>&1
echo end mail checker

main.pyでは、メールを40通見て、エラーと判定されるとメールを送信するようにしています。

ポイント

  • from apiclientからfrom googleapiclientにモジュール名が変更されています。 古い記事を参考にしている場合、ここでエラーになる場合があります。
  • payload['snippet'] はメールの概要を見るためのものです。実際に全文見ようとすると、 別の項目エンコードする必要があります
  • 調査中ですが、メールを重複して受信する場合があります
    • 恐らく、独自にラベルを設定していると、受信トレイ分とラベル分、二つのメールを受信してしまうようです