【bat】バッチファイルでエラー通知メールを自動送信する完全ガイド|PowerShell・ERRORLEVEL判定・ログ監視・Slack通知・Blat・実践パターンまで

【bat】バッチファイルでエラー通知メールを自動送信する完全ガイド|PowerShell・ERRORLEVEL判定・ログ監視・Slack通知・Blat・実践パターンまで bat

バックアップや定期処理のバッチが夜中に失敗しても、翌朝まで気づかない——そんな状況を防ぐにはエラー発生時だけ自動でメール通知を送る仕組みが必要です。

Windowsには標準で PowerShell があり、外部ツールなしでSMTPメールを送信できます。さらに Slack Webhook を使えばチャット通知も可能です。本記事では ERRORLEVEL 判定・ログ監視・通知内容のリッチ化まで実践コードで解説します。

この記事でわかること

  • ERRORLEVEL でエラーを検知して通知を送る基本パターン
  • PowerShell の Send-MailMessage でバッチからメールを送信する方法
  • SSL/TLS(Gmail・Office365)に対応した Net.Mail.SmtpClient の使い方
  • ログファイルの ERROR/WARN 文字列を検知して通知する方法
  • curl で Slack Webhook 通知を送信する方法(外部ツール不要)
  • 外部ツール Blat でシンプルにメール送信する方法
  • PC名・エラーログ本文・タイムスタンプを含むリッチな通知の作り方
  • エラー通知付きバックアップバッチの実践構成
スポンサーリンク

通知方式の比較

方式 外部ツール SSL/TLS 添付ファイル 実装難度
PowerShell Send-MailMessage 不要 △(-UseSsl) ✅ -Attachments
PowerShell Net.Mail.SmtpClient 不要 ✅(完全対応)
curl + Slack Webhook curl(Win10以降標準)
Blat(外部ツール) 要インストール ✅(-ssl) ✅ -attach
方式の使い分け
最も手軽なのは PowerShell Send-MailMessage(外部ツール不要・コードが短い)です。Gmail や Office365 など現代的なSMTPサーバーは TLS 必須のため、接続に問題が出る場合は Net.Mail.SmtpClient に切り替えてください。メール送信が難しい環境では curl + Slack Webhook が最もシンプルです。

ERRORLEVEL でエラーを検知して通知を送る基本パターン

バッチの処理がエラー終了(終了コード≠0)したときだけ通知を送る最もシンプルな構成です。通知処理をサブルーチン化しておくと複数の処理に適用しやすくなります。

errorlevel_notify.bat: コマンド失敗時だけ通知を呼び出す基本構成
@echo off
setlocal

set "LOGFILE=C:\logs\batch.log"
set "NOTIFY_TO=admin@example.com"
if not exist "C:\logs" mkdir "C:\logs"

echo [%DATE% %TIME%] 処理開始 >> "%LOGFILE%"

REM --- 処理本体 ---
xcopy "C:\data" "D:\backup\" /s /e /y >> "%LOGFILE%" 2>&1
set RC=%ERRORLEVEL%

if %RC% equ 0 (
    echo [%DATE% %TIME%] 処理成功 >> "%LOGFILE%"
) else (
    echo [%DATE% %TIME%] 処理失敗: ERRORLEVEL=%RC% >> "%LOGFILE%"
    call :SEND_NOTIFY "バックアップ失敗" "ERRORLEVEL=%RC% 詳細: %LOGFILE%"
)

exit /b %RC%

:SEND_NOTIFY
REM %1=件名  %2=本文
set "SUBJECT=%~1"
set "BODY=%~2"
set "HOST=%COMPUTERNAME%"
powershell -NoProfile -Command "
    Send-MailMessage ^
        -From 'batch@example.com' ^
        -To '%NOTIFY_TO%' ^
        -Subject '[ERROR][%HOST%] %SUBJECT%' ^
        -Body '%BODY%' ^
        -SmtpServer 'smtp.example.com' ^
        -Port 587 ^
        -UseSsl
"
goto :eof
終了コードは変数に保存してから通知する
if errorlevel 1 (...) のブロック内でコマンドを実行すると%ERRORLEVEL% が上書きされます。set RC=%ERRORLEVEL% で先に保存してから通知処理を呼び出すのが安全です。エラー判定パターンの詳細はエラー時に処理を中断・終了する方法も参照してください。

PowerShell Send-MailMessage でメールを送信する

PowerShell 5.1 以降に標準搭載の Send-MailMessage はコマンド1行でSMTPメールを送信できます。-UseSsl で STARTTLS、-Credential で認証に対応します。

PowerShell Send-MailMessage: 社内SMTPサーバー経由で送信する(認証なし)
powershell -NoProfile -ExecutionPolicy Bypass -Command "
    Send-MailMessage `
        -From 'batch@company.local' `
        -To 'admin@company.local' `
        -Subject '[ERROR] バックアップ失敗' `
        -Body 'バックアップ処理でエラーが発生しました。ログを確認してください。' `
        -SmtpServer 'mail.company.local' `
        -Encoding UTF8
"
Send-MailMessage: 認証付き・ログファイル添付・日本語件名
@echo off
setlocal

set "SMTP=smtp.example.com"
set "PORT=587"
set "FROM=batch@example.com"
set "TO=admin@example.com"
set "USER=batch@example.com"
set "PASS=yourpassword"
set "LOGFILE=C:\logs\batch.log"

powershell -NoProfile -ExecutionPolicy Bypass -Command "
    $cred = New-Object System.Management.Automation.PSCredential(
        '%USER%',
        (ConvertTo-SecureString '%PASS%' -AsPlainText -Force)
    )
    Send-MailMessage `
        -From '%FROM%' `
        -To '%TO%' `
        -Subject '[ERROR][%COMPUTERNAME%] バッチ処理失敗' `
        -Body "エラーが発生しました。添付ログを確認してください。`n実行日時: $(Get-Date)" `
        -SmtpServer '%SMTP%' `
        -Port %PORT% `
        -UseSsl `
        -Credential $cred `
        -Attachments '%LOGFILE%' `
        -Encoding UTF8
"

if %ERRORLEVEL% equ 0 (
    echo [OK] メール送信成功
) else (
    echo [NG] メール送信失敗: ERRORLEVEL=%ERRORLEVEL%
)
endlocal
Send-MailMessage は Gmail では動作しない場合がある
Google が 2022 年に「安全性の低いアプリのアクセス」を廃止したため、Send-MailMessage から Gmail に送信できなくなりました。Gmail を使いたい場合は後述の Net.Mail.SmtpClient でOAuth2 または App Password を使う方法か、社内SMTPリレーサーバーを経由する方法を検討してください。

Net.Mail.SmtpClient で SSL/TLS 完全対応のメール送信

System.Net.Mail.SmtpClient はより細かなTLS設定が可能で、Office365・SendGrid・社内Exchange など現代的なSMTPサーバーに対応しやすいです。

Net.Mail.SmtpClient: Office365 / Exchange Online 経由で送信する
@echo off
setlocal

set "SMTP=smtp.office365.com"
set "PORT=587"
set "FROM=batch@yourcompany.com"
set "TO=admin@yourcompany.com"
set "USER=batch@yourcompany.com"
set "PASS=yourpassword"
set "SUBJECT=[ERROR][%COMPUTERNAME%] バッチ失敗"
set "BODY=処理でエラーが発生しました。"

powershell -NoProfile -ExecutionPolicy Bypass -Command "
    $smtp = New-Object System.Net.Mail.SmtpClient('%SMTP%', %PORT%)
    $smtp.EnableSsl = $true
    $smtp.Credentials = New-Object System.Net.NetworkCredential('%USER%', '%PASS%')

    $msg = New-Object System.Net.Mail.MailMessage
    $msg.From = '%FROM%'
    $msg.To.Add('%TO%')
    $msg.Subject = '%SUBJECT%'
    $msg.Body = '%BODY%'
    $msg.BodyEncoding = [System.Text.Encoding]::UTF8
    $msg.SubjectEncoding = [System.Text.Encoding]::UTF8

    try {
        $smtp.Send($msg)
        Write-Host '[OK] メール送信成功'
    } catch {
        Write-Host "[NG] メール送信失敗: $_"
        exit 1
    } finally {
        $smtp.Dispose()
    }
"
endlocal
Net.Mail.SmtpClient: ログファイルを添付してメール送信
powershell -NoProfile -ExecutionPolicy Bypass -Command "
    $smtp = New-Object System.Net.Mail.SmtpClient('smtp.example.com', 587)
    $smtp.EnableSsl = $true
    $smtp.Credentials = New-Object System.Net.NetworkCredential('user@example.com', 'pass')

    $msg = New-Object System.Net.Mail.MailMessage
    $msg.From = 'batch@example.com'
    $msg.To.Add('admin@example.com')
    $msg.Subject = '[ERROR] バッチ失敗'

    REM ログ末尾20行を本文に含める
    $logLines = Get-Content 'C:\logs\batch.log' -Tail 20 | Out-String
    $msg.Body = "エラーが発生しました。`n`n=== ログ末尾 ===`n$logLines"
    $msg.BodyEncoding = [System.Text.Encoding]::UTF8

    REM ログファイルを添付
    $att = New-Object System.Net.Mail.Attachment('C:\logs\batch.log')
    $msg.Attachments.Add($att)

    $smtp.Send($msg)
    $att.Dispose()
    $smtp.Dispose()
    Write-Host '[OK] 送信完了'
"

ログファイルを監視して ERROR 文字列検知で通知する

コマンドの終了コードではなく、ログファイルに「ERROR」「WARN」などのキーワードが出力されたときに通知する方法です。findstr でキーワードを検索し、ヒットしたときだけ通知します。

log_notify.bat: ログファイルに ERROR が含まれる場合のみ通知する
@echo off
setlocal

set "LOGFILE=C:\logs\app.log"
set "NOTIFY_TO=admin@example.com"
set "SMTP=smtp.example.com"

REM プロセスを実行してログに出力
myprocess.exe >> "%LOGFILE%" 2>&1

REM ログに ERROR または WARN が含まれるか検索
findstr /i /c:"ERROR" /c:"WARN" "%LOGFILE%" >nul 2>&1
if %ERRORLEVEL% equ 0 (
    echo [%DATE% %TIME%] エラーキーワード検知、メール送信

    REM マッチした行だけを抽出して本文に含める
    for /f "delims=" %%L in ('findstr /i /c:"ERROR" /c:"WARN" "%LOGFILE%"') do (
        echo %%L
    ) > "C:\logs\error_lines.txt"

    powershell -NoProfile -Command "
        $lines = Get-Content 'C:\logs\error_lines.txt' | Out-String
        Send-MailMessage `
            -From 'batch@example.com' `
            -To '%NOTIFY_TO%' `
            -Subject '[WARN/ERROR] ログに異常を検知' `
            -Body "以下のエラー行が検出されました:`n$lines" `
            -SmtpServer '%SMTP%' `
            -Encoding UTF8
    "
) else (
    echo [%DATE% %TIME%] エラーなし
)
endlocal
継続監視ループ: ログファイルをポーリングして ERROR 検知で即時通知
@echo off
setlocal enabledelayedexpansion

set "LOGFILE=C:\logs\app.log"
set "LAST_SIZE=0"
set "CHECK_INTERVAL=30"

:WATCH_LOOP
timeout /t %CHECK_INTERVAL% /nobreak >nul

REM ファイルサイズが変化したか確認
for %%F in ("%LOGFILE%") do set "NOW_SIZE=%%~zF"

if !NOW_SIZE! gtr !LAST_SIZE! (
    REM 新しく追記された部分にERRORがあるか検索
    findstr /i "ERROR" "%LOGFILE%" >nul 2>&1
    if !ERRORLEVEL! equ 0 (
        echo [%TIME%] ERROR検知 - 通知送信
        call :SEND_ALERT
    )
    set "LAST_SIZE=!NOW_SIZE!"
)
goto :WATCH_LOOP

:SEND_ALERT
powershell -NoProfile -Command "Send-MailMessage -From 'from@ex.com' -To 'to@ex.com' -Subject 'ERROR検知' -Body 'ログにERRORが出力されました' -SmtpServer 'smtp.example.com'"
goto :eof
ログ監視バッチの活用パターン
ログ監視の詳細パターン(差分検知・複数ファイル横断・エラー行の抽出)についてはログファイルを監視して自動処理するバッチ完全ガイドも参照してください。

curl で Slack Webhook 通知を送信する(外部ツール不要)

Windows 10 1803 以降には curl.exe が標準搭載されており、Slack の Incoming Webhook URL に POST するだけで通知を送れます。メールサーバーの設定が不要で最も手軽な通知方法です。

Slack Webhook URL の取得方法

  • Slack ワークスペースの設定 → アプリ → Incoming Webhooks を追加
  • 通知先チャンネルを選択すると Webhook URL が発行される
  • URL 形式: https://hooks.slack.com/services/XXX/YYY/ZZZ
slack_notify.bat: curl で Slack チャンネルにエラー通知を送信する
@echo off
setlocal

set "WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ"
set "HOST=%COMPUTERNAME%"
set "MSG=バックアップ処理でエラーが発生しました"

curl -s -X POST "%WEBHOOK_URL%" ^
  -H "Content-Type: application/json" ^
  -d "{"text":":x: [ERROR][%HOST%] %MSG%"}"

if %ERRORLEVEL% equ 0 (
    echo [OK] Slack 通知送信成功
) else (
    echo [NG] Slack 通知送信失敗
)
endlocal
Slack 通知にリッチな情報(PC名・時刻・エラー詳細・ログ抜粋)を含める
@echo off
setlocal

set "WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ"
set "HOST=%COMPUTERNAME%"
set "DATETIME=%DATE% %TIME%"
set "LOGFILE=C:\logs\batch.log"

REM ログ末尾5行を取得
powershell -NoProfile -Command "Get-Content '%LOGFILE%' -Tail 5 | Out-String" > "%TEMP%\slack_msg.txt"
set /p LOG_TAIL=<"%TEMP%\slack_msg.txt"

REM JSON ペイロードをファイルに書き出して curl で送信
powershell -NoProfile -Command "
    $tail = (Get-Content '%LOGFILE%' -Tail 5) -join "`n"
    $payload = @{
        text = ":x: *[ERROR] バッチ失敗*"
        attachments = @(@{
            color = 'danger'
            fields = @(
                @{ title = 'サーバー'; value = '%HOST%'; short = $true }
                @{ title = '日時'; value = '%DATETIME%'; short = $true }
                @{ title = 'ログ末尾'; value = $tail; short = $false }
            )
        })
    } | ConvertTo-Json -Depth 5
    Invoke-RestMethod -Uri '%WEBHOOK_URL%' -Method Post -Body $payload -ContentType 'application/json'
"
endlocal
Slack 通知を使う場面
SMTPサーバーの設定が複雑な環境や、チーム全員がすぐに通知を見る必要がある場合には Slack 通知が便利です。メールより即時性が高く、スマホアプリで通知を受け取れます。curl.exe が使えない古い環境ではpowershell Invoke-RestMethod に置き換えてください。

外部ツール Blat でシンプルにメール送信する

Blat はコマンドライン SMTP メーラーです。PowerShell が使えない古い環境や、コードをシンプルに保ちたい場合に選択肢になります。ただし外部ツールのインストールが必要です。

Blat の初期設定とメール送信
REM 初期設定(1回のみ実行)
blat -install smtp.example.com sender@example.com

REM 基本的なメール送信
blat - -to admin@example.com -subject "[ERROR] バッチ失敗" -body "エラーが発生しました"

REM SMTP 認証あり・ポート指定
blat - -to admin@example.com ^
  -subject "[ERROR] バッチ失敗" ^
  -body "エラーが発生しました" ^
  -server smtp.example.com:587 ^
  -u your_username ^
  -pw your_password ^
  -ssl

REM ファイルを本文として送信
blat mail_body.txt -to admin@example.com -subject "[ERROR] バッチ失敗"

REM ログファイルを添付
blat - -to admin@example.com -subject "[ERROR] バッチ失敗" ^
  -body "エラーが発生しました" ^
  -attach "C:\logs\batch.log"
パスワードのハードコーディングに注意
バッチファイルにパスワードを直接書くとファイルを読める人に漏えいします。バッチファイルのアクセス権を実行ユーザーのみに制限するか、パスワードを環境変数から読み込む設計にしてください。PowerShell の場合は Get-Credential やWindows 資格情報マネージャーから読み込む方法もあります。

通知内容をリッチにする(PC名・エラーコード・ログ本文・日時)

通知メールの本文に情報を詰め込むことで、メールを受け取った担当者がすぐに状況を把握できるようになります。

rich_notify.bat: PC名・エラーコード・ログ末尾・日時を含むリッチ通知
@echo off
setlocal

set "LOGFILE=C:\logs\batch.log"
set "TASK_NAME=日次バックアップ"
set "SMTP=smtp.example.com"
set "FROM=batch@example.com"
set "TO=admin@example.com"

REM 処理実行
xcopy "C:\data" "D:\backup\" /s /e /y >> "%LOGFILE%" 2>&1
set RC=%ERRORLEVEL%

if %RC% neq 0 (

powershell -NoProfile -ExecutionPolicy Bypass -Command "
    $pc = '%COMPUTERNAME%'
    $task = '%TASK_NAME%'
    $rc = %RC%
    $now = Get-Date -Format 'yyyy/MM/dd HH:mm:ss'
    $log = (Get-Content '%LOGFILE%' -Tail 20 -ErrorAction SilentlyContinue) -join "`n"

    $body = @"
タスク: $task
PC名: $pc
日時: $now
終了コード: $rc

=== ログ末尾20行 ===
$log
"@

    Send-MailMessage `
        -From '%FROM%' `
        -To '%TO%' `
        -Subject "[ERROR][$pc] $task が失敗しました (RC=$rc)" `
        -Body $body `
        -Attachments '%LOGFILE%' `
        -SmtpServer '%SMTP%' `
        -Encoding UTF8
"

)
endlocal

実践パターン:エラー通知付きバックアップバッチの完全構成

backup_with_notify.bat: ログ・ERRORLEVEL判定・メール通知を組み込んだ実践版
@echo off
setlocal

REM ===== 設定 =====
set "SRC=C:\data"
set "DEST=D:\backup"
set "LOGDIR=C:\logs\backup"
set "SMTP=smtp.example.com"
set "FROM=batch@example.com"
set "TO=admin@example.com"
set "SLACK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ"
REM ================

if not exist "%LOGDIR%" mkdir "%LOGDIR%"
for /f "tokens=1-3 delims=/" %%A in ("%DATE%") do set "DT=%%A%%B%%C"
set "LOGFILE=%LOGDIR%\%DT%.log"

echo [%DATE% %TIME%] ===== バックアップ開始 ===== >> "%LOGFILE%"
echo 転送元: %SRC% >> "%LOGFILE%"
echo 転送先: %DEST%\%DT% >> "%LOGFILE%"

REM バックアップ実行
robocopy "%SRC%" "%DEST%\%DT%" /e /log+:"%LOGFILE%" /np
set RC=%ERRORLEVEL%

REM robocopy の終了コード: 0〜7 は成功、8以上はエラー
if %RC% lss 8 (
    echo [%DATE% %TIME%] バックアップ成功: RC=%RC% >> "%LOGFILE%"
    echo [OK] バックアップ完了
    exit /b 0
)

REM エラー発生 → メール + Slack 通知
echo [%DATE% %TIME%] バックアップ失敗: RC=%RC% >> "%LOGFILE%"

REM メール通知
powershell -NoProfile -Command "
    $log = (Get-Content '%LOGFILE%' -Tail 30) -join "`n"
    Send-MailMessage `
        -From '%FROM%' `
        -To '%TO%' `
        -Subject '[ERROR][%COMPUTERNAME%] バックアップ失敗 RC=%RC%' `
        -Body $log `
        -Attachments '%LOGFILE%' `
        -SmtpServer '%SMTP%' `
        -Encoding UTF8
"

REM Slack 通知(二重通知で確実に届ける)
curl -s -X POST "%SLACK_URL%" ^
  -H "Content-Type: application/json" ^
  -d "{"text":":x: [ERROR][%COMPUTERNAME%] バックアップ失敗 RC=%RC% 日時: %DATE% %TIME%"}"

exit /b %RC%
robocopy の終了コードは 0〜7 が成功
robocopy は差分コピー結果をビットフラグで返します。0(変更なし)〜7(ファイルコピー+ミスマッチあり)は成功、8以上がエラーです。通常の if %RC% neq 0 では正常終了でも通知が飛ぶため、if %RC% geq 8 で判定してください。ログ設計の詳細はログを出力する方法完全ガイドも参照してください。

まとめ

  • ERRORLEVEL 判定: set RC=%ERRORLEVEL% で保存してからサブルーチンで通知。終了コードを汚染しない
  • Send-MailMessage: 外部ツール不要・コードが短い。-UseSsl-Credential-Attachments で実用的に
  • Net.Mail.SmtpClient: TLS 完全対応。Office365/Exchange に適切。try-catch でエラー処理必須
  • ログ監視: findstr /i "ERROR" でキーワード検索。マッチ行を本文に含めて原因を即把握
  • Slack Webhook: curl で JSON POST するだけ。メールサーバー不要・即時性が高い
  • Blat: 外部ツール必要。古い環境でもコマンド1行でメール送信可能
  • リッチ通知: PC名・終了コード・ログ末尾20行・日時を本文に含めると担当者が即座に状況把握できる

関連記事: エラー時に処理を中断・終了する方法 / ログファイルを監視して自動処理するバッチ完全ガイド / schtasksコマンドで完全制御する完全ガイド

よくある質問(FAQ)

QSend-MailMessage でエラーになり「TLS の接続を確立できませんでした」と出ます。
ASMTPサーバーが要求するTLSバージョンと PowerShell のバージョンが一致しない場合に発生します。-UseSsl を外してポートを 25 に変えて試す、またはNet.Mail.SmtpClient に切り替えて[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12を追加してください。Office365 は TLS 1.2 が必須です。
Qメールは送れるがタスクスケジューラから実行すると送信されません。
Aタスクスケジューラ実行時は PowerShell の ExecutionPolicy が Restricted のままのことがあります。powershell -ExecutionPolicy Bypass を明示的に付けてください。また SYSTEM アカウントで実行している場合は認証情報が別ユーザーのものと異なるためネットワーク接続に失敗することがあります。タスクの実行ユーザーをメールアカウントにアクセスできるユーザーに変更してください。
Q処理が成功しても通知が来てしまいます。
AERRORLEVEL の判定で if %RC% neq 0 を使っているのにrobocopy などの終了コードが「成功でも 1〜7」を返すコマンドを使っているケースが多いです。robocopy は 8 以上がエラーのため if %RC% geq 8 で判定してください。また findstr の検索でマッチがなくてもログファイルに以前の ERROR 行が残っていると検知されます。ログを実行ごとに新規作成するか、今回追記分のみを対象に検索してください。
QSlack Webhook URL を直接バッチに書くのはセキュリティ上問題ですか?
AWebhook URL が漏えいすると第三者がチャンネルに書き込めてしまいます。バッチファイルのアクセス権を実行ユーザーのみに制限するか、Webhook URL を環境変数や設定ファイル(アクセス制限済み)から読み込む設計にしてください。例: set /p SLACK_URL=<C:\config\slack_url.txt
Q同じエラーが繰り返し発生するとメールが大量に届きます。
Aフラグファイルを使って「既にエラー通知済み」なら送信しない設計が有効です。if not exist "C:\flags\error_sent.flag" のときだけ送信し、送信後に echo . > "C:\flags\error_sent.flag" でフラグを作成します。次の正常実行時に del "C:\flags\error_sent.flag" でフラグを削除してください。これにより同じエラーで複数回通知が来ることを防げます。