
メール誤送信を防ぐリリース手順|本番で顧客に飛ばさない確認項目
「このメール文面の修正、大した改修じゃないんですけどね」 「……でも、間違って全会員に飛んだらと思うと、手が止まる」
メールが絡むリリースは、他の改修と少しだけ違います。画面の不具合なら、気づいてから直せばいい。でもメールは、送った瞬間に自分の手を離れて外へ出ていきます。あとから「なかったこと」にはできません。宛先を間違えれば謝罪が要り、二重送信すれば問い合わせが増え、内容によっては社内報告の手続きまで発生します。
だから緊張するのは当然です。その緊張は、危機感が正しく働いているということでもあります。ただ、緊張だけで守り続けるのはしんどいですよね。深夜に一人で反映して、「送信されていないよな」と何度も確認しに戻る。そういう夜を減らしたいところです。
この記事では、注意力ではなく段取りで誤送信を防ぐ形を一緒に整理します。環境や構成で細部は変わりますが、順番はそのまま使えます。
結論:メール送信を含む改修は、「止める → 試す → 開ける」の3段で本番に通します。具体的には、①送信機能を止めた(送らない)状態でコードだけ本番に出す → ②自分や社内の宛先1件だけに実際に送って、宛先・差出人・文面・リンクを実物で確かめる → ③少量から順に開けて、送信ログと件数を見ながら全体に広げる。あわせて、検証環境からは物理的に外へメールが出ない仕組み(送信先を開発用の受け皿に固定する)と、1回の実行で一定件数を超えたら止まる上限を先に入れておきます。「気をつける」を仕組みに置き換えるのが、いちばん効きます。
一度に全部そろえなくて大丈夫です。この記事の中では、③の「少量から開ける」と検証環境の出口をふさぐことの2つだけでも、効果がはっきり出ます。
何が起きているか:誤送信は「うっかり」より「段取りの穴」から起きる
メールの事故は、注意力が足りない人のところで起きるわけではありません。送信という処理が、他の処理と性質が違うのに、同じ手順で扱われているところで起きます。
普通の改修は「実行 → 確認 → おかしければ戻す」が成り立ちます。ところが送信は、戻すという操作が存在しません。だから、他の改修と同じ手順で通すと、確認のタイミングが1つ足りないまま本番に出ることになります。
現場で実際に起きやすいのは、だいたい次の5つの型です。心当たりがあっても、落ち込まなくて大丈夫です。どれも構造の問題です。
- 検証環境に本番のデータが入っていた型:動作確認のために本番DBをコピーして検証環境に置く。テストで送信処理を走らせたら、コピー元の実在するお客様のアドレスにそのまま届いた、というものです。いちばん多い型で、いちばん防ぎやすい型でもあります。
- 未送信フラグが巻き戻った型:データ移行やテーブル定義の変更で、送信済みを表すフラグが初期値(未送信)に戻る。次にバッチが動いた瞬間、過去分がまとめて再送されます。件数が大きくなりやすい、こわい型です。
- 宛先の絞り込みが外れた型:デバッグ用に「送信先を自分に固定する」設定を入れていて、本番でそれを外す・外し忘れるの取り違えが起きるもの。あるいは条件文の変更で、対象者を絞る
WHERE句が効かなくなり、全件が対象になるものです。 - 二重に走った型:バッチの多重起動、キューの再処理、リリース中のリトライ。同じメールが2通・3通と届きます。1通ずつは正しいのに、結果として事故になります。
- BCCとTOを取り違えた型:一斉送信で、本来伏せるべき宛先が受け取った全員に見える状態で出てしまうもの。届いた内容自体は正しいのに、他人のメールアドレスという個人情報が広がるため、影響が大きくなりがちです。
こうして並べてみると、どれも「気をつける」で防ぐのが難しいものばかりです。フラグの巻き戻りは目視では見えませんし、条件文の変更は正しく動いているように見えます。だから、手順の側で受け止めます。
本番への通し方:止める → 試す → 開ける

急がなくて大丈夫です。この3段を、それぞれ確認を挟みながら進めます。
① 止める:送信を止めた状態で本番に出す
コードの反映と、メールが飛ぶことを同じ瞬間に起こさないのがこの段の目的です。反映した直後にバッチが動いて、確認する前に出ていってしまうのを避けます。
止め方は、環境にあるものでかまいません。
- 送信のオン/オフを設定で持つ:
MAIL_ENABLED=falseのような設定値を1つ用意して、反映時はオフで出す。いちばん扱いやすい形です。 - バッチを一時的に止める:送信を担う定期実行を、作業のあいだだけ無効にします。
crontabの該当行をコメントアウトするなら、戻し忘れが起きないよう作業メモに「戻す」を1行書いておきます。
# 送信バッチを一時的に止める(該当行の先頭に # を付ける)
crontab -l > ~/crontab.$(date +%Y%m%d).bak # 先に退避を取る
crontab -e
# 作業後、退避したものと見比べて戻せているか確かめる
diff <(crontab -l) ~/crontab.$(date +%Y%m%d).bak
- キューを止める:キュー経由で送っているなら、ワーカーだけ停止しておきます。キューに積まれること自体は問題ありません。開けたときに流れます。
止めた状態で反映したら、まず「本当に止まっているか」を確かめます。ここを飛ばすと、止めたつもりで流れます。送信ログが増えていないこと、キューが処理されずに積まれていることを、実際に見て確認します。
なお「止める」の対象には、リリースの前からキューに残っていた分も入ります。古いテンプレートで積まれたものが、新しいコードで一斉に流れることがあるためです。積まれている件数を先に数えておくと安心です。
② 試す:自分宛の1通で確かめる
止まっている状態のまま、送信先を自分(または社内の確認用アドレス)だけに絞って、実際に1通送ります。ここが要です。検証環境でどれだけ確認していても、本番でしか分からないことが残ります。
1通の実物で見る項目はこれだけです。
- 宛先:意図した1件だけに届いたか。CCやBCCに余計な宛先が入っていないか。
- 差出人(From)と返信先(Reply-To):本番の正しいアドレスか。検証用のアドレスが残っていないか。
- 件名と本文:文字化けしていないか。差し込み項目(氏名、注文番号など)が空欄や
{{name}}のまま出ていないか。 - 本文中のリンク:実際にクリックして、本番のURLに飛ぶか。検証環境のドメインや
localhostが混じるのは、テンプレート改修でとても起きやすい型です。 - 見た目:HTMLメールなら、スマートフォンでも読めるか。画像が表示されない環境でも意味が通るか。
- 迷惑メール扱いになっていないか:受信箱に入ったか、迷惑メールフォルダに落ちたか。落ちる場合は送信元の設定側を確認します(メールが届かないときの切り分けにまとめています)。
差し込み項目は、空になりやすいデータを選んで試すのがコツです。氏名が未登録の会員、住所が途中までしか入っていない注文。正常なデータだけで試すと、本番で初めて「様」だけが並んだメールが出ます。
送信先を絞る方法は、コードを書き換えるのではなく設定で切り替えられる形にしておくのが安全です。書き換えて戻し忘れるのが、そのまま事故になるためです。
③ 開ける:少しずつ、ログを見ながら
1通で問題がなければ、いよいよ開けます。ただし一気に全開にしません。
- 上限を決めて開ける:まず10件、次に100件、というように段階を踏みます。送信件数の上限を設定値で持っておくと、この刻みが楽になります。
- 1段ごとに送信ログを見る:件数は想定どおりか。同じ宛先に2回出ていないか。エラーで失敗しているものはないか。
- バウンス(宛先不明で戻ってくるもの)を見る:急に増えていれば、宛先データの取り違えを疑います。
- 問い合わせ窓口に一声かけておく:「◯時からメール送信の反映をします」と伝えておくだけで、万一のとき最初の反応が早く届きます。
- 全開にしたら、しばらく手を離さない:最初の数分は画面を閉じないでおきます。
途中で少しでもおかしければ、すぐ止めて構いません。止めるのは失敗ではなく、この手順が正しく働いた証拠です。止めたあとに考える時間があるほうが、走り切ってから謝るよりずっと楽です。戻し方の考え方はロールバック手順の作り方と同じで、開ける前に「どう止めるか」を決めておくのがポイントになります。
事前の仕込み:検証環境から外へ出さない
ここまでの3段は当日の話でした。あわせて、普段の環境の側にも守りを1つ置いておくと、ぐっと楽になります。ねらいはひとつ、検証環境からは、間違っても外へメールが出ないようにすることです。
やり方はいくつかあります。どれか1つでかまいません。
- 開発用のメール受け皿に向ける:検証環境のSMTP設定を、外部のメールサーバーではなく手元で受け止めるツールに向けます。送ったメールはブラウザで中身を確認でき、外には1通も出ません。Mailpit のようなツールがこの用途に使われます(以前よく使われていた MailHog は開発が止まっているため、これから入れるなら後継のものを選ぶほうが安心です)。
- ファイルやログに書き出す設定にする:フレームワークによっては、送信ドライバを「ログに出力」に切り替えられます。実際には送らず、内容だけ残ります。
- 宛先ホワイトリストを効かせる:自社ドメイン宛て以外は送信処理の入口で捨てる、という判定を1か所に入れます。本番以外では強制的にオンになるようにしておきます。
- 送信サービスのサンドボックスを使う:外部の配信サービスを使っているなら、検証用のアカウントを検証済みアドレス以外に送れない状態のままにしておく方法もあります(Amazon SES なら、新規アカウントは既定でサンドボックス状態です)。
ここで大事なのは、判定を1か所にまとめることです。送信処理があちこちに散らばっていると、どこか1つが守りをすり抜けます。まずは、送信処理の呼び出し口がいくつあるかを数えるところからです。
# メール送信の呼び出し口が何か所あるか、まず数える(関数名は環境に合わせて読み替え)
grep -rn -e "mail(" -e "sendmail" -e "smtp" /var/www/html --include="*.php" | wc -l
# どのファイルに散らばっているかを見る
grep -rln -e "mail(" -e "sendmail" /var/www/html --include="*.php"
数えてみると、思ったより多いことがあります。全部をすぐ1本にまとめる必要はありません。「新しく足すものは必ずこの1本を通す」と決めるだけでも、散らばりは止まります。設定を環境ごとに切り替える考え方は環境差の設定管理が参考になります。
もう1つ、送信件数の上限(それを超えたら止まる仕組み)も入れておくと効きます。「1回の実行で500件を超えたら送信せず中断して通知」といった形です。フラグ巻き戻りによる大量再送は、これがあるだけで被害の桁が変わります。バッチの異常に気づく仕掛けはcronバッチの失敗を見逃さない仕組みと組み合わせると、より確実になります。
具体例:会員向けお知らせメールの文面改修
よくある形を、順番にたどってみます。文面を少し直すだけの、小さな改修です。
- 改修内容:会員向けお知らせメールの署名欄と、本文中の案内リンクを差し替える。対象は約8,000件。
- ①止める:
MAIL_ENABLED=falseにした状態でコードを本番へ反映。反映後、送信ログが増えていないことと、キューに0件しか積まれていないことを確認した。 - ②試す:送信先を自分のアドレス1件に固定して、1通だけ送信。届いたメールを見ると、署名は正しく変わっていたが、案内リンクが検証環境のドメインのままだった。テンプレート内でURLをベタ書きしていた箇所が1つ残っていた。修正して、もう一度1通送って確認。
- もう一度②:今度は差し込み項目が空になる会員(氏名未登録)を想定したデータで1通試した。宛名が「 様」になっていたので、未登録時は「お客様」と出るよう直した。
- ③開ける:上限10件で送信 → ログを確認、重複なし。次に100件 → バウンスが2件出たが、いずれも以前から宛先不明として記録済みのアドレスだった。問題なしと判断して全開。最初の5分は送信ログを開いたまま様子を見た。
- 記録:変更管理の台帳に「反映日/送信対象8,000件/段階(1→10→100→全開)/テンプレのURLベタ書きを1件修正/戻し方=
MAIL_ENABLED=false」と残した。
この例で救われたのは②です。検証環境では正しく動いていたのに、本番の実物を1通見て初めて分かりました。もしこれを飛ばして全開にしていたら、8,000人に検証環境へのリンクを案内していたことになります。1通の確認が、そのまま8,000通分の安心になった形です。
そして、ベタ書きのURLが残っていたことは誰かの不注意ではありません。改修のたびに毎回見つかる種類の見落としです。だからこそ、毎回見る手順にしておく価値があります。
影響:3段の手順を持つと、何が変わるか
送信を含むリリースに手順を1つ持っておくと、事故の確率が下がるだけでなく、進め方そのものが軽くなります。
- 反映のタイミングで身構えなくてよくなる。止めた状態で出せるので、コードの反映と送信の判断を切り離せます。
- 深夜に作業しなくてよくなることがある。「送信が始まらない」と分かっていれば、日中の落ち着いた時間に反映できます。
- 確認の抜けが減る。1通の実物で見る項目が決まっていれば、その日の集中力に結果が左右されません。
- 万一のときの被害が小さくて済む。段階的に開けていれば、気づいた時点で止まっている分が残ります。
- 説明できる形になる。「どういう手順で出したか」を答えられると、社内の不安も一緒に下がります。
なお、もし誤送信が起きてしまった場合は、まず止める → 送信ログで範囲を確定する → 関係者に一報の順です。内容によっては社内の報告手続きや、個人情報保護法にもとづく報告・通知の対象になることがあります。判断基準は自社の規程と個人情報保護委員会の公表資料で確認してください。第一報の伝え方は障害第一報のテンプレートが、証拠を消さない初動は不正アクセスが疑われるときの初動がそのまま使えます。
慌てないための備えとして、この順番だけ手元に置いておけば十分です。
明日やること:まず「出口」を1つ確かめる
全部そろえるのは大仕事です。明日できる、いちばん小さな一歩はこれです。
- 検証環境のメール送信設定を1行見る。SMTPの向き先が、外部の実サーバーになっていないかを確認します。外を向いていたら、それが今いちばん優先度の高い1件です。
- 送信処理の呼び出し口を数える。
grep -rn "mail(" ...を1回打つだけ。数が分かれば、守りをどこに置くかが決まります。 - 送信ログの残り方を確認する。「いつ・誰に・何を送ったか」が後から引けるか。引けないなら、まずログを1行足すのが先です。
- 次のリリース用に、止め方を1行メモする。「送信を止めるには、どのファイルの・どの設定を・どう変えるか」。この1行があるだけで、当日の判断が速くなります。
- 上限の値を決める。「1回の実行で何件を超えたら、いったん止まってほしいか」。数字を決めるところまでで、実装は後日でかまいません。
全部やらなくて大丈夫です。1番だけでも確かめておけば、いちばん起きやすい型は今日から遠ざかります。
メール送信を含むリリースのチェックリスト
反映の前後で確認する項目です。全部を毎回そろえる必要はありません。
まず外せない最低ラインはこの3つです。急いでいても、ここだけは押さえます。
- 【最低ライン】送信を止めた状態でコードを反映し、止まっていることを実際に確認したか
- 【最低ライン】本番で、自分(または社内)宛の1通を実際に送って、宛先・差出人・文面・リンクを実物で見たか
- 【最低ライン】いきなり全件に開けず、少量(10件程度)から段階的に開ける計画になっているか
次の項目は、余裕があるときや、対象件数が大きいときに追加で確認します。
- 送信対象の件数を、開ける前に数えて把握したか(想定と桁が合っているか)
- リリース前からキューに残っていた分の扱いを決めたか(流す/捨てる/内容を確かめる)
- データ移行や定義変更で、送信済みフラグが初期値に戻っていないか確認したか
- 対象者を絞る条件(
WHERE句など)を変更した場合、件数が想定どおりか事前にSELECT COUNT(*)で確かめたか - 差し込み項目が空になるデータでも、不自然な文面にならないか試したか
- 本文中のリンクを実際にクリックして、本番のURLに飛ぶことを確かめたか
- 一斉送信の場合、TOとBCCの使い分けが意図どおりか確認したか
- 二重起動・再処理で同じメールが複数回出ない作りになっているか
- 「いつ・誰に・何を送ったか」が後から引ける形でログに残るか
- 一定件数を超えたら止まる上限が入っているか
- 送信を止める手順(どの設定をどう変えるか)を、作業前に書き出したか
- 検証環境から外部へメールが出ない仕組みになっているか(受け皿ツール・ログ出力・ホワイトリスト等)
- 問い合わせ窓口に、反映の時間帯を事前に伝えたか
- 全開後、しばらく送信ログとバウンスの様子を見る時間を確保したか
全部に○が付かなくても大丈夫です。最低ラインの3つ、とくに「本番で1通試してから、少しずつ開ける」さえ守れれば、この作業はもう賭けではなくなります。
よければ、こちらも
メールに限らず、「出したら戻せない」種類の作業は、同じ考え方で軽くできます。あわせて少しずつ整えていくと効きます。
- リリース手順書(runbook)の作り方|最低限そろえたい項目:この3段を、次回そのまま使える1枚に落とし込むときの型です。
- 「すぐ戻せる」リリース設計|ロールバック手順の用意:開ける前に「どう止めるか」を決めておくための考え方をまとめています。
- 本番反映のチェックリスト|バックアップと確認の順番:反映そのものの段取りです。この記事と対で使えます。
- データ修正をSQLでやるときの安全手順|件数確認とバックアップ:送信対象を絞る条件を変えるとき、件数の確かめ方がそのまま応用できます。
- メールが届かないときの切り分け|SPF・DKIMから確認する順番:試し送りが迷惑メールに落ちたときは、こちらから追えます。
- 環境差の設定管理|本番と検証で値を安全に分ける:検証環境の出口をふさぐ設定を、事故なく分けておくための整理です。

メールのリリースで手が止まるのは、慎重すぎるからではありません。取り消せないことを、ちゃんと分かっているからです。その感覚は、送信を扱う人として何より大事なものだと思います。
だから、必要だったのは覚悟ではなく順番でした。止めた状態で出して、1通で試して、少しずつ開ける。それだけで、押す瞬間の重さがずいぶん軽くなります。途中で止めていいと決めておけば、なおさらです。
まずは、検証環境の送信設定が外を向いていないか、1行だけ見てみるところから。今日その1行を確かめておけば、次にメールの改修が来たとき、いちばん起きやすい事故はもう手前で止まっています。
ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。