# 通知設計書 10-個別ユーザーメール送信

## 概要

本ドキュメントは、特定のユーザーに対する個別メール送信機能について、テキスト/HTML両対応のメール送信設計仕様を記載する。

### 本通知の処理概要

本通知は、管理者が特定のユーザー1名に対して、個別にメールを送信するための機能である。

**業務上の目的・背景**：システム管理において、特定のユーザー1名に対して直接連絡を取りたい場面がある。例えば、アカウントに関する個別の問い合わせへの回答、特定ユーザーへの重要なお知らせ、個別のサポート対応などの用途がある。一斉配信（グループ宛・ロール宛）とは異なり、1対1のコミュニケーションを可能にする機能である。

**通知の送信タイミング**：管理画面のメール配信画面（/admin/mail/send）でmail_type='U'のメールに対して送信確認ダイアログを経てconfirm=1でPOSTリクエストした際に送信される。

**通知の受信者**：mail_slaveで指定されたユーザーID（user_id）のユーザー1名。ユーザーのメールフォーマット設定（user_mailformat）に応じてテキスト版またはHTML版が送信される。

**通知内容の概要**：作成されたメール本文（テキスト版またはHTML版、もしくは両方）と添付ファイルが送信される。

**期待されるアクション**：受信者はメール内容を確認し、必要に応じて記載された情報に基づいてアクションを取る。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 中 |
| リトライ | 無 |

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

mail_slaveで指定されたユーザーID（user_id）のユーザーを、Mailモデルの`fetchUsers()`メソッドで取得する。BCCで送信されるため、実際の送信先はBCCフィールドに設定される。

テキスト/HTML両方のメールを送信する場合：
- user_mailformat='text'のユーザーにはテキストメールを送信
- user_mailformat='html'のユーザーにはHTMLメールを送信

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | {registry.site.site.email} |
| 送信元名称 | {registry.site.site.name} |
| 件名 | {mail_subject}（DB登録値） |
| 形式 | テキスト/HTML（メール設定およびユーザー設定に応じて） |
| Toアドレス | {registry.site.site.email}（サイトメールアドレス） |
| To表示名 | {registry.site.site.name}（サイト名） |
| BCC | 対象ユーザーのメールアドレス |

### 本文テンプレート

本文はDB（mailテーブル）に登録された内容がそのまま使用される。テンプレート変数の置換は行われない。

```
{mail_text または mail_html の内容}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| {asset_name}.{asset_extension} | 各種 | メールに添付ファイルが設定されている場合 | Attachmentsモデルで取得した添付ファイル |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| mail_subject | メール件名 | mailテーブル | Yes |
| mail_text | テキスト本文 | mailテーブル | No |
| mail_html | HTML本文 | mailテーブル（html_entity_decodeで変換） | No |
| mail_slave | 送信先ユーザーID | mailテーブル | Yes |
| user_email | ユーザーメールアドレス | usersテーブル | Yes |
| user_alias | ユーザー表示名 | usersテーブル | Yes |
| user_mailformat | ユーザーのメール形式設定 | usersテーブル | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | 送信ボタン押下 | confirm=1かつ管理者権限ありかつメール未送信かつmail_type='U' | 管理画面の/admin/mail/send/id/{id}/confirm/1/にPOST |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 権限不足 | 操作者にmmailまたはmmailsend権限がない場合 |
| メールID未指定 | URLパラメータにidが含まれていない場合 |
| 確認未完了 | confirm=1でない（初回表示時）場合 |
| 送信済みメール | mail_status='sent'の場合 |
| バリデーションエラー | 宛先または件名が未入力の場合 |
| 対象タイプ不一致 | mail_typeが'U'でない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[送信リクエスト] --> B{権限チェック}
    B -->|権限なし| C[権限エラー画面]
    B -->|権限あり| D{confirm=1?}
    D -->|No| E[確認ダイアログ表示]
    D -->|Yes| F{バリデーションチェック}
    F -->|エラー| G[エラーメッセージ表示]
    F -->|成功| H[メール情報取得]
    H --> I[添付ファイル情報取得]
    I --> J{mail_status = sent?}
    J -->|Yes| K[送信済みエラー表示]
    J -->|No| L{mail_type = U?}
    L -->|No| M[他のmail_type処理へ]
    L -->|Yes| N{text/html/両方?}
    N -->|両方あり| O[text/html別々に送信]
    N -->|htmlのみ| P[HTMLメール送信]
    N -->|textのみ| Q[テキストメール送信]
    O --> R[format=textチェック]
    R --> S[テキストメール送信]
    S --> T[format=htmlチェック]
    T --> U[HTMLメール送信]
    P --> V[完了メッセージ表示]
    Q --> V
    U --> V
    C --> W[終了]
    E --> W
    G --> W
    K --> W
    M --> W
    V --> W
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| mail | メール情報取得 | Mailモデル経由 |
| users | 送信対象ユーザー取得 | Mailモデル経由（fetchUsers） |
| assets | 添付ファイル情報取得 | Attachmentsモデル経由 |

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

#### mail

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| mail_id | メール識別 | WHERE mail_id = ? |
| mail_type | 送信タイプ判定 | Mail::fetchMail() |
| mail_slave | 送信先ユーザーID | Mail::fetchMail() |
| mail_subject | メール件名 | Mail::fetchMail() |
| mail_text | テキスト本文 | Mail::fetchMail() |
| mail_html | HTML本文 | Mail::fetchMail() |
| mail_status | 送信ステータス | Mail::fetchMail() |

#### users

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| user_email | 送信先メールアドレス | Mail::fetchUsers(user => ?, format => ?) |
| user_alias | 送信先表示名 | Mail::fetchUsers(user => ?, format => ?) |
| user_id | ユーザー識別 | WHERE user_id = ? |
| user_mailformat | メール形式判定 | WHERE user_mailformat = ? |

#### assets（添付ファイル）

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| asset_file | ファイルパス | Attachments::fetchAttachments(type='M') |
| asset_name | ファイル名 | Attachments::fetchAttachments(type='M') |
| asset_extension | 拡張子 | Attachments::fetchAttachments(type='M') |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| mail | UPDATE | メール内容の更新（送信前に最新内容を保存） |

#### mailテーブル更新

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | mail_slave | フォーム入力値 | 送信先ユーザーID |
| UPDATE | mail_subject | フォーム入力値 | 件名 |
| UPDATE | mail_text | フォーム入力値 | テキスト本文 |
| UPDATE | mail_html | html_entity_decode(フォーム入力値) | HTML本文 |
| UPDATE | mail_date | NOW() | 更新日時 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 権限エラー | mmailまたはmmailsend権限がない | 権限エラー画面（privileges）にフォワード |
| 宛先未入力 | slaveパラメータが空 | エラーメッセージ「To is required」を表示 |
| 件名未入力 | subjectパラメータが空 | エラーメッセージ「Subject is required」を表示 |
| 送信済み | mail_status='sent' | エラーメッセージ「Mail Already Sent!」を表示 |
| メール送信失敗 | SMTP接続エラー等 | Zend_Mailが例外をスロー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

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

### 配信時間帯

配信時間帯の制限は設けられていない。24時間いつでも送信可能。

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

- 管理者権限（mmail + mmailsend）による操作制限あり
- 確認ダイアログによる誤操作防止機能あり
- BCCで送信されるがユーザーは1名のみのため、アドレス漏洩リスクは低い
- Toアドレスにはサイトのメールアドレスが設定され、個人情報は漏洩しない
- 添付ファイルは$syspathからの相対パスで取得されるため、パストラバーサルのリスクに注意
- HTML本文にはhtml_entity_decodeが適用されるため、XSS攻撃のリスクを含む可能性

## 備考

- 本機能はZend Framework 1.x系のZend_Mailコンポーネントを使用している
- テキスト版とHTML版の両方が設定されている場合、ユーザーのメール形式設定に応じて該当する形式のみ送信される
- 添付ファイルはcreateAttachment()で動的に添付される
- 添付ファイルのパスは$registry->assets->assets->syspathから取得される
- 送信設定はレジストリ（`$registry->mail`）で管理されるトランスポート設定に依存する
- 行1098に`$htmlmail`のタイポが存在する（`$textmail`であるべき箇所で`$htmlmail`を使用）

---

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

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

### 推奨読解順序

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

まず、個別ユーザーメール送信に必要なデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mail テーブル | データベース | mail_id, mail_type='U', mail_slave（ユーザーID）, mail_subject, mail_text, mail_html, mail_status の構造 |
| 1-2 | users テーブル | データベース | user_id, user_email, user_alias, user_mailformat の構造 |
| 1-3 | assets テーブル | データベース | asset_file, asset_name, asset_extension の構造 |

**読解のコツ**: mail_type='U'はUser（ユーザー）を意味し、mail_slaveにユーザーIDが格納される。usersテーブルのuser_idとJOINして対象ユーザーを取得する。

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

処理の起点となるコントローラーとアクションを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MailController.php | `application/modules/admin/controllers/MailController.php` | sendAction()メソッドがエントリーポイント |

**主要処理フロー（mail_type='U'の場合）**:
1. **行700**: `sendAction()`メソッド開始
2. **行702**: 権限チェック（mmail AND mmailsend）
3. **行704-705**: レイアウト・ビュー無効化
4. **行707-708**: URLパラメータ取得（confirm, id）
5. **行710**: confirm=1かつID存在チェック
6. **行754-758**: メール情報と添付ファイル情報取得
7. **行763**: mail_status != 'sent'チェック
8. **行765-770**: メール情報更新
9. **行772**: 最新メール情報再取得
10. **行997**: mail_type='U'の分岐開始
11. **行999-1051**: text/html両方ある場合の処理
12. **行1053-1077**: htmlのみの場合の処理
13. **行1079-1105**: textのみの場合の処理

#### Step 3: Mailモデルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Mail.php | `application/models/Mail.php` | fetchUsers(), fetchMail()メソッド |

**主要処理フロー**:
- **行249-264**: fetchUsers() - ユーザーIDおよびフォーマットでユーザー取得
- **行253-254**: user_id条件の適用
- **行270-284**: fetchMail() - メール情報取得

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

```
Admin_MailController::sendAction()
    |
    +-- ACL権限チェック (mmail AND mmailsend)
    |
    +-- URLパラメータ取得 (confirm, id)
    |
    +-- Zend_Filter_Input (バリデーション)
    |
    +-- Mail::fetchMail() (メール情報取得)
    |
    +-- Attachments::fetchAttachments() (添付ファイル取得)
    |
    +-- Mail::updateMail() (メール情報更新)
    |
    +-- mail_type='U' 分岐
        |
        +-- text/html両方の場合
        |   |
        |   +-- Mail::fetchUsers(user, format='text') (テキスト希望チェック)
        |   +-- Zend_Mail (テキストメール送信)
        |   |   +-- setBodyText()
        |   |   +-- setFrom()
        |   |   +-- addTo() (サイトメールアドレス)
        |   |   +-- setSubject()
        |   |   +-- addBcc() (ループ)
        |   |   +-- createAttachment() (ループ)
        |   |   +-- send()
        |   |
        |   +-- Mail::fetchUsers(user, format='html') (HTML希望チェック)
        |   +-- Zend_Mail (HTMLメール送信)
        |       +-- setBodyHtml()
        |       +-- ... (以下同様)
        |
        +-- htmlのみの場合
        |   +-- Mail::fetchUsers(user) (ユーザー取得)
        |   +-- Zend_Mail (HTMLメール送信)
        |
        +-- textのみの場合
            +-- Mail::fetchUsers(user) (ユーザー取得)
            +-- Zend_Mail (テキストメール送信)
```

### データフロー図

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

フォームデータ -------> 権限チェック ----------> エラー/続行判定
(slave, subject,            |
text, html)                 v
                     confirm判定
                           |
              +------------+------------+
              v                          v
         confirm!=1                 confirm=1
         確認ダイアログ              バリデーション
                                        |
                                        v
                                  メール情報取得
                                  添付ファイル取得
                                        |
                                        v
                                  mail_type='U'判定
                                        |
                                        v
                                  対象ユーザー取得
                                  (usersテーブル)
                                        |
                                        v
                                  メール送信 ----------> 対象ユーザー
                                  (BCC形式)              1名
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MailController.php | `application/modules/admin/controllers/MailController.php` | ソース | 個別ユーザーメール送信処理のコントローラー（行997-1105） |
| Mail.php | `application/models/Mail.php` | ソース | メール情報の取得・更新、ユーザー取得モデル |
| Attachments.php | `application/models/Attachments.php` | ソース | 添付ファイル情報の取得モデル |
| CMS_Controller_Action_Admin | `library/CMS/Controller/Action/Admin.php` | ソース | 管理画面コントローラーの基底クラス |
| edit.phtml | `application/modules/admin/views/scripts/mail/edit.phtml` | テンプレート | メール編集画面のビュー |
