見出し画像

[Python] Outlookで受信したメールから添付ファイルを指定フォルダに保存する

はじめに

今回は、PythonでOutlookで受信したメールから、添付ファイルを指定フォルダに保存する処理を実装します。

このPythonスクリプトを実行する前提条件としては、PCにOutlookがインストールされている必要があります。

処理概要は、下記です。

  • 受信トレイ内の特定のフォルダにあるメールを取得

  • 受信日が該当月の場合、添付ファイルを特定のフォルダにダウンロードする

  • ダウンロードしたファイルは、メール受信月を先頭に、次に送信者名のファイル名に設定して、保存する(例:メール受信月が「2022年9月」で、送信者が「AAA株式会社」の場合、「202209_AAA株式会社」)

この処理は、月1回、月末日に実行することを想定しています。

使用するライブラリ

PythonでWindowsのアプリ・ファイルを扱うためのライブラリです。

使用する際には、インストールが必要です。

pip install pywin32

動作環境

  • windows11

  • Python 3.10.2

Outlookの設定

メールを取得するOutlookの受信トレイは、受信トレイの中に「領収書」フォルダが存在する構成としています。

Outlookの受信トレイのフォルダ構成

また、領収書として保存したいメールの「領収書」フォルダへのメール移動は、仕分けルールを設定してメールの振り分けを行うよう設定しています。

添付ファイルの保存先のフォルダ構成

メールの受信日の年、月に対応するフォルダに保存していきます。フォルダ構成は、下記です。

\\001_領収書						
└─2022				
 ├─202201		
 ├─202202		
 ├─202203		
 ├─202204		
 ├─202205		
 ├─202206		
 ├─202207		
 ├─202208		
 ├─202209		
 ├─202210		
 ├─202211		
 └─202212
保存先のフォルダ構成

実装

全体の処理は下記です。

import datetime
import calendar
from pathlib import Path

import win32com.client

SAVE_FOLDER_ROOT = r'H:\xxxxx\001_領収書'

def get_first_day_of_this_month(date: datetime):
    return date.replace(day=1)

def get_end_of_this_month(date: datetime):
    _, end_day = calendar.monthrange(date.year, date.month)
    return date.replace(day=end_day)

def main():
    # 実行日より、対象月の月初日、月末日を取得
    now = datetime.datetime.now()
    start_date = get_first_day_of_this_month(now)
    end_date = get_end_of_this_month(now)

    # 保存するフォルダ名、ファイル名を作成
    year_folder_name = now.strftime('%Y')
    year_month = now.strftime('%Y%m')
    save_folder_path = Path(SAVE_FOLDER_ROOT) / year_folder_name / year_month

    outlook = win32com.client.Dispatch('Outlook.Application').GetNamespace('MAPI')

    inbox = outlook.GetDefaultFolder(6)  # 受信トレイ…「6」

    recept_folder = inbox.folders['領収書']

    # メールを取得
    for mail in recept_folder.Items:
        received_date = datetime.datetime(mail.ReceivedTime.year ,mail.ReceivedTime.month, mail.ReceivedTime.day, mail.ReceivedTime.hour, mail.ReceivedTime.minute, mail.ReceivedTime.second)

        if start_date <= received_date <= end_date:
         
	    # 添付ファイルを取得
            for attachment in mail.Attachments:
                attachment_file = Path(attachment.FileName)
                file_name = f'{year_month}_{mail.Sender}{attachment_file.suffix}'
                save_file_path = save_folder_path / file_name

                if not save_file_path.exists():
                    attachment.SaveAsFile(save_file_path)
                break

if __name__ == '__main__':
    main()

順番に処理の内容を説明します。

メールの受信日を絞り込むため、開始日、終了日を算出

処理実行日の月に受信したメールのみ処理対象とするため、絞り込み開始日として、実行日の月の月初日、絞り込み終了日として、実行日の月の月末日を取得します。

get_first_day_of_this_month関数で、月初日を取得します。
月初日の算出は、datetimeモジュールのdatetime.replaceメソッドを使用します。キーワード引数・dayには、月初日の1を設定します。

def get_first_day_of_this_month(date: datetime):
    return date.replace(day=1)

get_end_of_this_month関数で、月末日を取得します。
月末日の算出は、calendarモジュールのcalendar.monthrangeメソッドを使用します。
引数に、年、月を渡すと、月初日の曜日と、月の日数がタプルで戻り値として返されます。
そのため、月の日数を関数の戻り値として返します。

def get_end_of_this_month(date: datetime):
    _, end_day = calendar.monthrange(date.year, date.month)
    return date.replace(day=end_day)

保存先のフォルダ、ファイル名を作成

保存先のフォルダは、メール受信日の年と、年月で保存します。
実行日から年、年月を、datetimeモジュールのdatetime.strftimeメソッドを使用して、日付を文字列に変換します。

次に、ファイルのフルパスを、pathlibモジュールを使用し、Pathオブジェクトを生成し、パスの連結をしています。

  year_folder_name = now.strftime('%Y')
  year_month = now.strftime('%Y%m')
  save_folder_path = Path(SAVE_FOLDER_ROOT) / year_folder_name / year_month

Outlookからメール情報を取得

win32comモジュールを使用し、Outlookからメール情報を取得します。

outlook = win32com.client.Dispatch('Outlook.Application').GetNamespace('MAPI')

次に、受信トレイのフォルダを取得するには、outlook.GetDefaultFolderメソッドを使用します。
受信トレイを取得する場合、引数には、「6」を指定します。
今回は、受信トレイに「領収書」フォルダを配置しているため、下記のように指定することで、「領収書」フォルダを取得することができます。

inbox = outlook.GetDefaultFolder(6)  # 受信トレイ…「6」
recept_folder = inbox.folders['領収書']

それ以外のフォルダを指定する場合、下記を参照ください。

Outlookからメールを取得し、添付ファイルを保存する

「領収書」フォルダ内から、メールを取得します。今回、メール情報としては、下記を取得しています。

  • 受信日時…ReceivedTime

  • 送信者名…Sender

  • 添付ファイル情報…Attachments

受信日時を、datetimeオブジェクトに変換し、該当月の月初日から月末日内に受信したかどうかを判定します。

for mail in recept_folder.Items:
  received_date = datetime.datetime(mail.ReceivedTime.year ,mail.ReceivedTime.month, mail.ReceivedTime.day, mail.ReceivedTime.hour, mail.ReceivedTime.minute, mail.ReceivedTime.second)

  if start_date <= received_date <= end_date:

対象月に受信したメールの場合、添付ファイルをフォルダに保存します。
Pathlib.existsメソッドを使用し、同一ファイル名が存在しない場合のみ、添付ファイルを保存します。

  for attachment in mail.Attachments:
    attachment_file = Path(attachment.FileName)
    file_name = f'{year_month}_{mail.Sender}{attachment_file.suffix}'
    save_file_path = save_folder_path / file_name

    if not save_file_path.exists():
      attachment.SaveAsFile(save_file_path)

実行結果

該当月に受信したメールに添付されているファイルが保存されるのを確認できました!

まとめ

今回は、PythonでOutlookで受信したメールから、添付ファイルを指定フォルダに保存する処理について、まとめました。
毎月の定期実行は、WindowsOSのタスクスケジューラを設定しました。下記記事より設定方法ご参照ください。

参考サイト


この記事が気に入ったらサポートをしてみませんか?