Outlook (new)でメールをExcelに出す【VBA非対応】

Outlook (new)のメールをPython(Microsoft Graph)でExcelに出力する方法のアイキャッチ

Outlook (new)に切り替わってから、いつものVBAでメールをExcelに出そうとしたらマクロがまったく動かなくなった、という方に向けた記事です

結論から言うと、Outlook (new)ではVBAやCOM操作が使えません、これはバグでも設定ミスでもなく、Microsoftがそういう作りにしたためです

とはいえメールをExcelに落とす手段がなくなったわけではないので、この記事ではMicrosoftが公式に代替として案内しているPython(Microsoft Graph)とPower Automateの2つを、設定の流れとコードつきで紹介していきます

この記事で分かること

  • Outlook (new)でVBAが動かない理由(公式見解)
  • 過去メールも全件取りたいなら Python + Microsoft Graph
  • ノーコードでやるなら Power Automate(新着メールの自動収集向き)
  • 2つの方法のどちらを選べばいいか
目次

なぜOutlook (new)でVBAが使えないのか

まず「なぜ動かないのか」をはっきりさせておきます、ここを理解しておくと、無駄に設定をいじって時間を溶かさずに済みます

Outlook (new)は、これまでのOutlook (classic)(デスクトップ版)とはまったく別の作りになっています、中身はWeb技術(WebView2)ベースで、ブラウザで動くOutlook on the webに近いものです

VBAでメールを取得するときは、Outlook.Application や GetNamespace(“MAPI”) といったCOMという仕組み(アプリ同士をつなぐWindowsの仕掛け)を経由してOutlookのデータにアクセスしていました

ところがOutlook (new)には、このCOMの窓口そのものが用意されていません、だから CreateObject(“Outlook.Application”) の時点で失敗してしまい、これまでのマクロが軒並み動かなくなるわけです

Microsoftは公式ドキュメントで「Outlook (new)ではVBAとマクロをサポートしない」とはっきり書いています(VBA, Macros, and Custom Flows Alternatives)

将来サポートされる予定も今のところアナウンスされていないので、Outlook (new)で使う前提なら、VBA以外の手段に乗り換えるのが現実的です

Outlook (classic)に戻せばVBAは今までどおり動く

ここで1つ逃げ道もお伝えしておきます

もし手元の環境でOutlook (classic)に戻せるなら、Outlookウィンドウ右上のトグルで切り替えるだけで、これまでのVBAマクロがそのまま使えます、Outlook (classic)は2026年時点でまだサポートが続く見込みです

「とりあえず今までのマクロをもう一度動かしたいだけ」という場合は、Outlook (classic)に戻すのが一番手っ取り早いです、VBAでメールをExcel化する具体的なコードはOutlookのメールデータをExcelに取得するマクロでまとめているので、そちらをどうぞ

会社の方針などでOutlook (classic)に戻せない、あるいは将来を見据えてVBA以外でやっておきたい、という方はこの先の2つの方法に進んでください

方法1 Pythonで取得する(Microsoft Graph API)

1つめはPython + Microsoft Graph APIです、Microsoftが用意しているメール取得用のAPI(外部からデータを取りに行く窓口)をPythonから叩いて、メールをまとめてExcelに書き出します

こちらは設定にひと手間かかりますが、過去メールも含めて全件取得できるのが強みです、日付や件名でフィルタしたり、取得項目を自由に選べたりと、細かい制御が効きます

ステップ1 必要なライブラリを入れる

使うライブラリは3つです、認証用のmsal、API通信用のrequests、Excel書き出し用のopenpyxlを入れます

pip install msal requests openpyxl

ステップ2 Azure AD(Microsoft Entra ID)にアプリを登録する

Graph APIを使うには、自分のアプリをMicrosoft側に登録してCLIENT_ID(アプリの身分証のようなもの)をもらう必要があります、ここが今回いちばんの山場なので、画面ごとに区切って進めていきます

作業するのはMicrosoft Entra管理センター(entra.microsoft.com)です、以前はAzureポータル(portal.azure.com)の「Azure Active Directory」と呼ばれていた場所で、今はMicrosoft Entra IDに名前が変わっています、どちらから入っても同じ設定にたどり着けます

STEP
アプリの登録から「新規登録」を開く

Entra管理センターにサインインして、「Entra ID」→「アプリの登録」→「新規登録」と進みます

STEP
名前とアカウントの種類を選んで登録する

新規登録の画面には、上から「名前」「サポートされているアカウントの種類」「リダイレクトURI(任意)」の順で入力欄が並んでいます

  • 名前:あとから変えられるので、自分が分かる名前でかまいません(例 outlook-mail-export)
  • サポートされているアカウントの種類:迷ったら「任意のEntra IDテナント + 個人用Microsoftアカウント」を選ぶと、個人のOutlook.com(Hotmail/Live)でも会社のMicrosoft 365でも同じ手順で動きます、選んだ種類でコードのTENANT_IDが変わるので、下のメモもあわせて見てください
  • リダイレクトURI(任意):ここは空のままでOKです、次のステップの「認証」で設定します

入力できたら「登録」をクリックします

STEP
クライアントIDとテナントIDを控える

登録が終わると「概要」画面が開きます、ここに表示されるアプリケーション(クライアント)IDをコピーしておきます、これがコードのCLIENT_IDです

同じ画面のディレクトリ(テナント)IDも控えておきます、こちらは「シングルテナントのみ」を選んだ場合だけコードのTENANT_IDに入れます(commonや個人用を使うなら不要です)

STEP
リダイレクトURIを設定する

左メニューの「認証」(画面によっては「Authentication (Preview)」と表示されます)を開き、「リダイレクトURI構成」タブの「リダイレクトURIの追加」から「モバイルアプリケーションとデスクトップアプリケーション」のタイルを選びます

リダイレクトURIにhttp://localhostを指定して「構成」で保存します(推奨候補に出ていなければカスタムとして入力します)、これを入れておかないと、ログイン画面が返ってこずにエラーになります

STEP
APIのアクセス許可でMail.Readを追加する

左メニューの「APIのアクセス許可」→「アクセス許可の追加」→「Microsoft Graph」→「委任されたアクセス許可」と進み、Mail.Readを探して追加します

これで自分のメールを読む権限がアプリに付きます

今回は自分のログインでアクセスする委任(デリゲート)の方式なので、アプリのシークレット(パスワード的なもの)は不要です

はじめてログインするときに、Mail.Readの利用に同意するか聞かれることがあります、自分のアカウントに対する読み取りなので同意して進めて問題ないです

ステップ2で選んだ「サポートされているアカウントの種類」に合わせて、コードのTENANT_IDに入れる値を変えます、ここがズレると「Please use the /consumers endpoint」のような認証エラーになります

  • 任意のEntra IDテナント + 個人用(個人でも会社でも動く、迷ったらこれ):common
  • シングルテナントのみ(会社・学校のMicrosoft 365に限定):控えたディレクトリ(テナント)ID
  • 個人用アカウントのみ(Outlook.com専用):consumers

画面にある「複数のEntra IDテナント」は、複数の会社にまたがって使うSaaSアプリ向けなので、今回のメール取得では選びません

ステップ3 認証してメールを取得する

準備ができたらコードに進みます、まずは認証してアクセストークン(API利用の通行証)をもらう部分です

import msal

CLIENT_ID = "ここにアプリケーション(クライアント)ID"
TENANT_ID = "common"  # 個人でも会社でも動く、会社のアカウント専用なら控えたテナントID、個人専用なら consumers
SCOPES = ["https://graph.microsoft.com/Mail.Read"]

# パブリッククライアント(デスクトップアプリ)として認証する
app = msal.PublicClientApplication(
    CLIENT_ID,
    authority=f"https://login.microsoftonline.com/{TENANT_ID}",
)

# ブラウザが立ち上がってMicrosoftのログイン画面が出る
result = app.acquire_token_interactive(scopes=SCOPES)
token = result["access_token"]

このコードを実行するとブラウザが立ち上がり、いつものMicrosoftのログイン画面が出ます、ログインが終わるとトークンが手に入ります

続いてGraph APIを叩いてメール一覧を取ります、ポイントはページング処理です

Graph APIは一度に全件は返してくれず、続きがある場合は応答の中に@odata.nextLinkという「次のページのURL」が入ってきます、これが無くなるまでループで取りに行きます

import requests

# Prefer ヘッダーで本文をHTMLでなくプレーンテキストで受け取る
headers = {
    "Authorization": f"Bearer {token}",
    "Prefer": 'outlook.body-content-type="text"',
}

# $top で1ページの件数、$select で欲しい項目だけに絞る
url = ("https://graph.microsoft.com/v1.0/me/messages"
       "?$top=50"
       "&$select=subject,from,toRecipients,ccRecipients,receivedDateTime,isRead,hasAttachments,body")

all_messages = []
while url:
    resp = requests.get(url, headers=headers).json()
    all_messages.extend(resp.get("value", []))
    # 次のページがあれば nextLink が入る、無ければループ終了
    url = resp.get("@odata.nextLink")

print(f"{len(all_messages)} 件取得しました")

$selectで欲しい項目だけに絞ると、通信量が減って取得も速くなります、今回は件名・差出人・宛先・CC・受信日時・既読フラグ・添付の有無・本文を取っています、ほかにどんな項目が取れるかはmessageリソースの公式リファレンスに一覧があります

ステップ4 Excelに書き出す

最後にopenpyxlでExcelに書き出します、差出人・宛先・CCはどれも入れ子の構造で、メールによってはaddressが無くnameだけのこともあるので、取り出す部分をaddr_ofaddr_listという小さな関数にまとめておくと扱いやすいです

import openpyxl

# 差出人・宛先・CCを取り出すヘルパー(address が無ければ name を使う)
def addr_of(person):
    ea = (person or {}).get("emailAddress", {})
    return ea.get("address") or ea.get("name", "")

def addr_list(people):
    # toRecipients や ccRecipients は複数なので ; でつなぐ
    return "; ".join(addr_of(p) for p in (people or []))

wb = openpyxl.Workbook()
ws = wb.active
ws.append(["件名", "差出人", "宛先", "CC", "受信日時", "既読", "添付", "本文(先頭500字)"])

for msg in all_messages:
    ws.append([
        msg.get("subject", ""),
        addr_of(msg.get("from")),
        addr_list(msg.get("toRecipients")),
        addr_list(msg.get("ccRecipients")),
        msg.get("receivedDateTime", ""),
        "既読" if msg.get("isRead") else "未読",
        "あり" if msg.get("hasAttachments") else "",
        msg.get("body", {}).get("content", "")[:500],
    ])

wb.save("outlook_mail.xlsx")
print("outlook_mail.xlsx に保存しました")

本文は長くなりがちなので、ここでは先頭500字だけ取り出しています、全文が欲しい場合は[:500]を外してください

ここまでをひとつのファイルにまとめたものを置いておきます、CLIENT_IDとTENANT_IDを自分の値に書き換えれば、そのまま動かせるはずです

コード全文(コピペ用)
import msal
import requests
import openpyxl

CLIENT_ID = "ここにアプリケーション(クライアント)ID"
TENANT_ID = "common"  # 個人でも会社でも動く、会社のアカウント専用なら控えたテナントID、個人専用なら consumers
SCOPES = ["https://graph.microsoft.com/Mail.Read"]

# --- 認証(ブラウザでMicrosoftにログインする) ---
app = msal.PublicClientApplication(
    CLIENT_ID,
    authority=f"https://login.microsoftonline.com/{TENANT_ID}",
)
result = app.acquire_token_interactive(scopes=SCOPES)
token = result["access_token"]

# --- メール一覧を取得する ---
headers = {
    "Authorization": f"Bearer {token}",
    "Prefer": 'outlook.body-content-type="text"',
}
url = ("https://graph.microsoft.com/v1.0/me/messages"
       "?$top=50"
       "&$select=subject,from,toRecipients,ccRecipients,receivedDateTime,isRead,hasAttachments,body")

all_messages = []
while url:
    resp = requests.get(url, headers=headers).json()
    all_messages.extend(resp.get("value", []))
    url = resp.get("@odata.nextLink")

print(f"{len(all_messages)} 件取得しました")

# --- Excelに書き出す ---
def addr_of(person):
    ea = (person or {}).get("emailAddress", {})
    return ea.get("address") or ea.get("name", "")

def addr_list(people):
    return "; ".join(addr_of(p) for p in (people or []))

wb = openpyxl.Workbook()
ws = wb.active
ws.append(["件名", "差出人", "宛先", "CC", "受信日時", "既読", "添付", "本文(先頭500字)"])

for msg in all_messages:
    ws.append([
        msg.get("subject", ""),
        addr_of(msg.get("from")),
        addr_list(msg.get("toRecipients")),
        addr_list(msg.get("ccRecipients")),
        msg.get("receivedDateTime", ""),
        "既読" if msg.get("isRead") else "未読",
        "あり" if msg.get("hasAttachments") else "",
        msg.get("body", {}).get("content", "")[:500],
    ])

wb.save("outlook_mail.xlsx")
print("outlook_mail.xlsx に保存しました")

受信トレイだけ・期間で絞りたいとき

上のコードはメール全体を取りますが、対象を絞りたいこともあると思います、URLのところを少し変えるだけで対応できます

受信トレイだけに絞るならme/mailFolders/inbox/messagesにします、受信日時で絞るなら$filterを足します、たとえば2026年1月以降だけなら次のような形です

# 受信トレイの、2026年1月以降のメールに絞る例
url = ("https://graph.microsoft.com/v1.0/me/mailFolders/inbox/messages"
       "?$top=50"
       "&$select=subject,from,toRecipients,ccRecipients,receivedDateTime,isRead,hasAttachments,body"
       "&$filter=receivedDateTime ge 2026-01-01T00:00:00Z")

このあたりを自由にいじれるのが、Pythonで取る方法のいちばんの魅力かなと思います、$filterや$orderbyで指定できる条件はList messagesのリファレンスにまとまっています

方法2 Power Automateで新着メールをExcelに追記する

2つめはノーコードでできるPower Automateです、プログラムを書かずに「メールが届いたらExcelに1行追記する」という流れ(フロー)を組めます

Microsoft 365のアカウントがあれば、無料の枠でも基本的な自動フローは作れます、コードを書きたくない方はこちらの方が手軽です

先に大事な制約を1つ、Power Automateは「これから届くメール」を自動で拾う仕組みです

すでに受信トレイに溜まっている過去メールを一括でExcel化する用途には向きません、過去分もまとめて欲しいなら、方法1で紹介したPython(Microsoft Graph)の方が適しています

事前準備 OneDriveにExcelを置いてテーブル化しておく

フローを作る前に、書き込み先のExcelを用意します、ここを先にやっておかないと後の設定でつまずきます

  • OneDrive(またはSharePoint)にExcelファイルを置く ※ローカルPCのExcelは連携できません
  • 1行目に「件名」「差出人」「受信日時」などの見出しを入れる
  • 見出しを含めて範囲を選び、Excelの「挿入」→「テーブル」でテーブルに変換しておく

Power Automateの「行の追加」アクションはテーブルにしか書き込めないので、ただ見出しを打っただけのシートだと選択肢に出てきません、ここはハマりやすいポイントです

フローを作る手順

準備ができたら、Power Automate(make.powerautomate.com)でフローを組みます、流れはとてもシンプルです

STEP
自動化したクラウドフローを新規作成

「作成」から「自動化したクラウドフロー」を選びます、トリガー(きっかけ)になるイベントを後で指定する形式です

STEP
トリガーに「新しいメールが届いたとき」を選ぶ

Office 365 Outlookの「新しいメールが届いたとき (V3)」を選びます、特定の差出人や件名だけに絞りたい場合は、ここのオプションで条件を指定できます

STEP
アクションに「表に行を追加」を選ぶ

次のステップでExcel Online (OneDrive) の「表に行を追加」を選び、さきほど用意したファイル・テーブルを指定します

STEP
各列にメールの値を割り当てる

「件名」列にはトリガーの件名、「差出人」列には差出人、というように動的なコンテンツをはめ込んでいきます、これで保存すれば完成です

あとはメールが届くたびに、自動でExcelの最終行に1件ずつ積み上がっていきます、手作業のコピペから解放されるのは地味にうれしいポイントです

本文も列に入れたい場合は本文プレビューを割り当てると扱いやすいです、本文全文はHTMLタグが混ざることがあるので、用途に合わせて選んでください

どちらを選ぶか(比較)

2つの方法を表にまとめておきます、ざっくり言うと過去メールも全部欲しいならPython、これからのメールを自動で貯めたいならPower Automateです

スクロールできます
項目Python(Graph)Power Automate
必要なスキルPythonの基礎ノーコード(画面操作だけ)
事前準備Azure ADのアプリ登録OneDriveにExcel+テーブル化
新着メールの自動収集△ 定期実行の仕組みが別途必要○ 得意
過去メールの一括取得○ 全件取得できる× できない
日付・件名での絞り込み○ 自由に指定できる△ 簡単な条件のみ
費用無料(自分のアカウント範囲)無料プランあり

「溜まった問い合わせメールを一気にExcelで分析したい」のような一括処理ならPython、「届いたメールを台帳に自動で記録していきたい」のような運用ならPower Automate、という住み分けがしっくりくると思います

もちろん両方を組み合わせてもいいです、過去分はPythonで一気に吸い出して、これから先はPower Automateで貯めていく、という使い方も現実的です

まとめ

Outlook (new)でメールをExcel化する方法を整理しました、最後にもう一度ポイントをまとめておきます

  • Outlook (new)はVBA・COM非対応(Microsoft公式が明言、将来サポート予定もなし)
  • 今までのマクロを動かしたいだけなら、Outlook (classic)に戻すのが最短
  • 過去メールも全件・条件指定で取りたいなら Python + Microsoft Graph
  • 新着メールを自動で貯めたいなら Power Automate(ノーコード)

VBAが使えなくなったと聞くと身構えてしまいますが、代わりの道はちゃんと用意されています、自分の目的に合う方を選んでもらえればと思います

Outlook (classic)でVBAを使う具体的なコードはOutlookのメールデータをExcelに取得するマクロでまとめています、戻せる環境の方はこちらもあわせてどうぞ

📚 Python自動化の独学に効く本PR
退屈なことはPythonにやらせよう 第3版

退屈なことはPythonにやらせよう 第3版

Al Sweigart

Pythonクローリング&スクレイピング 増補改訂版

Pythonクローリング&スクレイピング 増補改訂版

加藤耕太

シゴトがはかどる Python自動処理の教科書

シゴトがはかどる Python自動処理の教科書

クジラ飛行机

私のおすすめからランダムで3冊を表示しています


最後に・・・

クラウドワークスココナラでお仕事受け付けています!

PythonとExcelを中心に仕事に役立つ業務ツールや自動化、スクレイピングツールの作成を受注していて、クラウドワークスでは気が付けば100件以上のお仕事を受注してきました!

会社員をやりながらの副業なので時間の捻出は相応ですが、クライアントの方々と近い立場でこちらからも提案しながら活動していますのでお悩みあれば是非ご相談ください

ココナラのプロフィールページへ

"ココナラ"に新規登録する際は1,000Pもらえる紹介コード使ってください

78E62K

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

この記事を書いた人

VBAとPythonを中心にユーザー側でできるITを自己学習しているので備忘録半分、学習履歴を残して同じ道を辿る人の参考になればとブログを始めました

副業でスクレイピングツール作成を中心にできることを色々やっていますのでご相談いただけるとありがたいです!


クラウドワークスのページへ


ココナラのページへ

コメント

コメントする

目次