# 通知設計書 23-メールボックス処理イベント

## 概要

本ドキュメントは、Ruby on Rails フレームワークにおける `process.action_mailbox` 計装イベント（Instrumentation Event）の仕様を定義する。このイベントは ActionMailbox が受信メールを処理する際に発行される内部計装通知であり、メール受信処理のパフォーマンス監視やデバッグに活用される。

### 本通知の処理概要

`process.action_mailbox` イベントは、ActionMailbox のメールボックスクラスが受信メール（InboundEmail）を処理する際に発行される計装イベントである。

**業務上の目的・背景**：メール駆動型のワークフローを持つアプリケーション（サポートチケットシステム、メール返信機能等）において、受信メールの処理は重要なビジネスプロセスを構成する。このイベントを購読することで、どのメールボックスがどのような受信メールを処理したか、処理にどれだけの時間がかかったか、処理結果（delivered/bounced/failed）を計測・記録できる。これにより、受信メール処理のパフォーマンス監視、処理エラーのトラッキング、およびAPMツールとの連携が可能となる。

**通知の送信タイミング**：メールボックスの `perform_processing` メソッドが呼び出され、受信メールの処理が開始される際に発行される。具体的には、`ActionMailbox::Base#perform_processing` メソッド内で `ActiveSupport::Notifications.instrument` を通じてイベントが発行される。イベントはブロックで囲まれており、メール処理の開始から終了までの時間が計測される。

**通知の受信者**：このイベントは `ActiveSupport::Notifications.subscribe` を使用して購読するサブスクライバーに配信される。アプリケーション開発者やAPMツールが独自のサブスクライバーを登録することで監視が可能となる。

**通知内容の概要**：イベントのペイロードには、処理を行うメールボックスインスタンス（`:mailbox`）と、処理対象の受信メール情報（`:inbound_email`）が含まれる。`:inbound_email` は受信メールのID、メッセージID、処理ステータスを含むハッシュである。

**期待されるアクション**：受信者（サブスクライバー）は、このイベントを使用して受信メール処理のログ記録、メトリクス収集、パフォーマンス監視ダッシュボードへのデータ送信、処理エラーのアラート生成、またはカスタムビジネスロジックの実行を行うことが期待される。

## 通知種別

計装通知（ActiveSupport::Notifications Instrumentation Event）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ブロック実行中にイベント発行） |
| 優先度 | 中（計装イベントとして標準的な優先度） |
| リトライ | なし（計装イベントは一度のみ発行） |

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

`ActiveSupport::Notifications` に登録されているすべてのサブスクライバーに対してブロードキャストされる。サブスクライバーは以下の方法で登録可能：

1. `ActiveSupport::Notifications.subscribe("process.action_mailbox")` - 特定イベントの購読
2. `ActiveSupport::Notifications.subscribe(/action_mailbox/)` - 正規表現による複数イベントの購読
3. `ActiveSupport::Notifications.subscribe(nil)` - すべてのイベントの購読

## 通知テンプレート

### イベントペイロード

| 項目 | 内容 |
|-----|------|
| イベント名 | `process.action_mailbox` |
| 名前空間 | `action_mailbox` |
| ペイロード形式 | Ruby Hash |

### ペイロード構造

```ruby
{
  mailbox: #<RepliesMailbox:0x00007f9f7a8388>,  # メールボックスインスタンス
  inbound_email: {
    id: 1,                                        # InboundEmailのID（Integer）
    message_id: "0CB459E0-0336-41DA-BC88-E6E28C697DDB@37signals.com",  # メッセージID（String）
    status: "processing"                          # 処理ステータス（String）
  }
}
```

### 添付ファイル

該当なし（計装イベントには添付ファイルは含まれない）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| `:mailbox` | メールボックスクラスのインスタンス | `self`（ActionMailbox::Base のサブクラス） | Yes |
| `:inbound_email` | 受信メール情報のハッシュ | `inbound_email.instrumentation_payload` | Yes |

### inbound_email ハッシュの詳細

| キー | 説明 | データ取得元 | 必須 |
|------|------|-------------|-----|
| `:id` | InboundEmailレコードのID | `inbound_email.id` | Yes |
| `:message_id` | メールのMessage-IDヘッダー値 | `inbound_email.message_id` | Yes |
| `:status` | 処理ステータス（pending/processing/delivered/failed/bounced） | `inbound_email.status` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| メソッド呼び出し | 受信メール処理の実行 | 常に送信 | `ActionMailbox::Base#perform_processing` が呼び出されると必ず発行 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | このイベントには送信抑止条件はない。perform_processingメソッドが呼び出されれば必ず発行される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[受信メール到着] --> B[InboundEmail作成]
    B --> C[ルーティングによりメールボックス決定]
    C --> D[Mailbox.receive実行]
    D --> E[perform_processing呼び出し]
    E --> F[instrumentation_payload構築]
    F --> G[ActiveSupport::Notifications.instrument]
    G --> H[process.action_mailboxイベント開始]
    H --> I[ステータスをprocessingに変更]
    I --> J[コールバック実行]
    J --> K[processメソッド実行]
    K --> L{処理結果}
    L -->|正常| M[ステータスをdeliveredに変更]
    L -->|バウンス| N[ステータスをbouncedに変更]
    L -->|エラー| O[ステータスをfailedに変更]
    M --> P[process.action_mailboxイベント終了]
    N --> P
    O --> P
    P --> Q[サブスクライバーへ通知]
    Q --> R[終了]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| action_mailbox_inbound_emails | 受信メール情報の取得 | id, message_id, status等の情報をペイロードに含める |

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

#### action_mailbox_inbound_emails

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | ペイロードの`:id`に使用 | 処理対象のレコード |
| message_id | ペイロードの`:message_id`に使用 | 処理対象のレコード |
| status | ペイロードの`:status`に使用 | 処理対象のレコード |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| action_mailbox_inbound_emails | UPDATE | ステータス更新（processing/delivered/bounced/failed） |

#### ステータス更新詳細

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | status | "processing" | 処理開始時 |
| UPDATE | status | "delivered" | 正常処理完了時 |
| UPDATE | status | "bounced" | バウンス時 |
| UPDATE | status | "failed" | 例外発生時 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| サブスクライバーエラー | サブスクライバー内で例外が発生 | エラーは伝播せず、他のサブスクライバーの処理は継続 |
| processメソッドエラー | メール処理中に例外が発生 | rescue_from で処理されない場合、ステータスを failed に変更し、例外を再スロー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（計装イベント自体にはリトライなし） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

注：メール処理自体のリトライはジョブキューのリトライ機構に依存する。

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（受信メール処理ごとに発行） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（受信メール処理が実行されるタイミングで即座に発行）

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

- ペイロードの `:mailbox` にはメールボックスインスタンスが含まれ、そこから `inbound_email.mail` を通じてメール本文にアクセス可能
- メールの送信元、宛先、件名、本文などには機密情報が含まれる可能性がある
- サブスクライバーでログ出力やメトリクス送信を行う際は、メール内容のマスキングやフィルタリングを検討すること
- `:inbound_email` の `:message_id` は一意識別子として使用できるが、外部からの追跡に使用される可能性があるため、ログの保管・アクセス管理に注意すること

## 備考

- このイベントは ActionMailbox による受信メール処理を計測する
- 処理開始時のステータスは `processing` で、ペイロードにはこのステータスが含まれる
- 処理完了後の最終ステータス（delivered/bounced/failed）は別途 InboundEmail のステータスを確認する必要がある
- `rescue_from` を使用して例外をハンドリングすることで、カスタムエラー処理が可能

---

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

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

### 推奨読解順序

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

まず、イベントのペイロード構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | base.rb | `actionmailbox/lib/action_mailbox/base.rb` | `instrumentation_payload` メソッド（117-122行目）を確認 |
| 1-2 | inbound_email.rb | `actionmailbox/app/models/action_mailbox/inbound_email.rb` | `instrumentation_payload` メソッド（45-51行目）を確認 |

**読解のコツ**: ペイロードは2段階で構築される。`ActionMailbox::Base#instrumentation_payload` が mailbox と inbound_email を含むハッシュを返し、`inbound_email` の値は `InboundEmail#instrumentation_payload` から取得される。

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

処理の起点となるメソッドを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | base.rb | `actionmailbox/lib/action_mailbox/base.rb` | `perform_processing` メソッド（83-94行目）がイベント発行の起点 |

**主要処理フロー**:
1. **83行目**: `perform_processing` メソッドの定義開始
2. **84行目**: `ActiveSupport::Notifications.instrument` によるイベント発行
3. **85-89行目**: ステータス追跡とコールバック実行
4. **90-92行目**: 例外処理（rescue_from での処理）

#### Step 3: ステータス追跡を理解する

InboundEmail のステータスがどのように変化するかを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | base.rb | `actionmailbox/lib/action_mailbox/base.rb` | `track_status_of_inbound_email` メソッド（124-131行目） |

**主要処理フロー**:
- **125行目**: 処理開始時に `processing!` を呼び出し
- **126行目**: ブロックを実行（processメソッド等）
- **127行目**: バウンスでなければ `delivered!` を呼び出し
- **128-130行目**: 例外発生時は `failed!` を呼び出して再スロー

#### Step 4: InboundEmailモデルを理解する

受信メールのモデル構造を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | inbound_email.rb | `actionmailbox/app/models/action_mailbox/inbound_email.rb` | InboundEmailモデルの定義（27-53行目） |

**主要処理フロー**:
- **31行目**: `enum :status` でステータス列挙型を定義（pending/processing/delivered/failed/bounced）
- **45-51行目**: `instrumentation_payload` でid, message_id, statusをハッシュとして返す

#### Step 5: メールボックスの受信処理を理解する

メールボックスがどのように呼び出されるかを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | base.rb | `actionmailbox/lib/action_mailbox/base.rb` | `receive` クラスメソッド（75-77行目） |

**主要処理フロー**:
- **75-77行目**: `receive` はInboundEmailを受け取り、新しいメールボックスインスタンスを生成して `perform_processing` を呼び出す

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

```
ActionMailbox::InboundEmail#route                    # ルーティング開始
    |
    +-- ApplicationMailbox.route(inbound_email)      # ルーティング実行
            |
            +-- RepliesMailbox.receive(inbound_email)  # 対象メールボックスに配信
                    |
                    +-- RepliesMailbox.new(inbound_email)
                    |
                    +-- RepliesMailbox#perform_processing
                            |
                            +-- instrumentation_payload 構築
                            |       |
                            |       +-- InboundEmail#instrumentation_payload
                            |
                            +-- ActiveSupport::Notifications.instrument("process.action_mailbox")
                                    |
                                    +-- track_status_of_inbound_email
                                    |       |
                                    |       +-- inbound_email.processing!
                                    |       +-- run_callbacks :process
                                    |       |       |
                                    |       |       +-- #process メソッド実行
                                    |       |
                                    |       +-- inbound_email.delivered!
                                    |
                                    +-- サブスクライバーへの通知
```

### データフロー図

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

InboundEmail ────────────────┐
                             │
Mailboxインスタンス ─────────┼──▶ ActionMailbox::Base#perform_processing
                             │           │
                             │           ▼
                             │   instrumentation_payload構築
                             │           │
                             │           ▼
                             │   ActiveSupport::Notifications.instrument
                             │           │
                             │           ├──▶ ステータス変更 (processing)
                             │           │
                             │           ├──▶ コールバック実行
                             │           │
                             │           ├──▶ #process メソッド実行
                             │           │
                             │           └──▶ ステータス変更 (delivered/bounced/failed)
                             │
                             └──▶ process.action_mailbox イベント
                                          │
                                          ▼
                             ┌───────────────────────────────────┐
                             │     サブスクライバー               │
                             │  - カスタムサブスクライバー        │ ──▶ ログ/メトリクス
                             │  - APMツール                      │ ──▶ パフォーマンス監視
                             └───────────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| base.rb | `actionmailbox/lib/action_mailbox/base.rb` | ソース | メールボックス基底クラス、イベント発行元 |
| inbound_email.rb | `actionmailbox/app/models/action_mailbox/inbound_email.rb` | ソース | 受信メールモデル、ペイロード生成 |
| callbacks.rb | `actionmailbox/lib/action_mailbox/callbacks.rb` | ソース | メールボックスコールバック定義 |
| routing.rb | `actionmailbox/lib/action_mailbox/routing.rb` | ソース | メールルーティング機能 |
| active_support_instrumentation.md | `guides/source/active_support_instrumentation.md` | ドキュメント | 公式計装ガイド（343-364行目） |
| notifications_test.rb | `actionmailbox/test/unit/mailbox/notifications_test.rb` | テスト | イベント発行のテスト |
