【Python】win32comを使ったOutlook操作のすべて

  • Windows でメール自動化をしたい
  • Python で Outlook を操作したい

Windows 環境なら Outlook を操作することで間接的にメールの操作ができます

とはいえ、Python から Outlook を直接触ることができないので、ここでは win32com というライブラリを使って操作していきます。

本記事の内容は以下のとおりです。

本記事の内容
  • 準備編
  • メールの作成と操作
  • メールから情報抽出

どの操作でも「準備編」の内容は必要になりますので、こちらは必ず目をお通しください。

win32com で Excel を自動化する方法も興味がある方はどうぞ。

Windows 環境のみ使える方法です。
他のOSをお使いの場合は別の方法をお試しください。

【準備編】 Outlook でメール作業を自動化する

まずは、Python で Outlook を操作する準備をしましょう。

準備の内容
  1. ライブラリのインストール
  2. Outlook アプリケーションの呼出
  3. メールフォルダの設定

① はコマンドライン上のお話なので、最初の一度だけ行います。

一方、② と ③ は Python コード内のお話になりますので、Outlook を使いたい場合に毎回コードを書くことになります。

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

まずはコマンドプロンプトで以下を実行してください。

Bash
pip install pywin32

これにより、Python 上から Outlook が操作できるモジュール win32com が使えるようになります。

なお、最近の開発では pip ではなく Poetry が使われることも増えてきました。
興味のある方はチャレンジしてみてください。

» パッケージ管理ツール “Poetry” の使いかた

ライブラリ名は win32com ではなく、pywin32 です。
間違いやすいのでご注意ください。

2. Outlook アプリケーションの呼出

Python から Outlook を呼び出すコードは次の通りです。

Python
import win32com.client

# OutlookAPP のインスタンス化
outlook = win32com.client.Dispatch("Outlook.Application")

4行目の outlook が「Outlook アプリケーションの実態」です。

この後の自動化コードはすべて、この Outlook アプリケーションに対して処理を加えていく流れになります。

3. メールフォルダの設定

「受信トレイ」や「下書きフォルダ」など、Outlook 内のフォルダに対して処理を行いたい場合があると思います。

その場合には、以下のような形でフォルダを定義します。

Python
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
フォルダごとの番号

そのほかにも様々なフォルダ番号が用意されていますので、公式ドキュメントの方も確認してみてください。

» Microsoft 公式ドキュメント: OlDefaultFolders 列挙 (Outlook)

【実践編 1】メールの作成と操作

これにて Python で Outlook を動かす準備が整いました。

続いて、次の内容を解説します。

  • メールを作成して下書きに保存する
  • メールを送信する
  • 装飾つきのメールを送信する

メールを作成して下書きに保存する

「メールを作成して、下書きに保存する」という基本的なコードをお伝えします。

Python
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) の部分です。

Python
# メールオブジェクトの作成
mail = outlook.CreateItem(0)

これにより、一通のまっさらなメールが変数 mail の中に生成されます。

もちろんこの段階では「宛先」「件名」「本文」「添付ファイル」などは設定されていません。

そこで、この mail オブジェクトにプロパティを付加していきます。

Python
# プロパティを設定
mail.To = "xxx@example.com"
mail.Subject = "件名"
mail.Body = "これはテストメールです。"
mail.Attachments.Add(r"C:\Users\username\somefile.csv")

ここまでくると mail オブジェクトには「宛先」「件名」「本文」「添付ファイル」が設定された状態になります。

最後に下書きフォルダに保存します。

Python
# 下書きフォルダに保存
mail.Save()
mail.Move(draft_folder)

mail オブジェクトはまだ実体がないので、先に mail.Save() として保存をします。

mail オブジェクトの実体が作られたところで、Move() メソッドにより下書きフォルダに移動しました。

メールを送信する

下書き保存ができるようになれば、送信は簡単です。

Python
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形式にします。

Python
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つです。

HTML 形式にするポイント
  1. mail.bodyFormat を 2 にする
  2. 本文の指定は HTMLBody を使う

特にHTMLBody を使うことは忘れてしまいがちなので、特に注意しましょう。

本文には HTML タグを使って記述すれば、色をつけたり見出しをつけたりなどリッチな表現ができます。

メールに画像を埋め込む方法

本来「メール」というものはテキストデータのみを送受信する想定で作られているため、本文に画像を埋め込みたい場合には一手間が必要になります。

結論として、画像データは base64 でバイナリ化して埋め込みます

Python
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> タグに画像を指定する際、バイナリデータを直接指定しています。

添付ファイルを付けて送信する

先ほどの装飾つきメールの例でも軽く登場していましたが、添付ファイルは Attachments.Add() にファイルパスを渡すだけで追加できます。

Python
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\report.xlsx")

# 送信
mail.Send()

複数ファイルを添付したい場合は、Attachments.Add() を繰り返し呼び出します。

Python
file_paths = [
    r"C:\Users\username\report.xlsx",
    r"C:\Users\username\summary.pdf",
]

for file_path in file_paths:
    mail.Attachments.Add(file_path)

メールを移動する

メールを移動する場合には、以下のように Move() メソッドを使います。

Python
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. メールフォルダを取得する
  2. フォルダ内の全メールを取得する
  3. 個々のメールの情報を取得する

ここまでご説明した内容を試していただいた方は、ほとんど苦労なく実装できると思います!

1. メールフォルダを取得する

例えば受信トレイ内のメールを指定して、情報を取得する方法をご説明します。

Python
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 を使います。

Python
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 によって得られるのはリスト型のようなオブジェクトなので、ループで個々のメールオブジェクトにアクセスします。
※ 正確にはリスト型ではなくコレクションです

Python
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メールの本文
HTMLBodyHTML 形式のメールの本文
Senderメールの送信者
SenderEmailAddress送信者のメールアドレス
To宛先のメールアドレス
CcCCのメールアドレス
BccBCCのメールアドレス
Attachments添付ファイルのコレクション
ReceivedTime受信時刻
SentOn送信時刻
UnRead未読かどうかの真偽値
Importance重要度
ReplyRecipients返信先のアドレス
Recipients受信者のコレクション
DisplayCc表示用のCCアドレス
DisplayTo表示用のToアドレス
主なプロパティ一覧

添付ファイルを保存する

上の表にある Attachments は添付ファイルのコレクションです。1件ずつ取り出して SaveAsFile() を呼べば、任意のフォルダに保存できます。

Python
import os
import win32com.client

# APPの初期化
outlook = win32com.client.Dispatch("outlook.application")
namespace = outlook.GetNamespace("MAPI")
inbox = namespace.GetDefaultFolder(6)  # 受信トレイ

save_dir = r"C:\Users\username\attachments"

for mail in inbox.Items:
    for attachment in mail.Attachments:
        save_path = os.path.join(save_dir, attachment.FileName)
        attachment.SaveAsFile(save_path)

attachment.FileName で元のファイル名が取得できるので、そのままの名前で保存できます。特定の拡張子だけ保存したい場合は、FileName を条件分岐でフィルタリングしてください。

エラーハンドリング

win32comを使っているとCOMエラーが表示されることがあります。これはPython・Outlook間の通信で何らかの問題がある場合に発生します。

Outlookが適切にインストールされていない場合などたまに見かけるエラーなので、例外処理してエラーハンドリングしておきましょう。

簡単な例としてOutlookインスタンスの生成に失敗した場合の例外に対して、printするだけのサンプルコードを提示します。

Python
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に書き出すサンプルプログラムです。

Python
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として書き出しています。

メールを作成して送信する例

メールを送信する方法は以下です。

Python
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()

より実践的なコードにするための補足

関数を用意してテンプレート化する

以下のような形でテンプレート化しておくと、コードの見通しが良くなります。

Python
from win32com.client import Dispatch, constants

def open_outlook():
    outlook = Dispatch("Outlook.Application")
    namespace = outlook.GetNamespace("MAPI")
    return outlook, namespace

def quit_outlook(outlook):
    # Outlook 自体を終了させたくない場合は、通常ここは呼ばない
    # outlook.Quit() するとアプリ自体が閉じる
    outlook.Quit()

まとめ

Windows 環境であれば Outlook を使った自動化はかなり簡単に実装できるはずです。

もし Excel の操作もしてみたいという方は、以下の win32com を使った Excel 自動化の記事も目を通してみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

普段は主にPython開発をしています。
最近はAI駆動開発にも関わっています。

コメント

コメントする