# 通知設計書 7-BaseMailer#implicit_multipart

## 概要

本ドキュメントは、Rails ActionMailerフレームワークにおけるBaseMailer#implicit_multipartメソッドによるマルチパートメール通知の設計を記述する。

### 本通知の処理概要

BaseMailer#implicit_multipartは、暗黙的なマルチパートメール（テキストとHTMLの両形式を含む）を送信するためのテスト用メーラーメソッドである。複数のテンプレートファイル（.text.erb, .html.erb）を配置することで、ActionMailerが自動的にmultipart/alternativeメールを生成する機能を実証する。

**業務上の目的・背景**：メールクライアントの表示能力に応じて、最適な形式でメールを表示させたい場合に使用される。HTMLをサポートするクライアントではリッチなコンテンツを、テキストのみのクライアントではプレーンテキストを表示できる。本実装はテスト用であり、同名の複数テンプレートによる暗黙的マルチパート生成機能の動作確認を主目的とする。

**通知の送信タイミング**：メーラーメソッドが呼び出された時点で送信される。

**通知の受信者**：デフォルトでは`system@test.lindsaar.net`宛に送信される（BaseMailerのクラスデフォルト設定）。

**通知内容の概要**：2つのテンプレート（implicit_multipart.text.erb, implicit_multipart.html.erb）を使用し、Content-Typeがmultipart/alternativeとなるメールを生成する。オプションで添付ファイルを含めることも可能。

**期待されるアクション**：受信者のメールクライアントは、サポートする形式に応じてHTMLまたはテキストパートを表示する。テスト用途では、複数テンプレートからのマルチパート自動生成が正しく動作することを確認する。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（deliver_now）/ 非同期（deliver_later） |
| 優先度 | 中（デフォルト） |
| リトライ | 配信メソッドに依存 |

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

BaseMailerのクラスデフォルト設定として`system@test.lindsaar.net`が指定されている。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | jose@test.plataformatec.com |
| 送信元名称 | （未設定） |
| 件名 | Implicit multipart（I18nデフォルト） |
| 形式 | multipart/alternative |

### 本文テンプレート

#### HTMLパート（implicit_multipart.html.erb）

```html
HTML Implicit Multipart
```

#### テキストパート（implicit_multipart.text.erb）

```
TEXT Implicit Multipart
```

テンプレートファイル:
- `actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb`
- `actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb`

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| invoice.pdf | application/pdf | attachments: trueオプション指定時 | オプショナルな添付ファイル |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| （なし） | 本テンプレートでは変数を使用しない | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | `BaseMailer.implicit_multipart` メソッド実行 | なし（常に送信） | メーラーメソッドの直接呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| perform_deliveries = false | ActionMailerの設定で配信を無効化している場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[BaseMailer.implicit_multipart 呼び出し] --> B[MessageDelivery オブジェクト生成]
    B --> C[deliver_now/deliver_later 呼び出し]
    C --> D[メーラーインスタンス生成]
    D --> E[implicit_multipart メソッド実行]
    E --> F{attachments オプション?}
    F -->|Yes| G[添付ファイル設定]
    F -->|No| H[mail hash 呼び出し]
    G --> H
    H --> I[テンプレート検索]
    I --> J[.text.erb と .html.erb 両方発見]
    J --> K[各テンプレートをレンダリング]
    K --> L[multipart/alternative 構造生成]
    L --> M{添付ファイルあり?}
    M -->|Yes| N[multipart/mixed でラップ]
    M -->|No| O[Mail::Message 生成]
    N --> O
    O --> P[配信処理]
    P --> Q[終了]
```

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

### 参照テーブル一覧

本メソッドはデータベースを参照しない（テスト用メーラー）。

### 更新テーブル一覧

本メソッドはデータベースを更新しない。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| テンプレート未検出 | implicit_multipart.*テンプレートが1つも存在しない場合 | ActionView::MissingTemplate例外 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | ActiveJob設定に依存（deliver_later使用時） |
| リトライ間隔 | ActiveJob設定に依存 |
| リトライ対象エラー | StandardError |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 設定なし |
| 1日あたり上限 | 設定なし |

### 配信時間帯

制限なし

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

- 両形式で同一の情報を提供し、セキュリティ上の差異がないようにすべき
- HTMLパートにはXSS対策としてコンテンツエスケープを適用
- テスト用メーラーのため、本番環境での使用は非推奨

## 備考

- 暗黙的マルチパートは、ブロックを渡さずにmailメソッドを呼び出すと自動的に動作する
- テンプレートの順序はparts_orderオプションで制御可能（デフォルト: text/plain, text/enriched, text/html）
- 添付ファイルがある場合、multipart/alternativeはmultipart/mixedの中にネストされる
- ロケールに基づいたテンプレート選択も可能（例: implicit_with_locale.pl.text.erb）

---

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

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

### 推奨読解順序

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

暗黙的マルチパートメールのMIME構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | base.rb | `actionmailer/lib/action_mailer/base.rb` | L503-508: parts_orderのデフォルト値 |
| 1-2 | base.rb | `actionmailer/lib/action_mailer/base.rb` | L892-895: マルチパートの並び順設定 |

**読解のコツ**: parts_orderはテンプレートの表示優先順序を定義し、メールクライアントは通常最後のパートを優先表示する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | base_mailer.rb | `actionmailer/test/mailers/base_mailer.rb` | L76-79: implicit_multipartメソッドの実装 |

**主要処理フロー**:
1. **L77**: `attachments["invoice.pdf"] = "..." if hash.delete(:attachments)` - 条件付き添付ファイル設定
2. **L78**: `mail(hash)` - ブロックなしでmailメソッド呼び出し（暗黙的マルチパート）

#### Step 3: テンプレート収集ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | base.rb | `actionmailer/lib/action_mailer/base.rb` | L968-976: collect_responsesメソッド |
| 3-2 | base.rb | `actionmailer/lib/action_mailer/base.rb` | L992-1003: collect_responses_from_templatesメソッド |
| 3-3 | base.rb | `actionmailer/lib/action_mailer/base.rb` | L1005-1012: each_templateメソッド |

**主要処理フロー**:
- **L970-971**: ブロックがない & bodyオプションがない場合、collect_responses_from_templates
- **L996-1002**: 同名の複数テンプレートを検索し、各フォーマットに対してレスポンスを生成
- **L1010**: `templates.uniq(&:format)` - 同一フォーマットの重複を除去

#### Step 4: テストケースで動作を確認する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | base_test.rb | `actionmailer/test/base_test.rb` | L343-351: 暗黙的マルチパートのテスト |
| 4-2 | base_test.rb | `actionmailer/test/base_test.rb` | L363-374: パート順序のテスト |
| 4-3 | base_test.rb | `actionmailer/test/base_test.rb` | L376-384: 添付ファイル付きネスト構造のテスト |

**主要処理フロー**:
- **L344-350**: パート数、Content-Type、各パートの内容検証
- **L365-373**: parts_orderオプションによる順序制御の検証
- **L377-383**: 添付ファイルがある場合のネスト構造検証

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

```
BaseMailer.implicit_multipart(hash)
    │
    ├─ ActionMailer::Base.method_missing
    │      └─ MessageDelivery.new(self, :implicit_multipart, hash)
    │
    └─ MessageDelivery#deliver_now
           │
           ├─ processed_mailer
           │      └─ BaseMailer.new.process(:implicit_multipart, hash)
           │             │
           │             └─ BaseMailer#implicit_multipart(hash)
           │                    │
           │                    ├─ (条件付き) attachments["invoice.pdf"] = "..."
           │                    │
           │                    └─ mail(hash) ← ブロックなし
           │                           │
           │                           ├─ collect_responses(headers)
           │                           │      └─ collect_responses_from_templates
           │                           │             │
           │                           │             └─ each_template
           │                           │                    ├─ implicit_multipart.text.erb
           │                           │                    └─ implicit_multipart.html.erb
           │                           │
           │                           ├─ create_parts_from_responses
           │                           │      └─ 複数レスポンス → マルチパート
           │                           │
           │                           └─ set_content_type
           │                                  └─ multipart/alternative
           │
           └─ message.deliver
```

### データフロー図

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

implicit_multipart.text.erb ───▶ lookup_context.find_all        ───▶ テンプレート配列
implicit_multipart.html.erb      │                                    [text, html]
                                 ▼
                            ───▶ each_template
                                 │
                                 ├─ render(text.erb) → "TEXT Implicit Multipart"
                                 │      └─ {body: "...", content_type: "text/plain"}
                                 │
                                 └─ render(html.erb) → "HTML Implicit Multipart"
                                        └─ {body: "...", content_type: "text/html"}
                                               │
                                               ▼
                            ───▶ create_parts_from_responses     ───▶ multipart/alternative
                                 │                                    ├─ text/plain パート
                                 │                                    └─ text/html パート
                                 ▼
                            ───▶ body.sort_parts!
                                 │
                                 └─ parts_order に従い並び替え
                                      [text/plain, text/html]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| base_mailer.rb | `actionmailer/test/mailers/base_mailer.rb` | ソース | テスト用メーラークラス定義 |
| base.rb | `actionmailer/lib/action_mailer/base.rb` | ソース | 暗黙的マルチパート生成ロジック |
| implicit_multipart.text.erb | `actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb` | テンプレート | テキストパート |
| implicit_multipart.html.erb | `actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb` | テンプレート | HTMLパート |
| base_test.rb | `actionmailer/test/base_test.rb` | テスト | マルチパート機能テスト |
