- Windows でメール自動化をしたい
- Python で Outlook を操作したい
Windows 環境なら Outlook を操作することで間接的にメールの操作ができます。
とはいえ、Python から Outlook を直接触ることができないので、ここでは win32com というライブラリを使って操作していきます。
本記事の内容は以下のとおりです。
- 準備編
- メールの作成と操作
- メールから情報抽出
どの操作でも「準備編」の内容は必要になりますので、こちらは必ず目をお通しください。
win32com で Excel を自動化する方法も興味がある方はどうぞ。
» 参考:【ExcelとPythonの最強コラボ!】win32comを使ったExcel操作のすべて
【準備編】 Outlook でメール作業を自動化する
まずは、Python で Outlook を操作する準備をしましょう。
- ライブラリのインストール
- Outlook アプリケーションの呼出
- メールフォルダの設定
① はコマンドライン上のお話なので、最初の一度だけ行います。
一方、② と ③ は Python コード内のお話になりますので、Outlook を使いたい場合に毎回コードを書くことになります。
1. ライブラリのインストール
まずはコマンドプロンプトで以下を実行してください。
pip install pywin32
これにより、Python 上から Outlook が操作できるモジュール win32com が使えるようになります。
なお、最近の開発では pip ではなく Poetry が使われることも増えてきました。
興味のある方はチャレンジしてみてください。
2. Outlook アプリケーションの呼出
Python から Outlook を呼び出すコードは次の通りです。
import win32com.client
# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("Outlook.Application")
4行目の outlook が「Outlook アプリケーションの実態」です。
この後の自動化コードはすべて、この Outlook アプリケーションに対して処理を加えていく流れになります。
3. メールフォルダの設定
「受信トレイ」や「下書きフォルダ」など、Outlook 内のフォルダに対して処理を行いたい場合があると思います。
その場合には、以下のような形でフォルダを定義します。
import win32com.client
# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")
draft_folder = namespace.GetDefaultFolder(16) # 16: 下書き
namespace は、Outlook 上に登録されているアカウントに関する情報が丸ごと格納されているオブジェクトと考えるとわかりやすいです。
namespace を呼び出しておくと、今回のようなフォルダへのアクセス、アカウント情報の取得、カレンダー情報へのアクセスなども可能になります。
ここではGetDefaultFolder() メソッドを使ってフォルダオブジェクトを取得してきたというわけです。
以下は、よく使うフォルダの番号です。
フォルダ名 | 番号 |
---|---|
受信トレイ | 6 |
送信トレイ | 4 |
送信済みアイテム | 5 |
下書き | 16 |
迷惑メール | 23 |
そのほかにも様々なフォルダ番号が用意されていますので、公式ドキュメントの方も確認してみてください。
【実践編 1】メールの作成と操作
これにて Python で Outlook を動かす準備が整いました。
続いて、次の内容を解説します。
- メールを作成して下書きに保存する
- メールを送信する
- 装飾つきのメールを送信する
メールを作成して下書きに保存する
「メールを作成して、下書きに保存する」という基本的なコードをお伝えします。
import win32com.client
# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("outlook.application")
mapi = outlook.GetNamespace("MAPI")
draft_folder = mapi.GetDefaultFolder(16) # 16: 下書き
# メールオブジェクトの作成
mail = outlook.CreateItem(0) # 0: メールアイテム
mail.To = "xxx@example.com"
mail.Subject = "件名"
mail.Body = "これはテストメールです。"
mail.Attachments.Add(r"C:\Users\username\somefile.csv")
# 下書きフォルダに保存
mail.Save()
mail.Move(draft_folder)
メールの作成でキモになるのは outlook.CreateItem(0) の部分です。
# メールオブジェクトの作成
mail = outlook.CreateItem(0)
これにより、一通のまっさらなメールが変数 mail の中に生成されます。
もちろんこの段階では「宛先」「件名」「本文」「添付ファイル」などは設定されていません。
そこで、この mail オブジェクトにプロパティを付加していきます。
# プロパティを設定
mail.To = "xxx@example.com"
mail.Subject = "件名"
mail.Body = "これはテストメールです。"
mail.Attachments.Add(r"C:\Users\username\somefile.csv")
ここまでくると mail オブジェクトには「宛先」「件名」「本文」「添付ファイル」が設定された状態になります。
最後に下書きフォルダに保存します。
# 下書きフォルダに保存
mail.Save()
mail.Move(draft_folder)
mail オブジェクトはまだ実体がないので、先に mail.Save() として保存をします。
mail オブジェクトの実体が作られたところで、Move() メソッドにより下書きフォルダに移動しました。
メールを送信する
下書き保存ができるようになれば、送信は簡単です。
import win32com.client
# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("outlook.application")
mapi = outlook.GetNamespace("MAPI")
# メールオブジェクトの作成
mail = outlook.CreateItem(0) # 0: メールアイテム
mail.To = "xxx@example.com"
mail.Subject = "件名"
mail.Body = "これはテストメールです。"
mail.Attachments.Add(r"C:\Users\username\somefile.csv")
# 送信
mail.Send()
作成したメールオブジェクトに対して Send() メソッドで送信しましょう。
装飾つきのメールを送信する
メール本文に装飾をつけたい場合には、HTML形式にします。
import win32com.client
# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("outlook.application")
mapi = outlook.GetNamespace("MAPI")
# メールオブジェクトの作成
mail = outlook.CreateItem(0) # 0: メールアイテム
mail.bodyFormat = 2 # HTML形式
mail.To = "xxx@example.com"
mail.Subject = "件名"
mail.HTMLBody = """<h1>見出し</h1><p style="color: red;">テキストが入ります。</p>"""
mail.Attachments.Add(r"C:\Users\username\somefile.csv")
# 送信
mail.Send()
メールを HTML 形式にするポイントは次の2つです。
- mail.bodyFormat を 2 にする
- 本文の指定は HTMLBody を使う
特にHTMLBody を使うことは忘れてしまいがちなので、特に注意しましょう。
本文には HTML タグを使って記述すれば、色をつけたり見出しをつけたりなどリッチな表現ができます。
メールに画像を埋め込む方法
本来「メール」というものはテキストデータのみを送受信する想定で作られているため、本文に画像を埋め込みたい場合には一手間が必要になります。
結論として、画像データは base64 でバイナリ化して埋め込みます。
import base64
import win32com.client as win32
def image_file_to_base64(file_path):
"""画像 => base64"""
with open(file_path, "rb") as image_file:
base64_obj = base64.b64encode(image_file.read())
base64_str = base64_obj.decode("utf-8")
return base64_str
# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("outlook.application")
mapi = outlook.GetNamespace("MAPI")
# メールオブジェクトの作成
mail = outlook.CreateItem(0) # 0: メールアイテム
mail.bodyFormat = 2 # HTML形式
mail.To = "xxx@example.com"
mail.Subject = "件名"
picture = image_file_to_base64(r"C:\Users\username\image.jpg")
mail.HTMLBody = f"""<img src="data:image/jpg;base64,{picture}" />"""
# 送信
mail.Send()
HTML の <img src> タグに画像を指定する際、バイナリデータを直接指定しています。
メールを移動する
メールを移動する場合には、以下のように Move() メソッドを使います。
import win32com.client
# APPの初期化
outlook = win32com.client.Dispatch("Outlook.Application")
mapi = outlook.GetNamespace("MAPI")
account = "your_email_address"
destination_folder = "archive"
# 移動元と移動先のフォルダを指定
inbox = mapi.GetDefaultFolder(6)
archive = outlook.Folders[account].Folders[destination_folder]
# 件名に'Test'を含むメールをarchiveフォルダに移動
mails = inbox.Items
for mail in mails:
if "Test" in mail.Subject:
mail.Move(archive)
print(f"Moved: {mail.Subject}")
上記では、複数アカウントが存在する場合にアカウントを跨いで移動ができるようコードを組んでみました。
【実践編 2】メールから情報抽出
メールの情報(件名や本文など)を抽出するには次の手順が必要です。
- メールフォルダを取得する
- フォルダ内の全メールを取得する
- 個々のメールの情報を取得する
ここまでご説明した内容を試していただいた方は、ほとんど苦労なく実装できると思います!
1. メールフォルダを取得する
例えば受信トレイ内のメールを指定して、情報を取得する方法をご説明します。
import win32com.client
# APPの初期化
outlook = win32com.client.Dispatch("outlook.application")
namespace = outlook.GetNamespace("MAPI")
inbox = namespace.GetDefaultFolder(6) # 受信トレイ
namespace に対して GetDefaultFolder() を指定することでフォルダオブジェクトを丸ごと取得できます。受信トレイは 6 を指定してください。
なお、よく使うフォルダ名と番号の対応関係は以下になります。
フォルダ名 | 番号 |
---|---|
受信トレイ | 6 |
送信トレイ | 4 |
送信済みアイテム | 5 |
下書き | 16 |
迷惑メール | 23 |
2. フォルダ内の全メールを取得する
フォルダ内の全メールを取得するためには Items を使います。
import win32com.client
# APPの初期化
outlook = win32com.client.Dispatch("outlook.application")
namespace = outlook.GetNamespace("MAPI")
inbox = namespace.GetDefaultFolder(6) # 受信トレイ
# フォルダ内の全メールを取得
inbox_mails = inbox.Items
3. 個々のメールの情報を取得する
inbox.Items によって得られるのはリスト型のようなオブジェクトなので、ループで個々のメールオブジェクトにアクセスします。
※ 正確にはリスト型ではなくコレクションです
import win32com.client
# APPの初期化
outlook = win32com.client.Dispatch("outlook.application")
namespace = outlook.GetNamespace("MAPI")
inbox = namespace.GetDefaultFolder(6) # 受信トレイ
# フォルダ内の全メールを取得
inbox_mails = inbox.Items
for mail in inbox_mails:
print(mail.SenderEmailAddress)
print(mail.Sender)
print(mail.To)
print(mail.Cc)
print(mail.Bcc)
print(mail.Body)
print(mail.Attachments)
ここで、メールの情報がどのように呼び出せるかをまとめておきます。
項目名 | プロパティ名 |
---|---|
Subject | メールの件名 |
Body | メールの本文 |
HTMLBody | HTML 形式のメールの本文 |
Sender | メールの送信者 |
SenderEmailAddress | 送信者のメールアドレス |
To | 宛先のメールアドレス |
Cc | CCのメールアドレス |
Bcc | BCCのメールアドレス |
Attachments | 添付ファイルのコレクション |
ReceivedTime | 受信時刻 |
SentOn | 送信時刻 |
UnRead | 未読かどうかの真偽値 |
Importance | 重要度 |
ReplyRecipients | 返信先のアドレス |
Recipients | 受信者のコレクション |
DisplayCc | 表示用のCCアドレス |
DisplayTo | 表示用のToアドレス |
エラーハンドリング
win32comを使っているとCOMエラーが表示されることがあります。これはPython・Outlook間の通信で何らかの問題がある場合に発生します。
Outlookが適切にインストールされていない場合などたまに見かけるエラーなので、例外処理してエラーハンドリングしておきましょう。
簡単な例としてOutlookインスタンスの生成に失敗した場合の例外に対して、printするだけのサンプルコードを提示します。
import win32com.client
try:
outlook = win32com.client.Dispatch("Outlook.Application")
except win32com.client.pywintypes.com_error as e:
print("Outlookが見つかりませんでした。適切にインストールされているか確認してください。")
print(f"エラーの詳細:{e}")
実際にはloggingライブラリなどを用いてログ出力したりする必要はあります。
サンプルコードで全体像を掴む
最後にサンプルコードを掲載します。
断片的なコードでは見えないことも、一連の流れを眺めるだけで気づくことがあると思いますのでぜひ参考にしてみてください。
受信トレイ内のメールをCSVに出力する例
受信トレイ内のメールを取得し、情報をCSVに書き出すサンプルプログラムです。
import pandas as pd
import win32com.client
# OutlookAPPのインスタンス化
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
inbox_items = inbox.Items
inbox_mails = []
for mail in inbox_items:
inbox_mails.append(
{
"sender_address": mail.SenderEmailAddress,
"sender_name": mail.Sender,
"to_address": mail.To,
"cc_address": mail.Cc,
"bcc_address": mail.Bcc,
"body": mail.Body,
"attachments": mail.Attachments,
}
)
df_inbox = pd.DataFrame.from_dict(inbox_mails, dtype=object)
df_inbox.to_csv("output_inbox.csv", encoding="utf-8_sig")
最終的には読み込んだメールの内容をCSVとして書き出しています。
メールを作成して送信する例
メールを送信する方法は以下です。
import win32com.client
# OutlookAPPのインスタンス化
outlook = win32com.client.Dispatch("Outlook.Application")
# メールオブジェクトを作成
mail = outlook.CreateItem(0)
# メールオブジェクトのプロパティを設定
mail.to = "aaa@xxx.co.jp"
mail.cc = "aaa@xxx.co.jp"
mail.bcc = "aaa@xxx.co.jp"
mail.subject = "件名が入ります"
mail.bodyFormat = 1 # テキスト形式で作成
mail.body = "こんにちは。\nこれはテストメールです。"
mail.Send()
まとめ
Windows 環境であれば Outlook を使った自動化はかなり簡単に実装できるはずです。
もし Excel の操作もしてみたいという方は、以下の win32com を使った Excel 自動化の記事も目を通してみてください。
コメント