# 通知設計書 16-MailerEngagementEvent

## 概要

本ドキュメントは、Symfony RemoteEventコンポーネントにおける `MailerEngagementEvent` イベントの設計仕様を定義する。外部メールサービスプロバイダ（ESP）からのWebhookで受信するメールエンゲージメント（受信者のメール操作）追跡イベントであり、メールの開封・クリック・スパム報告・配信停止等のユーザーアクションを把握するために使用される。

### 本通知の処理概要

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

**業務上の目的・背景**：メール送信後の受信者の行動（開封、リンククリック等）を追跡することは、メールマーケティングの効果測定、ユーザーエンゲージメントの分析、配信停止要求への対応等に不可欠である。MailerEngagementEventにより、ESP固有のWebhookペイロードをSymfonyの統一インターフェースに変換し、プロバイダ非依存のエンゲージメント追跡を実現する。スパム報告や配信停止の検知は、法的コンプライアンス（CAN-SPAM法、GDPR等）の観点からも重要である。

**通知の送信タイミング**：外部ESPがWebhookエンドポイントにHTTPリクエストを送信した際に、RemoteEventコンポーネントのWebhookハンドラーがペイロードをパースし、MailerEngagementEventオブジェクトを生成してディスパッチする。受信者のメール操作が検知されたタイミングで発火する（open: メール開封時、click: リンククリック時、spam: スパム報告時、unsubscribe: 配信停止時）。

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

**通知内容の概要**：エンゲージメント種別（open/click/spam/unsubscribe）、受信者メールアドレス、イベント発生日時、メタデータ、タグ情報を保持する。RemoteEventの基底クラスからイベント名、ID、ペイロードも継承する。

**期待されるアクション**：エンゲージメント種別に応じた後続処理を実行する。openの場合は開封率の集計、clickの場合はクリック率の記録、spamの場合はメールアドレスのブラックリスト登録、unsubscribeの場合は配信停止処理等。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

RemoteEventコンポーネントのConsumerインフラストラクチャを通じて、MailerEngagementEventに対するハンドラー（`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 |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Webhook受信（開封） | ESPが受信者のメール開封を検知 | RemoteEventコンポーネントが設定されていること | 開封トラッキングピクセルの読み込みを検知 |
| Webhook受信（クリック） | ESPが受信者のリンククリックを検知 | RemoteEventコンポーネントが設定されていること | トラッキングリンクのクリックを検知 |
| Webhook受信（スパム報告） | ESPが受信者のスパム報告を検知 | RemoteEventコンポーネントが設定されていること | 受信者がスパムとして報告 |
| Webhook受信（配信停止） | ESPが受信者の配信停止要求を検知 | RemoteEventコンポーネントが設定されていること | 受信者が配信停止リンクをクリック |

### 送信抑止条件

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

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[受信者: メール操作] --> B[ESP: エンゲージメント検知]
    B --> C[ESP: Webhook送信]
    C --> D[Symfony: Webhookエンドポイント受信]
    D --> E[Webhookパーサー: ペイロードパース]
    E --> F[MailerEngagementEvent生成]
    F --> G[エンゲージメント種別に応じた処理分岐]
    G -->|open| H[開封率集計]
    G -->|click| I[クリック率記録]
    G -->|spam| J[ブラックリスト登録]
    G -->|unsubscribe| K[配信停止処理]
```

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

### 参照テーブル一覧

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

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

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし。受信者のメール操作が検知された時点でESPからWebhookが送信される。

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

- Webhookエンドポイントはインターネットに公開されるため、ESP固有の署名検証やIPアドレス制限等のセキュリティ対策が必要
- 受信者メールアドレス（email）は個人情報であるため、ログ出力時のマスキングや保存時の暗号化を考慮すること
- スパム報告（spam）や配信停止（unsubscribe）の受信は法的対応が必要な場合があり、速やかに対応する仕組みを整えること
- 開封トラッキングはプライバシーに関わるため、メールクライアントの画像ブロック等により正確性が保証されない点を考慮すること

## 備考

- MailerEngagementEventは `Symfony\Component\RemoteEvent\Event\Mailer\MailerEngagementEvent` に定義されている
- エンゲージメント種別の定数: OPEN, CLICK, SPAM, UNSUBSCRIBE（行19-22）
- AbstractMailerEventを継承し、date, email, metadata, tagsのプロパティを持つ
- MailerDeliveryEvent（No.15）と異なり、reasonプロパティは持たない
- MailerDeliveryEventが「配信状態」を追跡するのに対し、MailerEngagementEventは「受信者の行動」を追跡する

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 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 | MailerEngagementEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerEngagementEvent.php` | イベント本体。4つのエンゲージメント種別定数（OPEN, CLICK, SPAM, UNSUBSCRIBE）を定義。独自プロパティは持たない（行17-23） |

**読解のコツ**: MailerEngagementEventはMailerDeliveryEventと同じクラス階層を持つが、独自プロパティ（reason等）を追加していない点が特徴的。状態の識別はRemoteEventのnameプロパティと定数で行う。

#### Step 2: MailerDeliveryEventとの比較

姉妹クラスであるMailerDeliveryEventとの構造的な違いを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MailerDeliveryEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/MailerDeliveryEvent.php` | 姉妹クラス。MailerEngagementEventにはないreasonプロパティを持つ。配信状態の定数は5つ（行17-36） |

**主要な違い**:
- MailerDeliveryEvent: 5つの配信状態定数 + reasonプロパティ
- MailerEngagementEvent: 4つのエンゲージメント種別定数のみ

#### Step 3: 基底クラスのプロパティ操作を理解する

AbstractMailerEventが提供するプロパティ操作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractMailerEvent.php | `src/Symfony/Component/RemoteEvent/Event/Mailer/AbstractMailerEvent.php` | 全プロパティのsetterがpublic。Webhookパーサーがイベント生成後にsetterでプロパティを設定する想定（行26-64） |

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

```
ESP (外部サービス)
    |
    +-- 受信者のメール操作を検知
            |
            +-- HTTP Webhook リクエスト
                    |
                    +-- Symfony Webhookエンドポイント
                            |
                            +-- ESP固有Webhookパーサー
                                    |
                                    +-- new MailerEngagementEvent($name, $id, $payload)
                                    |       |
                                    |       +-- setDate($date)
                                    |       +-- setRecipientEmail($email)
                                    |       +-- setMetadata($metadata)
                                    |       +-- setTags($tags)
                                    |
                                    +-- RemoteEventハンドラーへディスパッチ
                                            |
                                            +-- アプリケーション固有の処理
```

### データフロー図

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

受信者のメール操作
  (open/click/spam/           ESP: 操作検知
   unsubscribe)                    |
        |                          +----> Webhook送信
        |                                    |
ESP Webhook -----------> Webhookパーサー
  (HTTP POST)                  |
                               +----> MailerEngagementEvent生成
                               |          |
                               |          +-- name: エンゲージメント種別
                               |          +-- id: イベントID
                               |          +-- email: 受信者
                               |          +-- date: 日時
                               |
                               +----> ハンドラーへ配信
                                          |
                                          +----> 統計集計 / 配信停止 / ブラックリスト
```

### 関連ファイル一覧

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