5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

メール配信システムを運用していると、必ず遭遇するのがバウンスメールです。(個人利用でもなぜこのメール送れなかったの?なんてこともあると思います。)

「送信したはずのメールが戻ってきた」
「エラーコード550って何?」
「このアドレス、リストから消していいの?」

こんな疑問を持ったことはありませんか?

バウンスメールを正しく理解し、適切に対処することは、メール配信の成功率(到達率)を維持するために不可欠です。放置すると、最悪の場合 「ブラックリスト入り」 という事態を招いてしまいます。

今回は、バウンスメールの種類、エラーコードの読み方、そして正しい対処法をまとめてみました。

最近は企業側のセキュリティ強化により、添付ファイルのチェックが厳しくなってバウンスが増えるケースもあります。 メール配信だけでなく、個人利用でも正常なメールがエラーで戻ってくることが増えているため、なぜ戻ってくるのかを理解しておくことがますます重要になっています。

バウンスメールとは!?

バウンスメール(Bounce Mail)とは、送信したメールが何らかの理由で受信者に届かず、送信元にエラーとして返ってくるメールのことです。

m001 (1).png

「バウンス」は英語で「跳ね返る」という意味。メールがサーバー間で跳ね返されてきた、というイメージです。

2種類のバウンス(ハードとソフト)

バウンスメールは大きく2種類に分類されます。この区別が対処法を決める上でとっても重要です。

ハードバウンス(Hard Bounce)

永続的なエラー です。何度送っても届きません!!

主な原因 説明
メールアドレスが存在しない 入力ミス、退職、アカウント削除
ドメインが存在しない ドメイン失効、入力ミス
受信サーバーによる永久拒否 スパム判定、ブロックリスト

対処法
即座にリストから削除
ハードバウンスが発生したアドレスに再送を繰り返すと、スパマーと見なされるリスクがあります。

ソフトバウンス(Soft Bounce)

一時的なエラーです。時間が経てば解決する可能性があります。

主な原因 説明
メールボックスがいっぱい 受信者の容量不足
受信サーバーの一時停止 メンテナンス、障害
メールサイズが大きすぎる 添付ファイルの容量超過
一時的な接続エラー ネットワークの問題

対処法
様子を見て再送を試みる
ただし、同じアドレスでソフトバウンスが繰り返される場合は、ハードバウンスと同様に扱うべきです。多くの配信サービスでは3〜5回程度を基準にしています。本記事では5回を目安として解説します。 添付サイズの容量超過はよくあるので必ず確認してみましょう。

エラーコードの読み方

バウンスメールにはSMTPステータスコードが含まれています。このコードを読めば、エラーの原因がわかります。

例えば、こんな感じのメールが届きます。

件名:【Undelivered Mail Returned to Sender】
m005 (1).png
※実際のバウンスメールの例(画像は一部加工しています)

メールサーバーごとに件名や本文は違いますが、上記のように「554.5.7.1」のような形式で表示されています。

基本構造

m002 (1).png

550 5.1.1 The email account does not exist
│   │ │ │  └── エラーメッセージ(人間向け説明)
│   │ │ └──── 詳細コード(detail)
│   │ └────── サブジェクト(subject:1=アドレス関連)
│   └──────── クラス(class:2=成功/4=一時的/5=永続的)
└────────────── 応答コード(3桁のBasic Status Code)

5.1.1の部分は拡張ステータスコード(Enhanced Status Code) と呼ばれ、3つのフィールドで構成されています。

応答コードの1桁目

1桁目 意味
4xx 一時的なエラー(ソフトバウンス)
5xx 永続的なエラー(ハードバウンス)

これだけ覚えておけば、バウンスの種類はすぐに判断できます。

主要なエラーコード一覧

ハードバウンス(5xx系)

コード 意味 対処法
550 メールアドレスが存在しない リストから削除
551 ユーザーがローカルにいない アドレス確認・削除
552 メールボックス容量超過 一定期間おいて再送、続くなら削除
553 メールボックス名が不正 アドレス形式を確認
554 トランザクション失敗 原因調査が必要

補足:552について
552は5xxコードなので仕様上は「永続的エラー」ですが、実務では容量回復後に届くケースもあります。そのため、一定期間はソフトバウンス相当として様子を見る運用も一般的です。

550の詳細パターン

550は最もよく見るエラーですが、詳細によって意味が変わります。

550 5.1.1 User unknown        → アドレスが存在しない
550 5.7.1 Relay access denied → リレーが拒否された
550 5.7.0 Rejected by policy  → ポリシーで拒否

ソフトバウンス(4xx系)

コード 意味 対処法
421 サービス一時停止 時間をおいて再送
450 メールボックス一時利用不可 時間をおいて再送
451 ローカルエラー 時間をおいて再送
452 容量不足 サイズを小さくして再送

Gmail / Yahoo! / Outlook の独自エラー

大手メールサービスは、RFCの定義とは別に独自のエラーコードを使うことがあります。

Gmail の主なエラー

エラー 意味
421 4.7.0 ... rate limited 送信レート制限
550 5.7.1 ... not RFC 5322 compliant メール形式が不正
550 5.7.26 ... DMARC policy DMARC認証失敗

Yahoo! の主なエラー

エラー 意味
553 5.3.0 ... over quota 送信量制限超過
554 ... Message not allowed コンテンツがブロック

Outlook / Microsoft 365 の主なエラー

エラー 意味
550 5.4.1 Recipient address rejected 宛先アドレスが拒否された
550 5.7.1 Service unavailable 送信者がブロックされている
451 4.7.500 Server busy サーバー混雑による一時拒否

バウンスを放置するリスク

たまにエラーが出るけど、大半は届いてるから大丈夫

この考えはとても危険です。

1. IPレピュテーションの低下

存在しないアドレスに送り続けると、送信元IPの「評価」が下がります。これが下がると、正常なアドレスへのメールも迷惑メール扱いされやすくなります。

2. ブラックリスト登録

バウンス率が高い状態が続くと、送信元IPやドメインがブラックリストに登録される可能性があります。一度登録されると、解除には数週間〜数ヶ月以上かかることもあり、長期間にわたって影響が残ります。

3. 配信サービスのアカウント停止

メール配信サービスを利用している場合、バウンス率が高いとアカウントが停止されることがあります。

推奨されるバウンス率

一般的に、バウンス率は2%以下が推奨されています。

バウンス率 = バウンス数 / 送信数 × 100

1万通送って200通以上エラーが返ってくる状態は、改善が必要なサインです。

正しい対処フロー

バウンスメールを受け取ったら、以下のフローで対処しましょう。

m003 (1).png

実装例

Pythonのサンプルコードを見る
from enum import Enum, auto
from typing import Dict


class BounceAction(Enum):
    REMOVE_FROM_LIST = auto()   # リストから削除
    RETRY_LATER = auto()        # 後で再送
    INVESTIGATE = auto()        # 調査が必要


class BounceHandler:
    MAX_SOFT_BOUNCE_COUNT = 5

    def __init__(self) -> None:
        # emailごとのソフトバウンス回数を記録(Python 3.8 互換)
        self._soft_bounce_count: Dict[str, int] = {}

    def handle_bounce(self, email: str, error_code: int) -> BounceAction:
        """
        :param email: バウンスしたメールアドレス
        :param error_code: 3桁のSMTPステータスコード (例: 421, 550)
        """

        # ハードバウンス(5xx)は即削除
        if 500 <= error_code < 600:
            return BounceAction.REMOVE_FROM_LIST

        # ソフトバウンス(4xx)は回数をカウント
        if 400 <= error_code < 500:
            count = self._soft_bounce_count.get(email, 0) + 1
            self._soft_bounce_count[email] = count

            if count >= self.MAX_SOFT_BOUNCE_COUNT:
                return BounceAction.REMOVE_FROM_LIST

            return BounceAction.RETRY_LATER

        # それ以外は内容を調査
        return BounceAction.INVESTIGATE


# 使用例
if __name__ == "__main__":
    handler = BounceHandler()

    action = handler.handle_bounce("user@example.com", 550)
    print(action)  # BounceAction.REMOVE_FROM_LIST
C#のサンプルコードを見る
public class BounceHandler
{
    private readonly Dictionary<string, int> _softBounceCount = new();
    private const int MaxSoftBounceCount = 5;

    public BounceAction HandleBounce(string email, int errorCode)
    {
        // ハードバウンス(5xx)は即削除
        if (errorCode >= 500 && errorCode < 600)
        {
            return BounceAction.RemoveFromList;
        }

        // ソフトバウンス(4xx)はカウント
        if (errorCode >= 400 && errorCode < 500)
        {
            _softBounceCount.TryGetValue(email, out int count);
            _softBounceCount[email] = count + 1;

            if (_softBounceCount[email] >= MaxSoftBounceCount)
            {
                return BounceAction.RemoveFromList;
            }

            return BounceAction.RetryLater;
        }

        return BounceAction.Investigate;
    }
}

public enum BounceAction
{
    RemoveFromList,  // リストから削除
    RetryLater,      // 後で再送
    Investigate      // 調査が必要
}

実務でのヒント
上記はあくまで簡易的な例です。実務では 550 のような3桁コードだけでなく、
"550 5.7.26 ..." のような拡張ステータスコードやエラーメッセージ本文も解析すると、
Python でも C# でも同じ分類ロジックで運用できるようになり、より精度が上がります。

重要
5xxでもアドレス削除すべきでないケース

  • 550 5.1.1 User unknown → アドレス自体の問題 → 削除OK
  • 550 5.7.26 DMARC policy → 送信ドメイン認証の問題 → 削除NG(SPF/DKIM/DMARC設定を修正)

認証・ポリシー関連のエラー(5.7.x系)は、アドレスではなく送信側の設定に問題があるケースが多いため、
削除ではなく設定修正で対応しましょう。

バウンスを減らすための予防策

1. ダブルオプトイン

登録時に確認メールを送り、リンクをクリックしてもらうことで、存在するアドレスのみを登録できます。(最近はこの方法が多いですよね)

m004 (1).png

2. 定期的なリストクリーニング

長期間開封がないアドレスは、すでに使われていない可能性が高いです。定期的に確認メールを送り、反応がなければリストから除外しましょう。

3. メールアドレスのバリデーション

登録フォームで基本的な形式チェックを行いましょう。

Python
import re

# 基本的な形式チェック用の正規表現
EMAIL_REGEX = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")

def is_valid_email(email: str) -> bool:
    """メールアドレスの簡易チェック"""
    return bool(EMAIL_REGEX.match(email))


# 使用例
if __name__ == "__main__":
    print(is_valid_email("test@example.com"))   # True
    print(is_valid_email("invalid@@example"))   # False
C#
// 基本的な形式チェック
bool IsValidEmail(string email)
{
    return Regex.IsMatch(email, 
        @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
}

※あくまで簡易チェックなので、厳密なバリデーションが必要な場合は専用ライブラリの利用も検討してください。

4. 送信ドメイン認証の設定

SPF、DKIM、DMARCを正しく設定することで、受信サーバーからの拒否を減らせます。

メール配信サービスの活用

バウンス処理を自前で実装するのは大変です。メール配信サービスを使えば、以下が自動化されます。

  • バウンスの自動検知と分類
  • ハードバウンスアドレスの自動除外
  • レピュテーション管理
  • 詳細なレポート

例えば、blastengineでは、配信結果をAPIで以下のようなステータスが取得できます。

ステータス 意味
SENT 配信成功
HARDERROR ハードエラー(永続的)
SOFTERROR ソフトエラー(一時的)
DROP エラー停止アドレスに合致

これにより、自前でSMTPログを解析する手間が省けます。

まとめ

項目 ハードバウンス ソフトバウンス
エラーの性質 永続的 一時的
エラーコード 5xx系 4xx系
対処法 即座に削除 様子見(5回で削除)
放置のリスク 非常に高い 中程度

覚えておくべきポイント!

  1. 5xx = 削除、4xx = 様子見
  2. バウンス率は2%以下を維持
  3. 放置するとブラックリスト入りのリスク
  4. ダブルオプトインで予防
  5. 配信サービスを使えば自動化できる

バウンスメールは「エラー」ですが、正しく理解して対処すれば、メール配信の品質向上につながる貴重なフィードバックでもあります。ぜひ、メールが戻ってきてしまったら確認してみてください。

参考リンク

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?