# 通知設計書 15-MailerDeliveryEvent

## 概要

本ドキュメントは、Symfony RemoteEventコンポーネントにおける `MailerDeliveryEvent` イベントの設計仕様を定義する。外部メールサービスプロバイダ（ESP）からのWebhookで受信するメール配信状態の追跡イベントであり、メールが受信者に到達したかどうかを把握するために使用される。

### 本通知の処理概要

MailerDeliveryEventは、RemoteEventコンポーネントが提供するメール配信追跡用のイベントクラスである。外部メールサービスプロバイダ（SendGrid、Mailgun、Postmark等）からWebhookで送信される配信ステータス情報を、Symfony内部のイベントオブジェクトとして統一的に扱うための抽象化レイヤーを提供する。

**業務上の目的・背景**：メール送信後の配信状態を追跡することは、メールマーケティング、トランザクションメール、業務通知等の信頼性確保に不可欠である。メールが実際に受信者のメールボックスに到達したか、バウンスしたか、遅延しているかを把握することで、コミュニケーションの品質管理とトラブルシューティングが可能になる。MailerDeliveryEventはESP固有のWebhookペイロードをSymfonyの統一インターフェースに変換し、プロバイダ非依存の配信追跡を実現する。

**通知の送信タイミング**：外部ESPがWebhookエンドポイントにHTTPリクエストを送信した際に、RemoteEventコンポーネントのWebhookハンドラーがペイロードをパースし、MailerDeliveryEventオブジェクトを生成してディスパッチする。配信状態の種類に応じて異なるタイミングで発火する（received: 受信直後、delivered: 配信完了時、bounce: バウンス検知時等）。

**通知の受信者**：RemoteEventコンポーネントのConsumer/Handlerを通じて、アプリケーション内のイベントリスナーやWebhookハンドラーが受信する。

**通知内容の概要**：配信状態（received/dropped/delivered/deferred/bounce）、受信者メールアドレス、イベント発生日時、配信失敗理由（reason）、メタデータ、タグ情報を保持する。RemoteEventの基底クラスからイベント名、ID、ペイロードも継承する。

**期待されるアクション**：配信状態に応じた後続処理を実行する。例えば、bounceの場合はメールアドレスの無効化、deferredの場合は配信遅延の監視、deliveredの場合は配信確認の記録等。

## 通知種別

Webhookイベント通知（外部ESPからのHTTP Webhook経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（外部ESPからのWebhook受信をトリガーとする） |
| 優先度 | 中（配信状態の追跡） |
| リトライ | ESP側のWebhookリトライ仕様に依存 |

### 送信先決定ロジック

RemoteEventコンポーネントのConsumerインフラストラクチャを通じて、MailerDeliveryEventに対するハンドラー（`RemoteEventHandlerInterface` 実装）にイベントが配信される。

## 通知テンプレート

### メール通知の場合

本イベントはメール通知ではなく、メール配信状態の追跡イベントであるため、メールテンプレートは適用されない。

### 本文テンプレート

```
該当なし（Webhookペイロードから生成されるイベントオブジェクト）
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| 該当なし | - | - | イベントオブジェクトのため添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| name | イベント名 | RemoteEvent::getName() | Yes |
| id | イベントID | RemoteEvent::getId() | Yes |
| payload | Webhookペイロード | RemoteEvent::getPayload() | Yes |
| date | イベント発生日時 | AbstractMailerEvent::getDate() | Yes |
| email | 受信者メールアドレス | AbstractMailerEvent::getRecipientEmail() | Yes |
| metadata | メタデータ | AbstractMailerEvent::getMetadata() | No |
| tags | タグ情報 | AbstractMailerEvent::getTags() | No |
| reason | 配信失敗理由 | MailerDeliveryEvent::getReason() | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Webhook受信 | ESPからの配信ステータスWebhook | RemoteEventコンポーネントが設定されていること | ESPがメール配信状態の変更を通知した際 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| Webhookエンドポイント未設定 | RemoteEventコンポーネントのWebhook受信が設定されていない場合 |
| ESP側のWebhook無効 | ESPの管理画面でWebhook送信が無効化されている場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ESP: メール配信状態変更] --> B[ESP: Webhook送信]
    B --> C[Symfony: Webhookエンドポイント受信]
    C --> D[Webhookパーサー: ペイロードパース]
    D --> E[MailerDeliveryEvent生成]
    E --> F[状態に応じた処理分岐]
    F -->|received| G[受信記録]
    F -->|delivered| H[配信完了記録]
    F -->|bounce| I[バウンス処理]
    F -->|dropped| J[ドロップ記録]
    F -->|deferred| K[遅延監視]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| 該当なし | - | RemoteEventコンポーネント自体はDB参照を行わない |

### テーブル別参照項目詳細

該当なし。MailerDeliveryEventはイベントオブジェクトであり、データベースアクセスはハンドラー側の実装に依存する。

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| 該当なし | - | ハンドラー側で必要に応じてDB更新を実装 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Webhookパースエラー | ESPからのペイロードが不正な形式 | Webhookパーサー側でバリデーション、エラーレスポンス返却 |
| ハンドラー内例外 | イベントハンドラー内で例外が発生 | ハンドラーの標準動作に従い伝播 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | ESP側のWebhookリトライ仕様に依存 |
| リトライ間隔 | ESP側の設定に依存 |
| リトライ対象エラー | HTTP 5xxレスポンス時（一般的） |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | ESP側の設定に依存 |
| 1日あたり上限 | ESP側の設定に依存 |

### 配信時間帯

制限なし。ESPが配信状態を検知した時点でWebhookが送信される。

## セキュリティ考慮事項

- Webhookエンドポイントはインターネットに公開されるため、ESP固有の署名検証やIPアドレス制限等のセキュリティ対策が必要
- 受信者メールアドレス（email）は個人情報であるため、ログ出力時のマスキングや保存時の暗号化を考慮すること
- Webhookペイロードの改ざん防止のため、HMAC署名検証等を実装すること

## 備考

- MailerDeliveryEventは `Symfony\Component\RemoteEvent\Event\Mailer\MailerDeliveryEvent` に定義されている
- 配信状態の定数: RECEIVED, DROPPED, DELIVERED, DEFERRED, BOUNCE（行19-23）
- AbstractMailerEventを継承し、date, email, metadata, tagsのプロパティを持つ
- RemoteEventを基底クラスとし、name, id, payloadのプロパティも持つ
- 関連クラスとして `MailerEngagementEvent`（No.16）がある

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

MailerDeliveryEventのクラス階層と保持するデータの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | RemoteEvent.php | `src/Symfony/Component/RemoteEvent/RemoteEvent.php` | 基底クラス。name, id, payloadの3つのreadonlyプロパティをコンストラクタで受け取る（行17-40） |
| 1-2 | AbstractMailerEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/AbstractMailerEvent.php` | 中間抽象クラス。date, email, metadata, tagsの4プロパティとそのgetter/setterを定義（行19-65） |
| 1-3 | MailerDeliveryEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerDeliveryEvent.php` | イベント本体。5つの配信状態定数（RECEIVED, DROPPED, DELIVERED, DEFERRED, BOUNCE）とreasonプロパティを定義（行17-36） |

**読解のコツ**: クラス階層が3段あるため、RemoteEvent -> AbstractMailerEvent -> MailerDeliveryEventの順に読むことで、各層で追加されるプロパティを理解しやすい。

#### Step 2: エントリーポイントを理解する

MailerDeliveryEventの生成元を理解する。イベントの生成はESP固有のWebhookパーサーで行われる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MailerDeliveryEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerDeliveryEvent.php` | setReason()/getReason()メソッド（行27-35）で配信失敗理由を設定・取得 |

**主要処理フロー**:
1. ESP固有のWebhookパーサーがHTTPリクエストを受信
2. ペイロードをパースしてMailerDeliveryEventを生成
3. 配信状態に応じた定数を使用して状態を設定
4. bounce/droppedの場合はsetReason()で失敗理由を設定
5. setDate(), setRecipientEmail(), setMetadata(), setTags()で各プロパティを設定

#### Step 3: 関連イベントクラスを理解する

同じ階層構造を持つMailerEngagementEventとの関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | MailerEngagementEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerEngagementEvent.php` | 姉妹クラス。配信後のユーザーアクション（open, click, spam, unsubscribe）を追跡する（行17-23） |

### プログラム呼び出し階層図

```
ESP (外部サービス)
    |
    +-- HTTP Webhook リクエスト
            |
            +-- Symfony Webhookエンドポイント
                    |
                    +-- ESP固有Webhookパーサー
                            |
                            +-- new MailerDeliveryEvent($name, $id, $payload)
                            |       |
                            |       +-- setDate($date)
                            |       +-- setRecipientEmail($email)
                            |       +-- setReason($reason)  [bounce/dropped時]
                            |       +-- setMetadata($metadata)
                            |       +-- setTags($tags)
                            |
                            +-- RemoteEventハンドラーへディスパッチ
                                    |
                                    +-- アプリケーション固有の処理
```

### データフロー図

```
[入力]                          [処理]                              [出力]

ESP Webhook ---------> Webhookパーサー
  (HTTP POST)              |
                           +----> MailerDeliveryEvent生成
                           |          |
                           |          +-- name: イベント名
                           |          +-- id: イベントID
                           |          +-- payload: 元ペイロード
                           |          +-- date: 日時
                           |          +-- email: 受信者
                           |          +-- reason: 失敗理由
                           |          +-- metadata: メタデータ
                           |          +-- tags: タグ
                           |
                           +----> ハンドラーへ配信
                                      |
                                      +----> DB更新 / ログ / 通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MailerDeliveryEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerDeliveryEvent.php` | ソース | イベントクラス本体 |
| AbstractMailerEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/AbstractMailerEvent.php` | ソース | メーラーイベント抽象基底クラス |
| RemoteEvent.php | `src/Symfony/Component/RemoteEvent/RemoteEvent.php` | ソース | リモートイベント基底クラス |
| MailerEngagementEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerEngagementEvent.php` | ソース | 姉妹クラス（エンゲージメント追跡） |
