\ お問い合わせはこちら /

Python で Outlook を自動操作する【win32com 超実践ガイド】

Windows 環境+Outlook が入っている方向けの記事です。

win32com を使えば、メール送受信・仕分け・添付ファイル保存・予定の作成・タスク管理など、かなりの範囲を Python から自動化できます。

本記事ではその方法をご紹介します。

目次
  1. 1. 事前準備(環境・基本構造)
  2. 2. Outlook.Application と MAPI 名前空間
  3. 3. フォルダ操作(Inbox / サブフォルダなど)
  4. 4. メール送信(MailItem)
  5. 5. 添付ファイルの追加・受信側の保存
  6. 6. 受信メールの取得・検索・フィルタ
  7. 7. メールの状態変更・移動・削除
  8. 8. メール本文の取得・解析
  9. 9. 予定表(AppointmentItem)の操作
  10. 10. 連絡先(ContactItem)の操作
  11. 11. タスク(TaskItem)の操作
  12. 12. ルールに近いことを Python で代用する
  13. 13. エラーハンドリングと注意点
  14. まとめ:Outlook も win32com でガッツリ自動化できる

1. 事前準備(環境・基本構造)

Python から Outlook を操作する準備

Outlook 用でも Excel と同じく pywin32 を使います。

Bash
pip install pywin32

基本の雛形はこんなイメージです。

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

Outlook は普段から起動したまま使うことが多いので、Quit() はあえて呼ばずに、Python スクリプト側だけ終了させるパターンも多いです。

2. Outlook.Application と MAPI 名前空間

Outlook.Application を取得する

通常はこれで OK です。Outlook が起動していなければ起動されます。

Python
from win32com.client import Dispatch

outlook = Dispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")

既存インスタンスに接続する(GetObject)

すでに起動している Outlook にぶら下がりたい場合。

Python
from win32com.client import GetObject

outlook = GetObject(Class="Outlook.Application")
namespace = outlook.GetNamespace("MAPI")

プロファイルを指定してログオンする

Exchange や複数プロファイルを使っている場合は Logon を明示することがあります。

Python
namespace.Logon(
    Profile="Outlook",     # プロファイル名(Outlook 側の設定)
    ShowDialog=False,
    NewSession=False,
)

既定のストア(メールボックス)を取得する

Python
store = namespace.DefaultStore
print(store.DisplayName)  # 「あなたの名前」など
root_folder = store.GetRootFolder()

3. フォルダ操作(Inbox / サブフォルダなど)

既定のフォルダ(受信トレイ・送信済みなど)を取得する

GetDefaultFolder に定数を渡します。

Python
from win32com.client import constants

inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
sent = namespace.GetDefaultFolder(constants.olFolderSentMail)
drafts = namespace.GetDefaultFolder(constants.olFolderDrafts)
calendar = namespace.GetDefaultFolder(constants.olFolderCalendar)
contacts = namespace.GetDefaultFolder(constants.olFolderContacts)
tasks = namespace.GetDefaultFolder(constants.olFolderTasks)

サブフォルダを取得する

Python
# 受信トレイ配下の「請求書」フォルダ
invoice_folder = inbox.Folders("請求書")

フォルダを列挙する

Python
def print_folders(folder, level=0):
    indent = "  " * level
    print(indent + folder.Name)
    for sub in folder.Folders:
        print_folders(sub, level + 1)

root = namespace.DefaultStore.GetRootFolder()
print_folders(root)

サブフォルダを作成・削除する

Python
# 受信トレイ配下に「スクリプト用」フォルダを作成
new_folder = inbox.Folders.Add("スクリプト用")

# 削除
new_folder.Delete()

4. メール送信(MailItem)

シンプルなテキストメールを送る

Python
outlook, namespace = open_outlook()

mail = outlook.CreateItem(constants.olMailItem)
mail.To = "example@example.com"
mail.Subject = "テストメール"
mail.Body = "Python + win32com からのテストメールです。"
mail.Send()

宛先・CC・BCC を指定する

Python
mail = outlook.CreateItem(constants.olMailItem)
mail.To = "to1@example.com; to2@example.com"
mail.CC = "cc1@example.com"
mail.BCC = "bcc1@example.com"
mail.Subject = "CC/BCC テスト"
mail.Body = "CC と BCC を使ったサンプルです。"
mail.Send()

HTML メール(HTMLBody)を送る

Python
html = """
<html>
  <body>
    <h1>Python からの HTML メール</h1>
    <p>これは <b>太字</b> のサンプルです。</p>
  </body>
</html>
"""

mail = outlook.CreateItem(constants.olMailItem)
mail.To = "example@example.com"
mail.Subject = "HTML メールのテスト"
mail.HTMLBody = html
mail.Send()

既定の署名を使いたい場合の簡易テクニック

Outlook の既定署名をそのまま利用するには、一度 Display() してから HTMLBody を加工する方法がよく使われます。

Python
mail = outlook.CreateItem(constants.olMailItem)
mail.To = "example@example.com"
mail.Subject = "署名付きメール"

# 署名付きの空メールを表示させる
mail.Display()

# 既に署名が入った HTMLBody の先頭に本文を追加
body = "<p>本文です。署名の前に追加されます。</p>"
mail.HTMLBody = body + mail.HTMLBody

# そのまま人間が送信ボタンを押しても良いし、自動送信も可
# mail.Send()

5. 添付ファイルの追加・受信側の保存

メール送信時に添付ファイルを追加する

Python
mail = outlook.CreateItem(constants.olMailItem)
mail.To = "example@example.com"
mail.Subject = "添付ファイルのテスト"
mail.Body = "ファイルを添付しています。"

file_path = r"C:\path\to\report.xlsx"
mail.Attachments.Add(Source=file_path)

mail.Send()

受信メールの添付ファイルを保存する

Python
import os

inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
messages = inbox.Items

save_dir = r"C:\path\to\download_attachments"

for msg in messages:
    # 添付がない場合もあるのでチェック
    if msg.Attachments.Count > 0:
        for i in range(1, msg.Attachments.Count + 1):
            attachment = msg.Attachments(i)
            filename = attachment.FileName
            save_path = os.path.join(save_dir, filename)
            attachment.SaveAsFile(save_path)
            print("Saved:", save_path)

6. 受信メールの取得・検索・フィルタ

受信トレイの最新メールを取得する

Python
inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
items = inbox.Items
items.Sort("[ReceivedTime]", True)  # True で降順(新しい順)

latest = items.GetFirst()
print(latest.Subject, latest.ReceivedTime)

条件付きでメールを取得(Restrict を使う)

Restrict は Outlook 側のフィルタ機能で、高速に抽出できます。

Python
from datetime import datetime, timedelta

inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
items = inbox.Items

# 直近 1 日以内のメール
yesterday = datetime.now() - timedelta(days=1)
criteria = "[ReceivedTime] >= '" + yesterday.strftime("%m/%d/%Y %H:%M %p") + "'"
filtered = items.Restrict(criteria)

for msg in filtered:
    print(msg.Subject, msg.ReceivedTime)

※ 日付フォーマットは Outlook 依存があるので、うまく動かない場合はローカル設定に合わせて調整が必要なことがあります。

件名や送信者でフィルタする(単純な例)

Python
inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
items = inbox.Items

# 件名に「請求書」を含むメールのみ
matched = [m for m in items if "請求書" in (m.Subject or "")]
for msg in matched:
    print(msg.Subject, msg.SenderName)

(これは Python 側でフィルタしている例なので件数が多いと遅いです。できれば RestrictFind を使うほうが高速です。)

Find / FindNext を使った検索

Python
items = inbox.Items
item = items.Find("[Subject] = '特別なお知らせ'")

while item is not None:
    print("Found:", item.Subject, item.ReceivedTime)
    item = items.FindNext()

7. メールの状態変更・移動・削除

既読/未読を切り替える

Python
inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
items = inbox.Items

for msg in items:
    if not msg.UnRead:
        continue
    # 未読メールだけ既読にする
    msg.UnRead = False
    msg.Save()

フォルダにメールを移動する

Python
inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
target_folder = inbox.Folders("スクリプト用")

items = inbox.Items
for msg in list(items):  # 途中でコレクションが変わるので list() でコピー
    if "請求書" in (msg.Subject or ""):
        moved = msg.Move(target_folder)
        print("Moved:", moved.Subject)

メールを削除する

Python
inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
items = inbox.Items

for msg in list(items):
    if "[自動削除]" in (msg.Subject or ""):
        msg.Delete()

カテゴリを設定する

Outlook の「カテゴリ」機能に色ラベルが付いている場合。

Python
msg.Categories = "Python処理"  # Outlook 側に存在するカテゴリ名
msg.Save()

フラグを設定する(フォローアップ)

Python
msg.FlagRequest = "フォローアップ"
msg.FlagStatus = constants.olFlagMarked
msg.Save()

8. メール本文の取得・解析

テキスト本文(Body)を取得する

Python
msg = inbox.Items.GetFirst()
print(msg.Subject)
print(msg.Body)

HTML 本文(HTMLBody)を取得する

Python
html = msg.HTMLBody
print(html)

正規表現で金額・日付を抽出する簡単な例

Python
import re

body = msg.Body or ""

amount_match = re.search(r"(\d{1,3}(?:,\d{3})*)(|JPY)", body)
if amount_match:
    amount = amount_match.group(1)
    print("検出金額:", amount)

9. 予定表(AppointmentItem)の操作

予定を新規作成する

Python
from datetime import datetime, timedelta

outlook, namespace = open_outlook()
calendar = namespace.GetDefaultFolder(constants.olFolderCalendar)

appt = outlook.CreateItem(constants.olAppointmentItem)
appt.Subject = "Python で作成した予定"
appt.Location = "会議室 A"

start = datetime(2025, 11, 20, 10, 0)
end = start + timedelta(hours=1)

appt.Start = start
appt.End = end
appt.Body = "これは Python スクリプトから作成された会議です。"
appt.ReminderMinutesBeforeStart = 15
appt.BusyStatus = constants.olBusy

appt.Save()           # 予定表に保存
# appt.Display()      # 画面で確認したいとき

参加者を招待する(会議として送信)

Python
meeting = outlook.CreateItem(constants.olAppointmentItem)
meeting.MeetingStatus = constants.olMeeting

meeting.Subject = "Python 勉強会"
meeting.Location = "オンライン"
meeting.Start = datetime(2025, 11, 21, 19, 0)
meeting.Duration = 90  # 分

recipient = meeting.Recipients.Add("guest@example.com")
recipient.Type = 1  # 必須参加(olRequired)

meeting.Body = "Python + Outlook 自動化の勉強会です。"

meeting.Send()  # 招待メールを送る

予定表から予定を取得・検索する

Python
calendar = namespace.GetDefaultFolder(constants.olFolderCalendar)
items = calendar.Items
items.Sort("[Start]")
items.IncludeRecurrences = True

start = datetime(2025, 11, 1)
end = datetime(2025, 11, 30)

restriction = f"[Start] >= '{start:%m/%d/%Y %H:%M %p}' AND [End] <= '{end:%m/%d/%Y %H:%M %p}'"
filtered = items.Restrict(restriction)

for appt in filtered:
    print(appt.Subject, appt.Start, appt.End)

10. 連絡先(ContactItem)の操作

新しい連絡先を作成する

Python
contacts_folder = namespace.GetDefaultFolder(constants.olFolderContacts)

contact = outlook.CreateItem(constants.olContactItem)
contact.FullName = "山田 太郎"
contact.Email1Address = "taro.yamada@example.com"
contact.CompanyName = "ヤマダ株式会社"
contact.MobileTelephoneNumber = "090-1234-5678"
contact.JobTitle = "営業"
contact.Save()

連絡先を列挙する

Python
for item in contacts_folder.Items:
    print(item.FullName, item.Email1Address)

11. タスク(TaskItem)の操作

タスクを新規作成する

Python
tasks_folder = namespace.GetDefaultFolder(constants.olFolderTasks)

task = outlook.CreateItem(constants.olTaskItem)
task.Subject = "レポート提出"
task.Body = "金曜日までに営業レポートをまとめる"
task.DueDate = datetime(2025, 11, 22)
task.Importance = constants.olImportanceHigh
task.Save()

タスクを一覧取得する

Python
for t in tasks_folder.Items:
    print(t.Subject, t.DueDate, t.Status)

タスクを完了にする

Python
for t in tasks_folder.Items:
    if t.Subject == "レポート提出":
        t.MarkComplete()
        t.Save()

12. ルールに近いことを Python で代用する

Outlook の「受信トレイルール」を直接いじるのは複雑なので、

  • Python スクリプトを定期実行(タスクスケジューラなど)
  • 条件に合うメールを検索してフォルダに移動する

という形で「自作ルール」を実装するのが現実的です。

件名に「請求書」を含むメールを自動で移動

Python
from datetime import datetime, timedelta

outlook, namespace = open_outlook()
inbox = namespace.GetDefaultFolder(constants.olFolderInbox)
target_folder = inbox.Folders("請求書")

items = inbox.Items
items.Sort("[ReceivedTime]", True)

# 直近 3 日分だけチェックしてフォルダに移動
limit = datetime.now() - timedelta(days=3)
criteria = "[ReceivedTime] >= '" + limit.strftime("%m/%d/%Y %H:%M %p") + "'"
recent = items.Restrict(criteria)

for msg in list(recent):
    if "請求書" in (msg.Subject or ""):
        msg.Move(target_folder)

13. エラーハンドリングと注意点

try / finally で安全に扱う

Python
from win32com.client import Dispatch, constants

outlook = None
try:
    outlook = Dispatch("Outlook.Application")
    namespace = outlook.GetNamespace("MAPI")
    inbox = namespace.GetDefaultFolder(constants.olFolderInbox)

    # ここに処理を書く
    msg = inbox.Items.GetFirst()
    print(msg.Subject)

except Exception as e:
    print("エラー:", e)

finally:
    # Outlook を閉じたくない場合は何もしない
    # outlook.Quit() するとアプリ自体が終了する
    pass

セキュリティ警告について

一部環境では、プログラムからのメール送信や連絡先アクセス時に Outlook のセキュリティ警告 が出ることがあります(ウイルス対策ソフトの設定や Outlook のバージョンに依存)。

  • セキュリティ設定で「自動承認」を許可する
  • 会社環境では情報システム部門のポリシーに従う

などの対応が必要になる場合があります。

まとめ:Outlook も win32com でガッツリ自動化できる

ここまでで、

  • Outlook.ApplicationMAPI 名前空間の基本
  • メールの送信(テキスト・HTML・添付)
  • 受信メールの取得・検索・既読/移動/削除・カテゴリ/フラグ
  • 添付ファイルの一括保存
  • 予定表(AppointmentItem)・会議招待
  • 連絡先(ContactItem)・タスク(TaskItem)
  • 疑似ルールによる自動仕分け

といった、実務で使いそうな操作を一通り押さえました。

実務的には、

  1. フォルダをきちんと分ける
  2. 定型処理(請求書の仕分け、添付の保存、定例会議の作成など)をスクリプト化
  3. Windows タスクスケジューラなどで定期実行する

という流れにすると、「Outlook の定期ルーチンを全部 Python に任せる」ことができます。

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

この記事を書いた人

普段はエンジニアとして働きつつ、旅行では「住むように旅する」をテーマに動き回っています。

TABIGRAMMER では、
・旅の情報(台湾を中心としたアジア旅ガイド)
・ミニマリストの持ち物や旅の効率化テクニック
・ブログ運営やプログラミング記事

といった、旅とITが交差するコンテンツを発信しています。

難しいことをわかりやすく、旅をより快適に。そんなスタイルで記事を書いています。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)