【Python】OUTLOOKの添付ファイルを指定フォルダに自動保存するアプリ開発

/

【Python】OUTLOOKの添付ファイルを指定フォルダに自動保存するアプリ開発

Pythonのtkinterを使用して、OUTLOOKで受信したメールから添付ファイルを自動的に指定フォルダへ保存するアプリケーションの作成方法を解説していきます。

指定した日付、指定した受信フォルダの添付ファイルのみを保存するため、仕事でも非常に有効なアプリケーションです。

作成したアプリはexeファイルにして配布すれば、社内の誰でもすぐに使うことができるデスクトップアプリケーションになるので非常に便利です。

それでは作成するアプリケーションの開発方法を詳しく解説していきます。

アプリ概要(GUI画面・機能)

これから作成するアプリの概要を説明します。

GUIの画面は以下のようになります。

outlookプログラムのGUI画面

以下の機能を有するアプリケーションを作成します。

機能一覧

対象メールの期間選択

保存先フォルダ(パス)の選択

対象受信フォルダの選択

期間や受信フォルダで絞り込みされたメールの添付ファイルを指定フォルダへ保存

以上の機能を有するOUTLOOKの添付ファイル保存プログラムを作成します。

GUI画面の作成

Pythonの標準ライブラリであるtkinterを使ってGUIを作成します。

tkinterの使い方は以下のリンクをご覧ください。

GUIのソースコードを下記に記します。

import tkinter as tk
import tkinter.ttk as ttk
# メインウィンドウの設定
root = tk.Tk()
root.title("OUTLOOK操作")
root.geometry("600x300")

# メインフレームの作成と設置
frame = ttk.Frame(root)
frame.grid(column=0, row=0, sticky=tk.NSEW, padx=5, pady=10)

# 各種ウィジェットの作成
label_start = ttk.Label(frame, text="集計開始日(yyyy/mm/dd):")
entry_start = ttk.Entry(frame)
label_end = ttk.Label(frame, text="集計終了日(yyyy/mm/dd):")
entry_end = ttk.Entry(frame)
label_folder = ttk.Label(frame, text="出力先フォルダ:")
entry_folder = ttk.Entry(frame, width=50)
button_folder = ttk.Button(frame, text="参照")
label_outlook = ttk.Label(frame, text="OUTLOOK受信フォルダ名:")
entry_outlook = ttk.Entry(frame)
button_execute = ttk.Button(frame, text="実行")

# 各種ウィジェットの設置
label_start.grid(row=0, column=0, padx=10, pady=2)
entry_start.grid(row=0, column=1, sticky=tk.W)
label_end.grid(row=1, column=0, padx=10, pady=2)
entry_end.grid(row=1, column=1, sticky=tk.W)
label_folder.grid(row=2, column=0, padx=10,pady=2, sticky=tk.E)
entry_folder.grid(row=2, column=1,sticky=tk.W)
button_folder.grid(row=2, column=2, sticky=tk.E)
label_outlook.grid(row=3, column=0, padx=10, pady=2, sticky=tk.E)
entry_outlook.grid(row=3, column=1, sticky=tk.W)
button_execute.grid(row=4, column=1, pady=10)

root.mainloop()

上記のソースコードから以下のGUI画面が作成されます。

outlookプログラムのGUI画面(tkinter)

集計終了日に初期値として本日の日にちをセットする場合は下記のコードを追記します。

import datetime  #追加
import tkinter as tk
import tkinter.ttk as ttk
############
GUI画面
############

# entry_endに本日の日にちをセットする
dt_now = datetime.datetime.now()
dt_now = dt_now.strftime("%Y/%m/%d")
entry_end.insert(tk.END, dt_now)

root.mainloop()

これでまず土台ができましたので、このGUI画面に機能を追加していきます。

保存先フォルダーの選択機能

保存先のフォルダーを選択する機能の関数を下記のように作成します。

from tkinter import filedialog
def ask_folder():
  fld = filedialog.askdirectory()
  entry_folder.insert(tk.END, fld)

filedialog.askdirectory()でフォルダ選択のダイアログを表示します。

選択したフォルダをinsertメソッドでentry_folderにセットします。

テキストボックスから文字列の取得・セット・クリアは下記リンク先でご確認ください。

定義したask_folder関数をbutton_folderに割り当てます。

button_folder = ttk.Button(frame, text="参照", command=ask_folder)

PythonでOUTLOOKへのメールアクセス

以下にOUTLOOKの受信フォルダ・サブフォルダ・各メールへアクセスするプログラムを記します。

import win32com.client
# Outlookからメール情報を取得
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# OUTLOOK受信フォルダ名に入力があるかの判定
if not entry_outlook.get():
    # 受信フォルダのメールを取得
    folders = outlook.GetDefaultFolder(6)
else:
    # 指定されたメールフォルダのメールを取得
    folders = outlook.GetDefaultFolder(6).Folders[entry_outlook.get()]
# メールフォルダ内のメールにアクセス
mails=folders.Items

win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")により、OUTLOOKアプリに接続します。

win32com.clientライブラリを使うためには事前にインストールが必要なので、下記コマンドでインストールしてください。

pip install pypiwin32

次のif判定では、OUTLOOK受信フォルダ名に入力がなければ受信フォルダ(Inbox)にアクセスし、入力があればそのフォルダにアクセスします。
*受信フォルダのサブフォルダまでしか今回はアクセスできません。

mails=folders.Itemsでアクセスしたフォルダからメール情報を取得しています。

添付ファイル保存用フォルダの作成

メールから添付ファイルを取得する前に、添付ファイルを保存するフォルダを指定されたパスに作成します。

#添付ファイルの保管用フォルダ作成
newfolder_path = entry_folder.get() + '/Outlook_test'
# 作成フォルダが存在するかの確認
if os.path.isdir(newfolder_path) == False:
    # フォルダがなければ作成する
    os.makedirs(newfolder_path)

指定されたフォルダ内(entry_folder)にOutlook_testというフォルダを作成(os.makedirs())します。

もしすでに作成されていた場合は作成しないようにif判定をしています。

フォルダがすでに存在するかどうかはos.path.isdir()を使用します。

絞り込み日程の取得

入力された絞り込み日程を取得します。

# 絞り込み日程の取得
startdate = datetime.datetime.strptime(entry_start.get(), '%Y/%m/%d')
enddate = datetime.datetime.strptime(entry_end.get(), '%Y/%m/%d')

getメソッドで文字列を取得したままだとstring型なので、datetime.datetime.strptimeでdatetime型に変換しています。

OUTLOOKからメール情報を取得

OUTLOOKの指定されたフォルダからメールを取得して、添付ファイルがあれば保存するプログラムを下記に記します。

#メール情報を1件1件取得し、添付ファイルがあれば保存する
for mail in mails:
    RT=mail.ReceivedTime
    period = datetime.datetime(RT.year ,RT.month, RT.day, RT.hour, RT.minute, RT.second)
    if startdate <= period <= enddate:
        if mail.Attachments.Count > 0:
            myDate = RT.strftime("%Y/%m/%d")
            myDate = myDate.replace("/","-")
            datefolder_path = newfolder_path + '\\' + myDate
            if os.path.isdir(datefolder_path) == False:
                os.makedirs(datefolder_path)
            for myAttachment in mail.Attachments:
                folder_path = datefolder_path + '\\' + myAttachment.FileName
                if os.path.isfile(folder_path) == False:
                    myAttachment.SaveAsFile(folder_path)
messagebox.showinfo("完了","添付ファイルをダウンロードしました")

これまでに解説したOUTLOOK操作を関数として定義して、実行ボタンにそれを割り当てれば今回のプログラムは作成します。

まとめ

今回作成したプログラムすべてのソースコードを以下に記します。

import win32com.client
import datetime
import os
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog
from tkinter import messagebox
import os.path

# 保存先フォルダーを指定し、entry_folderにセットする
def ask_folder():
    fld = filedialog.askdirectory()
    entry_folder.insert(tk.END, fld)

def click_execute():
    # Outlookからメール情報を取得
    outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
    if not entry_outlook.get():
        # 受信フォルダのメールを取得
        folders = outlook.GetDefaultFolder(6)
    else:
        # 指定されたメールフォルダのメールを取得
        folders = outlook.GetDefaultFolder(6).Folders[entry_outlook.get()]
    # メールフォルダ内のメールにアクセス
    mails=folders.Items

    #添付ファイルの保管用フォルダ作成
    newfolder_path = entry_folder.get() + '/Outlook_test'
    # 作成フォルダが存在するかの確認
    if os.path.isdir(newfolder_path) == False:
        # フォルダがなければ作成する
        os.makedirs(newfolder_path)

    # 絞り込み日程の取得
    startdate = datetime.datetime.strptime(entry_start.get(), '%Y/%m/%d')
    enddate = datetime.datetime.strptime(entry_end.get(), '%Y/%m/%d')


    #メール情報を1件1件取得し、添付ファイルがあれば保存する
    for mail in mails:
        RT=mail.ReceivedTime
        period = datetime.datetime(RT.year ,RT.month, RT.day, RT.hour, RT.minute, RT.second)
        if startdate <= period <= enddate:
            if mail.Attachments.Count > 0:
                myDate = RT.strftime("%Y/%m/%d")
                myDate = myDate.replace("/","-")
                datefolder_path = newfolder_path + '\\' + myDate
                if os.path.isdir(datefolder_path) == False:
                    os.makedirs(datefolder_path)
                for myAttachment in mail.Attachments:
                    folder_path = datefolder_path + '\\' + myAttachment.FileName
                    if os.path.isfile(folder_path) == False:
                        myAttachment.SaveAsFile(folder_path)
    messagebox.showinfo("完了","添付ファイルをダウンロードしました")
# メインウィンドウの設定
root = tk.Tk()
root.title("OUTLOOK操作")
root.geometry("600x300")

# メインフレームの作成と設置
frame = ttk.Frame(root)
frame.grid(column=0, row=0, sticky=tk.NSEW, padx=5, pady=10)

# 各種ウィジェットの作成
label_start = ttk.Label(frame, text="集計開始日(yyyy/mm/dd):")
entry_start = ttk.Entry(frame)
label_end = ttk.Label(frame, text="集計終了日(yyyy/mm/dd):")
entry_end = ttk.Entry(frame)
label_folder = ttk.Label(frame, text="出力先フォルダ:")
entry_folder = ttk.Entry(frame, width=50)
button_folder = ttk.Button(frame, text="参照", command=ask_folder)
label_outlook = ttk.Label(frame, text="OUTLOOK受信フォルダ名:")
entry_outlook = ttk.Entry(frame)
button_execute = ttk.Button(frame, text="実行", command=click_execute)

# 各種ウィジェットの設置
label_start.grid(row=0, column=0, padx=10, pady=2)
entry_start.grid(row=0, column=1, sticky=tk.W)
label_end.grid(row=1, column=0, padx=10, pady=2)
entry_end.grid(row=1, column=1, sticky=tk.W)
label_folder.grid(row=2, column=0, padx=10,pady=2, sticky=tk.E)
entry_folder.grid(row=2, column=1,sticky=tk.W)
button_folder.grid(row=2, column=2, sticky=tk.E)
label_outlook.grid(row=3, column=0, padx=10, pady=2, sticky=tk.E)
entry_outlook.grid(row=3, column=1, sticky=tk.W)
button_execute.grid(row=4, column=1, pady=10)

dt_now = datetime.datetime.now()
dt_now = dt_now.strftime("%Y/%m/%d")
entry_end.insert(tk.END, dt_now)

root.mainloop()