# 機能設計書 42-Mime

## 概要

本ドキュメントは、Symfony Mimeコンポーネントの機能設計を記述する。MimeはMIME（Multipurpose Internet Mail Extensions）メッセージの構築・操作機能を提供し、メール本文、添付ファイル、マルチパート構成のオブジェクト指向的な操作を実現するコンポーネントである。

### 本機能の処理概要

Mimeコンポーネントは、RFC準拠のMIMEメッセージをオブジェクト指向APIで構築・操作する機能を提供する。Emailクラスを中心とした流暢なAPIにより、テキスト・HTML本文、添付ファイル、インライン画像、ヘッダー、アドレス管理等のメール構成要素を統合的に操作できる。

**業務上の目的・背景**：メール送信においては、MIME仕様に準拠したメッセージ構造の構築が不可欠である。テキストとHTMLのマルチパート構成、添付ファイル、インライン画像の埋め込み、適切なヘッダー設定など、複雑なMIME構造をプログラム的に正確に構築するには専用のライブラリが必要となる。MimeコンポーネントはMailerコンポーネントやNotifierコンポーネントの基盤として機能する。

**機能の利用シーン**：メール送信時のメッセージ構築、MIME形式のコンテンツタイプ判定、メールアドレスのRFC準拠バリデーション、DKIM署名対応のメッセージ生成、テンプレートベースのメール作成等。

**主要な処理内容**：
1. Email/Messageオブジェクトの生成とフルーエントAPI操作
2. テキスト本文・HTML本文のマルチパート構成自動生成
3. 添付ファイル・インライン画像の追加と適切なMIME構造への変換
4. MIMEヘッダー（From、To、Cc、Bcc、Subject等）の管理
5. メールアドレスのRFC 2822準拠バリデーション
6. MIMEタイプの推測（FileinfoMimeTypeGuesser、FileBinaryMimeTypeGuesser）
7. メッセージID生成とDKIM署名対応

**関連システム・外部連携**：Mailerコンポーネント（メール送信）、Notifierコンポーネント（メール通知）、Twig Bridge（テンプレートメール）と連携する。egulias/email-validatorパッケージに依存してメールアドレスのバリデーションを行う。

**権限による制御**：Mimeコンポーネント自体には権限制御機構はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 30 | メーラーパネル | 参照画面 | MIMEメッセージの構造（ヘッダー、本文、添付ファイル）の表示 |
| 54 | メール通知（HTML - デフォルト） | 結果表示画面 | MIMEメッセージとしてのHTMLメール本文構成 |
| 55 | メール通知（テキスト - デフォルト） | 結果表示画面 | MIMEメッセージとしてのテキストメール本文構成 |
| 56 | メール通知（HTML - Zurb 2） | 結果表示画面 | MIMEメッセージとしてのHTMLメール本文構成 |
| 57 | メール通知（テキスト - Zurb 2） | 結果表示画面 | MIMEメッセージとしてのテキストメール本文構成 |

## 機能種別

データ構築 / メッセージング基盤

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| subject | string | No | メールの件名 | - |
| from | Address\|string | Yes（送信時） | 送信者アドレス | RFC 2822準拠 |
| to | Address\|string | Yes（送信時） | 宛先アドレス | RFC 2822準拠 |
| cc | Address\|string | No | CCアドレス | RFC 2822準拠 |
| bcc | Address\|string | No | BCCアドレス | RFC 2822準拠 |
| text | string\|resource | No | テキスト本文 | - |
| html | string\|resource | No | HTML本文 | - |
| attachments | DataPart[] | No | 添付ファイル | - |
| priority | int | No | 優先度（1-5） | 1(最高)〜5(最低) |

### 入力データソース

- アプリケーションコードからのEmailオブジェクト生成
- Twigテンプレートからのレンダリング結果（Twig Bridge経由）
- ファイルシステムからの添付ファイル読み込み

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| toString | string | MIME形式のメッセージ文字列 |
| toIterable | iterable | ストリーミング対応のメッセージイテレータ |
| Headers | Headers | 準備済みヘッダー（Message-ID、MIME-Version等を含む） |
| Body | AbstractPart | MIMEパート構造（multipart/mixed、multipart/alternative等） |

### 出力先

- Mailerコンポーネント（SMTP送信）
- Notifierコンポーネント（メール通知チャネル）
- WebProfilerBundleメーラーパネル（デバッグ時）

## 処理フロー

### 処理シーケンス

```
1. Emailオブジェクトの生成
   └─ Headers、Body(AbstractPart)の初期化
2. フルーエントAPIによるメッセージ構成
   └─ from()、to()、subject()、text()、html()、attach()等
3. getBody()呼び出し時にMIME構造の自動生成（generateBody）
   └─ prepareParts()で添付ファイルとインライン画像を分離
   └─ TextPart(text) + TextPart(html) = AlternativePart
   └─ AlternativePart + インライン画像 = RelatedPart
   └─ RelatedPart + 添付ファイル = MixedPart
4. getPreparedHeaders()でヘッダーの最終準備
   └─ From未設定時はSenderから補完
   └─ MIME-Version、Date、Message-IDの自動追加
   └─ Bccヘッダーの除去
5. toString()またはtoIterable()で最終出力
```

### フローチャート

```mermaid
flowchart TD
    A[Email生成] --> B[from/to/subject設定]
    B --> C[text/html本文設定]
    C --> D{添付ファイルあり?}
    D -->|Yes| E[attach/embed]
    D -->|No| F[getBody呼び出し]
    E --> F
    F --> G[generateBody]
    G --> H[prepareParts]
    H --> I{テキスト+HTML?}
    I -->|Yes| J[AlternativePart生成]
    I -->|No| K[単一Part]
    J --> L{インライン画像あり?}
    K --> L
    L -->|Yes| M[RelatedPart生成]
    L -->|No| N{添付ファイルあり?}
    M --> N
    N -->|Yes| O[MixedPart生成]
    N -->|No| P[最終Part]
    O --> P
    P --> Q[getPreparedHeaders]
    Q --> R[toString/toIterable]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-42-01 | メール本文必須 | text、html、添付ファイル、またはBodyのいずれかが設定されていなければならない | ensureBodyValid()時 |
| BR-42-02 | 送信者必須 | FromまたはSenderヘッダーが必須 | ensureValidity()時 |
| BR-42-03 | 宛先必須 | To、Cc、Bccのいずれかが必須 | ensureValidity()時 |
| BR-42-04 | ドラフト送信不可 | X-Unsentが"1"の場合は送信できない | ensureValidity()時 |
| BR-42-05 | 優先度範囲制限 | priorityは1〜5の範囲に制限される | priority()設定時 |
| BR-42-06 | インライン画像CID置換 | HTML中のcid:参照はDataPartのContentIdに自動置換される | prepareParts()実行時 |

### 計算ロジック

メッセージIDの生成: `bin2hex(random_bytes(16))` + Senderアドレスの"@"以降を連結（**Message.php 151行目**）

## データベース操作仕様

Mimeコンポーネントはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | LogicException | 本文（text/html/attachments/body）がすべて未設定 | text()またはhtml()で本文を設定する |
| - | LogicException | From/Senderヘッダーが未設定 | from()またはsender()を設定する |
| - | LogicException | To/Cc/Bccがすべて未設定 | to()、cc()、bcc()のいずれかを設定する |
| - | LogicException | X-Unsentが"1"のメッセージを送信しようとした場合 | DraftEmailを使用しない |
| - | RfcComplianceException | メールアドレスがRFC 2822に準拠していない | 正しいメールアドレス形式を使用する |
| - | LogicException | EmailValidatorクラスが未インストール | composer require egulias/email-validatorを実行する |

### リトライ仕様

Mimeコンポーネントはメッセージ構築のみを担当するため、リトライ仕様はない。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- cachedBody機構により、同一Emailオブジェクトのbody生成が複数回行われることを防止する
- RawMessageのtoIterable()でストリーミング対応し、大きなメッセージのメモリ使用量を抑制する

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

- Bccヘッダーは`getPreparedHeaders()`で自動除去される（**Message.php 101行目**）
- メールアドレスはegulias/email-validatorでRFC準拠バリデーションされる
- IDN（国際化ドメイン名）エンコーディングに対応

## 備考

- Emailクラスの継承クラスとしてDraftEmailが存在する（X-Unsentヘッダー付き）
- Crypto名前空間でSMime暗号化・署名機能を提供
- MimeTypes.phpでMIMEタイプとファイル拡張子のマッピングを管理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Address.php | `src/Symfony/Component/Mime/Address.php` | メールアドレスの表現とRFC準拠バリデーション |
| 1-2 | RawMessage.php | `src/Symfony/Component/Mime/RawMessage.php` | メッセージの最も基本的な表現（文字列/リソース/イテレータ） |
| 1-3 | Message.php | `src/Symfony/Component/Mime/Message.php` | Headers + AbstractPartによるMIMEメッセージ構造 |

**読解のコツ**: RawMessage -> Message -> Email という継承階層を理解することが重要。Address.phpの`FROM_STRING_PATTERN`（**34行目**）は"Name \<email\>"形式の文字列パースに使用される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Email.php | `src/Symfony/Component/Mime/Email.php` | メール構築のメインAPI |

**主要処理フロー**:
1. **61-69行目**: subject()でSubjectヘッダー設定
2. **113-128行目**: from()で送信者アドレス設定（最低1アドレス必須）
3. **270-281行目**: text()でテキスト本文設定（cachedBodyをnullリセット）
4. **301-312行目**: html()でHTML本文設定
5. **332-335行目**: attach()で添付ファイル追加
6. **382-389行目**: getBody()でbody自動生成（cachedBody利用）
7. **429-461行目**: generateBody()でMIME構造自動組立

#### Step 3: MIME構造生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Email.php (generateBody) | `src/Symfony/Component/Mime/Email.php` | **429-461行目**: text/html/添付からMixedPart/RelatedPart/AlternativePartを組み立てるロジック |
| 3-2 | Email.php (prepareParts) | `src/Symfony/Component/Mime/Email.php` | **463-510行目**: インライン画像のCID参照解析と添付ファイルの分類 |

**主要処理フロー**:
- **437-446行目**: TextPartとHTMLPartからAlternativePartを生成
- **448-450行目**: インライン画像がある場合はRelatedPartで包む
- **452-458行目**: 添付ファイルがある場合はMixedPartで包む
- **472-481行目**: HTMLからcid:参照を正規表現で抽出

#### Step 4: ヘッダー準備を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Message.php (getPreparedHeaders) | `src/Symfony/Component/Mime/Message.php` | **72-104行目**: 送信用ヘッダーの最終準備 |

**主要処理フロー**:
- **76-81行目**: Fromが未設定の場合Senderから補完
- **83-85行目**: MIME-Versionヘッダー自動追加
- **87-89行目**: Dateヘッダー自動追加
- **96-98行目**: Message-ID自動生成
- **101行目**: Bccヘッダー除去

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

```
Email（ユーザーAPI）
    |
    ├─ from() / to() / cc() / bcc()
    |      └─ Address::create() → RFC バリデーション
    |
    ├─ subject() / text() / html()
    |      └─ Headers::setHeaderBody()
    |
    ├─ attach() / embed()
    |      └─ DataPart / File
    |
    ├─ getBody()
    |      └─ generateBody()
    |             ├─ prepareParts()
    |             |      └─ cid:参照の正規表現マッチング
    |             ├─ TextPart (text/plain)
    |             ├─ TextPart (text/html)
    |             ├─ AlternativePart (text + html)
    |             ├─ RelatedPart (+ inline images)
    |             └─ MixedPart (+ attachments)
    |
    └─ toString() / toIterable()
           └─ getPreparedHeaders() + body.toString()
```

### データフロー図

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

from/to/cc/bcc       Email オブジェクト              MIME文字列
  (Address)          ├─ Headers管理                  (toString)
                     ├─ Body構築                      |
subject/text/html    |   ├─ AlternativePart          MIME iterable
  (string/resource)  |   ├─ RelatedPart              (toIterable)
                     |   └─ MixedPart
attachments          └─ getPreparedHeaders            Headers
  (DataPart/File)        ├─ MIME-Version追加           (準備済み)
                         ├─ Date追加
                         ├─ Message-ID生成
                         └─ Bcc除去
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Email.php | `src/Symfony/Component/Mime/Email.php` | ソース | メール構築のメインクラス |
| Message.php | `src/Symfony/Component/Mime/Message.php` | ソース | MIMEメッセージ基底クラス |
| RawMessage.php | `src/Symfony/Component/Mime/RawMessage.php` | ソース | 生メッセージ基底クラス |
| Address.php | `src/Symfony/Component/Mime/Address.php` | ソース | メールアドレス表現 |
| DraftEmail.php | `src/Symfony/Component/Mime/DraftEmail.php` | ソース | ドラフトメール |
| MimeTypes.php | `src/Symfony/Component/Mime/MimeTypes.php` | ソース | MIMEタイプ推測 |
| MessageConverter.php | `src/Symfony/Component/Mime/MessageConverter.php` | ソース | メッセージ変換ユーティリティ |
| Header/ | `src/Symfony/Component/Mime/Header/` | ソース | MIMEヘッダー管理 |
| Part/ | `src/Symfony/Component/Mime/Part/` | ソース | MIMEパート構造（TextPart、DataPart等） |
| Encoder/ | `src/Symfony/Component/Mime/Encoder/` | ソース | エンコーディング処理 |
| Crypto/ | `src/Symfony/Component/Mime/Crypto/` | ソース | SMime暗号化・署名 |
