# 通知設計書 9-ロール別メール配信

## 概要

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

### 本通知の処理概要

本通知は、管理者が特定のユーザーロール（役割）に属するユーザー全員に対して、メールを一斉配信するための機能である。

**業務上の目的・背景**：システム内のユーザーは役割（ロール）によって分類されており、特定の役割を持つユーザー群に対して一斉に情報を配信したい場面がある。例えば、管理者ロールのユーザーにのみシステムメンテナンス通知を送る、編集者ロールのユーザーにのみコンテンツガイドラインの更新を通知するなどの用途がある。ロール別配信により、対象者を明確に絞り込んだ効率的なコミュニケーションが可能になる。

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

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

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

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

## 通知種別

メール

## 送信仕様

### 基本情報

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

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

mail_slaveで指定されたユーザーロール（user_role）に属するユーザーを、Mailモデルの`fetchUsers()`メソッドで取得する。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='R' | 管理画面の/admin/mail/send/id/{id}/confirm/1/にPOST |

### 送信抑止条件

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

## 処理フロー

### 送信フロー

```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 = R?}
    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(role => ?, format => ?) |
| user_alias | 送信先表示名 | Mail::fetchUsers(role => ?, format => ?) |
| user_role | ロール判定 | WHERE user_role = ? |
| 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で送信されるため受信者同士のメールアドレスは非公開
- Toアドレスにはサイトのメールアドレスが設定され、個人情報は漏洩しない
- 添付ファイルは$syspathからの相対パスで取得されるため、パストラバーサルのリスクに注意
- HTML本文にはhtml_entity_decodeが適用されるため、XSS攻撃のリスクを含む可能性

## 備考

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

---

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

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

### 推奨読解順序

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

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

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

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

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

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

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

**主要処理フロー（mail_type='R'の場合）**:
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. **行887**: mail_type='R'の分岐開始
11. **行889-942**: text/html両方ある場合の処理
12. **行943-967**: htmlのみの場合の処理
13. **行969-995**: textのみの場合の処理

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

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

**主要処理フロー**:
- **行249-264**: fetchUsers() - ロールおよびフォーマットでユーザー取得
- **行270-284**: fetchMail() - メール情報取得

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

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

### データフロー図

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

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

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MailController.php | `application/modules/admin/controllers/MailController.php` | ソース | ロール別メール送信処理のコントローラー（行887-995） |
| 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` | テンプレート | メール編集画面のビュー |
