# 通知設計書 102-service_desk_custom_email_verification_email

## 概要

本ドキュメントは、GitLabのService Deskカスタムメール機能において、カスタムメールアドレスの所有権を検証するために送信される検証メールの設計を記載するものです。

### 本通知の処理概要

本通知は、Service Deskのカスタムメールアドレス設定時に、そのメールアドレスの所有権と転送設定の正しさを検証するために送信されるメールです。

**業務上の目的・背景**：Service Deskではプロジェクト固有のカスタムメールアドレスを設定することで、サポート対応のブランディングを強化できます。この機能を安全に利用するためには、設定されたメールアドレスが正当な所有者によって管理され、メール転送が正しく設定されていることを確認する必要があります。本通知は、その検証プロセスの中核を担います。

**通知の送信タイミング**：`ServiceDesk::CustomEmailVerifications::CreateService`がexecuteされた際に、SMTP設定を使用して同期的に送信されます（56行目: `Notify.service_desk_custom_email_verification_email(settings).deliver`）。同期送信により、SMTP接続エラーを即座に検出できます。

**通知の受信者**：`service_desk_setting.custom_email_address_for_verification`に設定されたメールアドレスです。これは通常、検証用のサブアドレス形式のメールアドレスです。

**通知内容の概要**：自動生成されたメールであること、検証トークンが含まれます。このメールがGitLabのService Deskに正しく転送されることで、所有権と転送設定の検証が完了します。

**期待されるアクション**：このメールは人間が読むためのものではなく、メール転送システムによってGitLabのService Desk受信アドレスに転送されることが期待されます。GitLabシステムが転送されたメールを受信し、トークンを検証することで、設定の正当性が確認されます。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（deliver） - エラー即時検出のため |
| 優先度 | 高 |
| リトライ | なし（同期送信のため呼び出し元でエラーハンドリング） |

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

`service_desk_setting.custom_email_address_for_verification`で取得されるメールアドレスに送信されます。これは設定されたカスタムメールアドレスに検証用のサブアドレスを付加した形式です。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | カスタムメールアドレス（`@service_desk_setting.custom_email`） |
| 送信元名称 | `@service_desk_setting.outgoing_name` |
| 件名 | `Verify custom email address {email} for {project_name}` |
| 形式 | テキスト |

### 本文テンプレート

#### テキスト版（service_desk_custom_email_verification_email.text.erb）
```
This email is auto-generated. It verifies the ownership of the entered Service Desk custom email address and
correct functionality of email forwarding.

Verification token: {verification_token}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 本通知には添付ファイルはありません |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @service_desk_setting | Service Desk設定 | 引数として渡される | Yes |
| @project | 対象プロジェクト | @service_desk_setting.project | Yes |
| @verification_token | 検証トークン | @service_desk_setting.custom_email_verification.token | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作/API | ServiceDesk::CustomEmailVerifications::CreateService.execute | settings.present? かつ admin_project権限あり | カスタムメール検証の開始時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| settings.blank? | Service Desk設定が存在しない場合 |
| !can?(current_user, :admin_project, project) | ユーザーがプロジェクト管理権限を持たない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CustomEmailVerifications::CreateService.execute] --> B{settings存在?}
    B -->|No| C[error_settings_missing]
    B -->|Yes| D{admin_project権限?}
    D -->|No| E[error_user_not_authorized]
    D -->|Yes| F[update_settings]
    F --> G[custom_email_enabled=false]
    G --> H[verification.mark_as_started!]
    H --> I[notify_project_owners_and_user_about_verification_start]
    I --> J[send_verification_email_and_catch_delivery_errors]
    J --> K{SMTPエラー発生?}
    K -->|Yes| L[handle_error_case]
    L --> M[notify_project_owners_and_user_about_result]
    M --> N[verification.mark_as_failed!]
    N --> O[error_not_verified]
    K -->|No| P[log_info]
    P --> Q[ServiceResponse.success]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| service_desk_settings | カスタムメール設定の取得 | |
| service_desk_custom_email_verifications | 検証情報の取得 | |
| service_desk_custom_email_credentials | SMTP認証情報の取得 | |
| projects | プロジェクト情報の取得 | |
| users | Support Botの取得 | |

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

#### service_desk_settings

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| custom_email | カスタムメールアドレス | |
| custom_email_enabled | カスタムメール有効状態 | |
| outgoing_name | 送信者名 | |
| project_id | プロジェクトID | |

#### service_desk_custom_email_verifications

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| token | 検証トークン | WHERE project_id = ? |
| triggerer_id | 検証開始者のユーザーID | |
| state | 検証状態 | |

#### service_desk_custom_email_credentials

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| smtp_address | SMTPサーバーアドレス | |
| smtp_port | SMTPポート | |
| smtp_username | SMTP認証ユーザー名 | |
| smtp_password | SMTP認証パスワード（暗号化） | |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| service_desk_settings | UPDATE | custom_email_enabledをfalseに更新 |
| service_desk_custom_email_verifications | INSERT/UPDATE | 検証レコードの作成・更新 |

#### service_desk_custom_email_verifications

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | state | started | 検証開始時 |
| UPDATE | triggerer_id | current_user.id | 検証開始者 |
| UPDATE | state | failed | エラー発生時 |
| UPDATE | error | エラー種別 | smtp_host_issue, invalid_credentials等 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| settings_missing | Service Desk設定が存在しない | ServiceResponse.errorを返却 |
| user_not_authorized | admin_project権限がない | ServiceResponse.errorを返却 |
| smtp_host_issue | SocketError, SSLError等 | 検証失敗として記録、結果通知送信 |
| invalid_credentials | Net::SMTPAuthenticationError | 検証失敗として記録、結果通知送信 |
| read_timeout | Net::ReadTimeout | 検証失敗として記録、結果通知送信 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 特になし（検証は手動トリガーのため） |
| 1日あたり上限 | 特になし |

### 配信時間帯

特に制限なし（ユーザーの操作に応じて即時送信）

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

- 検証トークンはワンタイムで使用され、検証完了後は無効化される
- SMTP認証情報は暗号化して保存されている
- 検証メールの`Auto-Submitted`ヘッダーは明示的に`no`に設定される（Service Deskが自動生成メールを無視する設定を回避するため）
- カスタムメール設定のSMTP認証情報を使用して直接送信される
- プロジェクトオーナーとトリガーユーザーに検証開始の通知が送信される

## 備考

- 検証プロセスは30分のタイムアウトがある
- 検証メールがService Deskに正しく転送されない場合、`mail_not_received_within_timeframe`エラーとなる
- Fromヘッダーが改変された場合、`incorrect_from`エラーとなる
- 検証トークンが一致しない場合、`incorrect_token`エラーとなる

---

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

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

### 推奨読解順序

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

まず、カスタムメール検証に関連するデータモデルを理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | service_desk_setting.rb | `app/models/service_desk_setting.rb` | カスタムメール関連の属性とアソシエーション |
| 1-2 | custom_email_verification.rb | `app/models/service_desk/custom_email_verification.rb` | 検証状態の管理、トークン生成 |
| 1-3 | custom_email_credential.rb | `app/models/service_desk/custom_email_credential.rb` | SMTP認証情報の管理 |

**読解のコツ**: 検証の状態遷移（started -> finished/failed）を理解することが重要。

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

検証サービスの処理フローを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | create_service.rb | `app/services/service_desk/custom_email_verifications/create_service.rb` | 検証開始の主要ロジック |
| 2-2 | base_service.rb | `app/services/service_desk/custom_email_verifications/base_service.rb` | 共通機能、通知送信 |

**主要処理フロー**:
1. **16-29行目**: executeメソッド - 設定チェック、権限チェック、検証開始
2. **39-45行目**: update_settings - カスタムメール無効化、検証状態更新
3. **47-51行目**: notify_project_owners_and_user_about_verification_start - 開始通知
4. **54-68行目**: send_verification_email_and_catch_delivery_errors - メール送信とエラーハンドリング
5. **76-81行目**: handle_error_case - エラー時の処理

#### Step 3: メーラーを理解する

検証メールの生成処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | service_desk.rb | `app/mailers/emails/service_desk.rb` | service_desk_custom_email_verification_emailメソッド |

**主要処理フロー**:
- **88-117行目**: service_desk_custom_email_verification_email - メール生成
- **92-97行目**: sender設定 - カスタムメールアドレスを使用
- **99行目**: 検証トークンの取得
- **113行目**: Auto-Submittedヘッダーを`no`に設定
- **116行目**: inject_service_desk_custom_email(force: true) - SMTP設定の強制適用

#### Step 4: ビューテンプレートを理解する

メール本文のテンプレートを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | service_desk_custom_email_verification_email.text.erb | `app/views/notify/service_desk_custom_email_verification_email.text.erb` | テキスト形式のメール本文 |

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

```
ServiceDesk::CustomEmailVerifications::CreateService#execute
    │
    ├─ error_settings_missing（settings.blank?の場合）
    │
    ├─ error_user_not_authorized（権限なしの場合）
    │
    ├─ update_settings
    │      ├─ settings.update!(custom_email_enabled: false)
    │      └─ verification.mark_as_started!(current_user)
    │
    ├─ notify_project_owners_and_user_about_verification_start
    │      └─ BaseService#notify_project_owners_and_user_with_email
    │             └─ Notify.service_desk_verification_triggered_email
    │
    └─ send_verification_email_and_catch_delivery_errors
           │
           ├─ Notify.service_desk_custom_email_verification_email(settings)
           │      │
           │      ├─ sender（カスタムメール設定）
           │      │
           │      ├─ @verification_token取得
           │      │
           │      ├─ mail_with_locale
           │      │
           │      └─ inject_service_desk_custom_email(force: true)
           │             └─ mail.delivery_method(::Mail::SMTP, delivery_options)
           │
           ├─ .deliver（同期送信）
           │
           └─ rescue（SMTPエラー捕捉）
                  └─ handle_error_case
                         ├─ notify_project_owners_and_user_about_result
                         └─ verification.mark_as_failed!
```

### データフロー図

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

current_user            ServiceDesk::CustomEmail         検証メール送信
（検証開始者）     ───▶  Verifications::CreateService  ───▶ （カスタムSMTP経由）
                                   │
service_desk_setting        ───▶   │                    ───▶  検証開始通知
（カスタムメール設定）              │                          （プロジェクトオーナーへ）
                                   │
custom_email_credential     ───▶   │                    ───▶  verification状態更新
（SMTP認証情報）                    │                          （started/failed）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| create_service.rb | `app/services/service_desk/custom_email_verifications/create_service.rb` | ソース | 検証開始サービス |
| base_service.rb | `app/services/service_desk/custom_email_verifications/base_service.rb` | ソース | 検証サービス基底クラス |
| service_desk.rb | `app/mailers/emails/service_desk.rb` | ソース | Service Deskメーラー |
| service_desk_custom_email_verification_email.text.erb | `app/views/notify/service_desk_custom_email_verification_email.text.erb` | テンプレート | メール本文テンプレート |
| service_desk_setting.rb | `app/models/service_desk_setting.rb` | ソース | Service Desk設定モデル |
| custom_email_verification.rb | `app/models/service_desk/custom_email_verification.rb` | ソース | 検証状態モデル |
| custom_email_credential.rb | `app/models/service_desk/custom_email_credential.rb` | ソース | SMTP認証情報モデル |
