# 테넌트 이메일 연동 가이드

> **작성일**: 2026-03-11
> **상태**: 설계 확정
> **관련 정책**: [이메일 발송 정책](../standards/email-policy.md)

---

## 1. 개요

### 1.1 목적

SAM 멀티테넌시 환경에서 각 테넌트(회사)가 사용하는 다양한 메일 시스템을 SAM과 연동하는 방법을 정의한다.
**본사(코드브릿지엑스)가 MNG 관리 화면에서 각 테넌트의 메일 설정을 대행 관리**하는 방식으로 운영한다.

### 1.2 핵심 원칙

| 원칙 | 설명 |
|------|------|
| 🔴 본사 중앙 관리 | 테넌트 메일 설정은 MNG 관리자(본사)가 등록/수정한다 |
| 🔴 프리셋 기반 | 주요 메일 제공자별 SMTP 프리셋을 제공하여 설정 오류를 방지한다 |
| 🟡 연결 테스트 필수 | 설정 저장 전 SMTP 연결 테스트를 통과해야 한다 |
| 🟡 단계적 확장 | 플랫폼 발송(Phase 1) → SMTP 릴레이(Phase 2) → OAuth2(Phase 3) |
| 🟢 가이드 제공 | 테넌트에게 앱 비밀번호 생성 등 사전 준비 절차를 안내한다 |

### 1.3 운영 모델

```
본사 (코드브릿지엑스)                    테넌트 (고객사)
┌────────────────────────┐              ┌────────────────────────┐
│  MNG 관리 화면          │              │                        │
│  ├── 테넌트 목록        │   SMTP 정보  │  기존 메일 시스템       │
│  ├── 메일 설정 등록     │ ←──── 전달 ──│  (Gmail, Naver 등)     │
│  ├── SMTP 프리셋 선택   │              │                        │
│  ├── 연결 테스트        │              │  앱 비밀번호 생성       │
│  └── 발송 현황 모니터링 │              │  (본사 안내에 따라)     │
└────────────────────────┘              └────────────────────────┘
```

> **테넌트는 MNG에 접근하지 않는다.** 본사 관리자가 테넌트로부터 SMTP 정보를 전달받아 MNG에서 설정한다.

---

## 2. 테넌트 메일 환경 현황

### 2.1 한국 기업 메일 시스템 분류

| 유형 | 주로 사용하는 메일 | 예시 도메인 | 비율 (추정) |
|------|-------------------|------------|------------|
| 포털 메일 | 네이버, 다음 | `ceo@naver.com` | 소기업 30% |
| 호스팅 메일 | 카페24, 가비아 | `admin@company.co.kr` | 중소기업 25% |
| Google Workspace | Gmail 인프라 | `hong@company.com` | 중소~중견 20% |
| 네이버웍스 | 네이버 인프라 | `hong@company.com` | 중소기업 15% |
| Microsoft 365 | Exchange/Outlook | `hong@company.co.kr` | 중견~대기업 8% |
| 자체 메일 서버 | On-premise | `hong@company.com` | 대기업 2% |

### 2.2 메일 제공자별 SMTP 정보

| 제공자 | SMTP 호스트 | 포트 | 암호화 | 인증 방식 | 일일 한도 |
|--------|------------|------|--------|----------|----------|
| Gmail / Google Workspace | `smtp.gmail.com` | 587 | TLS | 앱 비밀번호 | 500건 (무료) / 2,000건 (Workspace) |
| 네이버 | `smtp.naver.com` | 587 | TLS | 앱 비밀번호 | 500건 |
| 네이버웍스 | `smtp.worksmobile.com` | 587 | TLS | 앱 비밀번호 | 관리자 설정 |
| 다음/카카오 | `smtp.daum.net` | 465 | SSL | 앱 비밀번호 | 500건 |
| Microsoft 365 | `smtp.office365.com` | 587 | STARTTLS | OAuth2 권장 | 10,000건 |
| 카페24 | 업체별 상이 | 587 | TLS | ID/PW | 업체별 상이 |
| 가비아 | `smtp.gabia.com` | 587 | TLS | ID/PW | 업체별 상이 |

---

## 3. 연동 방식 (3단계 전략)

### 3.1 Phase 1: 플랫폼 발송 + Reply-To (즉시 적용)

```
┌─────────────────────────────────────────────────────────┐
│  Phase 1 — 플랫폼 발송                                    │
│                                                           │
│  SAM 공용 SMTP로 발송하되, 테넌트 브랜딩 적용              │
│                                                           │
│  From: "주일블라인드" <noreply@sam.codebridge-x.com>       │
│  Reply-To: admin@juil-blind.co.kr                         │
│  Subject: [SAM] 전자서명 요청                              │
│                                                           │
│  테넌트 설정: from_name + reply_to만 입력하면 됨            │
│  provider: 'platform'                                      │
└─────────────────────────────────────────────────────────┘
```

**장점**: 테넌트가 SMTP 정보를 제공하지 않아도 즉시 사용 가능
**단점**: 발신 주소가 `@sam.codebridge-x.com`으로 보임 (신뢰도 하락 가능)

**적합 대상**: 메일 설정이 어렵거나 SMTP 정보를 제공하지 않는 테넌트

### 3.2 Phase 2: SMTP 릴레이 (핵심 — 대부분의 테넌트)

```
┌─────────────────────────────────────────────────────────┐
│  Phase 2 — SMTP 릴레이                                    │
│                                                           │
│  테넌트의 SMTP 서버를 통해 발송                             │
│                                                           │
│  From: "주일블라인드" <admin@juil-blind.co.kr>              │
│  Subject: 전자서명 요청                                     │
│                                                           │
│  테넌트 설정: SMTP 프리셋 선택 + 계정/비밀번호 입력          │
│  provider: 'smtp'                                          │
│  → 수신자에게는 테넌트 회사 메일에서 온 것처럼 보임           │
└─────────────────────────────────────────────────────────┘
```

**장점**: 테넌트 도메인으로 발송, 높은 신뢰도
**단점**: 테넌트에게 앱 비밀번호 생성을 요청해야 함

**적합 대상**: SMTP 접근 가능한 대부분의 테넌트

### 3.3 Phase 3: OAuth2 연동 (고급 — 향후)

```
┌─────────────────────────────────────────────────────────┐
│  Phase 3 — OAuth2 연동                                    │
│                                                           │
│  Google / Microsoft 계정 OAuth2 인증                       │
│  비밀번호 저장 없이 토큰 기반 발송                           │
│                                                           │
│  provider: 'google_oauth' | 'microsoft_oauth'              │
│  → 가장 안전하지만 구현 복잡도 높음                          │
└─────────────────────────────────────────────────────────┘
```

**장점**: 비밀번호 저장 불필요, 보안 최상
**단점**: 구현 복잡도 높음, Google/MS만 지원, Azure AD 등록 필요

**적합 대상**: Google Workspace / Microsoft 365 사용 중견기업 이상

### 3.4 단계별 구현 우선순위

| Phase | 범위 | 대상 테넌트 | 구현 난이도 | 우선순위 |
|-------|------|-----------|------------|---------|
| Phase 1 | 플랫폼 발송 + Reply-To | 전체 (기본값) | 낮음 | 🔴 필수 |
| Phase 2 | SMTP 릴레이 + 프리셋 | SMTP 정보 제공 가능 | 중간 | 🔴 필수 |
| Phase 3 | OAuth2 연동 | Google/MS 365 사용 업체 | 높음 | 🟢 권장 |

---

## 4. SMTP 프리셋 시스템

### 4.1 프리셋 설정 파일

> **위치**: `/home/aweso/sam/mng/config/mail-presets.php` (MNG)
> `/home/aweso/sam/api/config/mail-presets.php` (API)

```php
<?php

return [
    'gmail' => [
        'label' => 'Gmail / Google Workspace',
        'host' => 'smtp.gmail.com',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => 'gmail',
        'daily_limit' => 500,
        'notes' => '앱 비밀번호 필요 (2단계 인증 활성화 후 생성)',
    ],
    'naver' => [
        'label' => '네이버 메일',
        'host' => 'smtp.naver.com',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => 'naver',
        'daily_limit' => 500,
        'notes' => '네이버 메일 설정 > POP3/SMTP > SMTP 사용 활성화 필요',
    ],
    'naverworks' => [
        'label' => '네이버웍스 (NAVER WORKS)',
        'host' => 'smtp.worksmobile.com',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => 'naverworks',
        'daily_limit' => null,
        'notes' => '관리자 콘솔에서 SMTP 허용 설정 필요',
    ],
    'daum' => [
        'label' => '다음/카카오 메일',
        'host' => 'smtp.daum.net',
        'port' => 465,
        'encryption' => 'ssl',
        'guide_key' => 'daum',
        'daily_limit' => 500,
        'notes' => '카카오 계정 > 보안 > 앱 비밀번호 생성',
    ],
    'microsoft365' => [
        'label' => 'Microsoft 365 (Outlook)',
        'host' => 'smtp.office365.com',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => 'microsoft365',
        'daily_limit' => 10000,
        'notes' => 'Basic Auth 폐지 주의 — OAuth2 전환 권장',
    ],
    'cafe24' => [
        'label' => '카페24 호스팅 메일',
        'host' => '',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => 'cafe24',
        'daily_limit' => null,
        'notes' => 'SMTP 호스트는 호스팅 계정마다 상이 — 수동 입력',
    ],
    'gabia' => [
        'label' => '가비아 호스팅 메일',
        'host' => 'smtp.gabia.com',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => 'gabia',
        'daily_limit' => null,
        'notes' => '가비아 메일 관리 > SMTP 설정 확인',
    ],
    'custom' => [
        'label' => '직접 입력 (자체 서버 등)',
        'host' => '',
        'port' => 587,
        'encryption' => 'tls',
        'guide_key' => null,
        'daily_limit' => null,
        'notes' => '호스트, 포트, 암호화 방식을 직접 입력',
    ],
];
```

### 4.2 프리셋 선택 흐름

```
본사 관리자가 MNG에서 테넌트 메일 설정
    │
    ├── 1. 테넌트 선택
    │
    ├── 2. 발송 방식 선택
    │       ├── "SAM 기본" → Phase 1 (from_name + reply_to만 입력)
    │       └── "자체 SMTP" → Phase 2 (프리셋 선택 진행)
    │
    ├── 3. 프리셋 선택 (자체 SMTP 시)
    │       ├── [Gmail ▼] 선택 → host/port/encryption 자동 채움
    │       ├── [네이버 ▼] 선택 → host/port/encryption 자동 채움
    │       └── [직접 입력] 선택 → 모든 필드 수동 입력
    │
    ├── 4. 계정 정보 입력
    │       ├── SMTP 사용자명 (이메일 주소)
    │       └── SMTP 비밀번호 (앱 비밀번호)
    │
    ├── 5. 연결 테스트 [🔧 테스트] 버튼
    │       ├── 성공 → "SMTP 연결 성공 (230ms)" ✅
    │       └── 실패 → 에러 메시지 + 트러블슈팅 안내
    │
    └── 6. 저장 (테스트 통과 시에만 활성화)
```

---

## 5. MNG 관리 화면 설계

### 5.1 메뉴 위치

```
MNG 사이드바
└── 시스템 관리
    └── 테넌트 관리
        └── 이메일 설정    ← 신규 메뉴
```

> **라우트**: `GET /system/tenants/{tenant}/mail-config`
> **컨트롤러**: `App\Http\Controllers\System\TenantMailConfigController`

### 5.2 화면 구조 — 테넌트 메일 설정 폼

```
┌─ 이메일 설정 — [주일블라인드] ──────────────────────────┐
│                                                          │
│  ── 기본 정보 ────────────────────────────────────────── │
│  발신자명:     [주일블라인드          ]                    │
│  발신 이메일:  [admin@juil-blind.co.kr]                   │
│  회신 주소:    [admin@juil-blind.co.kr] (선택)            │
│  일일 발송 한도: [500] 건                                 │
│                                                          │
│  ── 발송 방식 ────────────────────────────────────────── │
│  ● SAM 기본 (플랫폼 SMTP)                                │
│    발신 주소: noreply@sam.codebridge-x.com                │
│    Reply-To에 위 발신 이메일 자동 적용                     │
│                                                          │
│  ○ 자체 SMTP                                             │
│    ┌─ SMTP 설정 ──────────────────────────────────────┐ │
│    │  프리셋:   [Gmail / Google Workspace ▼]            │ │
│    │            ℹ️ 앱 비밀번호 필요 (가이드 보기)         │ │
│    │                                                    │ │
│    │  호스트:   [smtp.gmail.com    ] (자동)              │ │
│    │  포트:     [587               ] (자동)              │ │
│    │  암호화:   [TLS ▼             ] (자동)              │ │
│    │  사용자명: [admin@juil-blind.co.kr]                 │ │
│    │  비밀번호: [••••••••••••••••   ]                    │ │
│    │                                                    │ │
│    │  [🔧 연결 테스트]                                   │ │
│    │                                                    │ │
│    │  테스트 결과:                                       │ │
│    │  ✅ SMTP 연결 성공 (응답시간: 230ms)                │ │
│    │  ✅ 테스트 메일 발송 완료                            │ │
│    │     → admin@juil-blind.co.kr로 전송                 │ │
│    └────────────────────────────────────────────────────┘ │
│                                                          │
│  ── 브랜딩 (선택) ────────────────────────────────────── │
│  회사명:     [주일블라인드             ]                   │
│  로고:       [📎 업로드] sam_bi_logo.png                  │
│  테마 컬러:  [#1a56db] 🎨                                │
│  회사 주소:  [서울시 강남구...        ]                    │
│  연락처:     [02-1234-5678            ]                   │
│  푸터 문구:  [SAM 시스템에서 발송된 메일입니다]            │
│                                                          │
│  ── 상태 ─────────────────────────────────────────────── │
│  설정 상태: ✅ 활성  |  마지막 테스트: 2026-03-11 14:30   │
│  오늘 발송: 23/500건  |  이번 달 총 발송: 456건           │
│                                                          │
│             [💾 저장]     [↩️ 취소]                       │
└──────────────────────────────────────────────────────────┘
```

### 5.3 화면 구조 — 테넌트 목록 (메일 설정 현황)

```
┌─ 테넌트 이메일 설정 현황 ────────────────────────────────┐
│                                                          │
│  ┌────┬──────────┬──────────┬────────┬───────┬───────┐  │
│  │ ID │ 테넌트명  │ 발송 방식 │ 프리셋  │ 상태   │ 발송  │  │
│  ├────┼──────────┼──────────┼────────┼───────┼───────┤  │
│  │  1 │ 주일블라인드│ 자체 SMTP│ Gmail  │ ✅ 활성│ 23건  │  │
│  │  2 │ 경동스크린 │ SAM 기본 │ —      │ ✅ 활성│ 12건  │  │
│  │  3 │ 테스트업체 │ 미설정   │ —      │ ⚠️ 미설정│ 0건  │  │
│  └────┴──────────┴──────────┴────────┴───────┴───────┘  │
│                                                          │
│  ⚠️ 미설정 테넌트는 플랫폼 기본 SMTP로 발송됩니다         │
└──────────────────────────────────────────────────────────┘
```

### 5.4 파일 구조

```
mng/
├── app/Http/Controllers/System/
│   └── TenantMailConfigController.php     ← 컨트롤러
├── app/Services/Mail/
│   ├── TenantMailService.php              ← 메일 발송 서비스
│   └── SmtpConnectionTester.php           ← SMTP 연결 테스트
├── config/
│   └── mail-presets.php                   ← SMTP 프리셋 설정
└── resources/views/system/tenant-mail/
    ├── index.blade.php                    ← 테넌트 목록
    └── edit.blade.php                     ← 설정 폼
```

---

## 6. SMTP 연결 테스트

### 6.1 테스트 절차

```
[🔧 연결 테스트] 클릭
    │
    ├── 1. SMTP 서버 접속 (TCP 연결)
    │       └── 실패: "SMTP 서버에 접속할 수 없습니다 (호스트/포트 확인)"
    │
    ├── 2. TLS/SSL 핸드셰이크
    │       └── 실패: "암호화 연결 실패 (암호화 방식 확인)"
    │
    ├── 3. 인증 (AUTH LOGIN)
    │       └── 실패: "인증 실패 (사용자명/비밀번호 확인)"
    │
    ├── 4. 테스트 메일 발송 (선택)
    │       ├── 수신자: 입력한 from_address (자기 자신에게)
    │       ├── 제목: "[SAM] SMTP 연결 테스트"
    │       └── 본문: "이 메일은 SAM 시스템의 SMTP 연결 테스트입니다."
    │
    └── 5. 결과 반환
            ├── 응답시간 (ms)
            ├── 서버 배너 (SMTP EHLO 응답)
            └── 성공/실패 메시지
```

### 6.2 `SmtpConnectionTester` 서비스

> **위치**: `mng/app/Services/Mail/SmtpConnectionTester.php`

```php
class SmtpConnectionTester
{
    /**
     * SMTP 연결 테스트 실행
     *
     * @return array{
     *     success: bool,
     *     message: string,
     *     response_time_ms: int,
     *     server_banner: string|null,
     *     error_code: string|null
     * }
     */
    public function test(
        string $host,
        int $port,
        string $encryption,
        string $username,
        string $password,
        ?string $testRecipient = null
    ): array;
}
```

### 6.3 에러 코드 및 트러블슈팅

| 에러 코드 | 메시지 | 원인 | 해결 방법 |
|----------|--------|------|----------|
| `CONN_REFUSED` | SMTP 서버 접속 거부 | 호스트/포트 오류, 방화벽 | 호스트/포트 확인, 프리셋 재선택 |
| `TLS_FAILED` | TLS 핸드셰이크 실패 | 암호화 방식 불일치 | SSL ↔ TLS 전환 시도 |
| `AUTH_FAILED` | 인증 실패 | 비밀번호 오류, 앱 비밀번호 미사용 | 앱 비밀번호 재생성 안내 |
| `SMTP_DISABLED` | SMTP 비활성화 | 메일 설정에서 SMTP 미허용 | 메일 서비스 SMTP 활성화 안내 |
| `QUOTA_ERROR` | 발송 한도 초과 | 일일 한도 도달 | 시간 경과 후 재시도 |
| `TIMEOUT` | 연결 시간 초과 (10초) | 네트워크, 서버 과부하 | 잠시 후 재시도 |

---

## 7. 테넌트 사전 준비 안내

### 7.1 안내 절차

본사 관리자가 테넌트에게 메일 연동을 위한 사전 준비를 안내한다.

```
본사 → 테넌트 안내 흐름:
    │
    ├── 1. 테넌트가 사용하는 메일 서비스 확인
    │       "현재 회사 메일이 Gmail인가요, 네이버인가요?"
    │
    ├── 2. 해당 서비스의 앱 비밀번호 생성 가이드 전달
    │       (SAM 도움말 페이지 링크 또는 PDF)
    │
    ├── 3. 테넌트가 앱 비밀번호 생성 후 본사에 전달
    │       ├── SMTP용 이메일 주소
    │       └── 앱 비밀번호 (일반 비밀번호 아님)
    │
    └── 4. 본사가 MNG에서 설정 → 연결 테스트 → 완료 통보
```

### 7.2 제공자별 앱 비밀번호 생성 안내

#### Gmail / Google Workspace

```
1. Google 계정 > 보안 > 2단계 인증 활성화 (필수 전제)
2. Google 계정 > 보안 > 앱 비밀번호
3. "앱 선택" → "기타 (맞춤 이름)" → "SAM" 입력
4. 생성된 16자리 비밀번호를 본사에 전달
```

#### 네이버 메일

```
1. 네이버 메일 > 환경설정 > POP3/IMAP 설정
2. "IMAP/SMTP 사용" → "사용함" 체크
3. 네이버 계정 > 보안 설정 > 2단계 인증 활성화
4. "앱 비밀번호 관리" → 앱 이름 "SAM" 입력 → 생성
5. 생성된 비밀번호를 본사에 전달
```

#### 네이버웍스

```
1. 네이버웍스 관리자 콘솔 접속 (관리자 권한 필요)
2. 보안 > 외부 앱 연동 > SMTP 허용
3. 사용할 계정의 이메일/비밀번호를 본사에 전달
   (또는 앱 전용 비밀번호 생성)
```

#### 다음/카카오 메일

```
1. 다음 메일 > 환경설정 > IMAP/POP > SMTP 사용 체크
2. 카카오 계정 > 보안 > 앱 비밀번호 생성
3. 생성된 비밀번호를 본사에 전달
```

#### Microsoft 365

```
1. Microsoft 365 관리자 센터 > 인증 정책
2. SMTP AUTH 허용 (테넌트 수준 또는 사용자 수준)
3. 해당 사용자 계정의 이메일/비밀번호 전달
   ※ Basic Auth 폐지 추세 → OAuth2 연동(Phase 3) 권장
```

#### 카페24 / 가비아 호스팅 메일

```
1. 호스팅 관리 패널에서 SMTP 서버 주소 확인
2. 메일 계정의 이메일/비밀번호를 본사에 전달
   (호스팅 메일은 별도 앱 비밀번호 없이 일반 비밀번호 사용)
```

---

## 8. `tenant_mail_configs` 확장 — `options` JSON

> 기존 [이메일 발송 정책](../standards/email-policy.md)의 `options` 구조에 연동 관련 필드를 추가한다.

### 8.1 전체 `options` JSON 구조

```json
{
    "smtp": {
        "host": "smtp.gmail.com",
        "port": 587,
        "username": "admin@juil-blind.co.kr",
        "password": "<encrypted>",
        "encryption": "tls"
    },
    "preset": "gmail",
    "branding": {
        "logo_url": "/storage/tenants/1/logo.png",
        "primary_color": "#1a56db",
        "company_name": "주일블라인드",
        "company_address": "서울시 강남구...",
        "company_phone": "02-1234-5678",
        "footer_text": "본 메일은 SAM 시스템에서 발송되었습니다."
    },
    "connection_test": {
        "last_tested_at": "2026-03-11T14:30:00",
        "last_result": "success",
        "response_time_ms": 230,
        "server_banner": "220 smtp.gmail.com ESMTP",
        "tested_by": "admin@codebridge-x.com"
    },
    "domain_auth": {
        "spf_verified": false,
        "dkim_verified": false,
        "dkim_selector": null,
        "verified_at": null
    },
    "oauth": {
        "provider": null,
        "access_token": null,
        "refresh_token": null,
        "expires_at": null
    }
}
```

### 8.2 `options` 키 설명

| 키 | Phase | 설명 |
|-----|-------|------|
| `smtp.*` | Phase 2 | 테넌트 SMTP 접속 정보 |
| `preset` | Phase 2 | 프리셋 식별자 (`gmail`, `naver`, `custom` 등) |
| `branding.*` | Phase 1~2 | 메일 템플릿 브랜딩 정보 |
| `connection_test.*` | Phase 2 | 마지막 SMTP 연결 테스트 결과 |
| `domain_auth.*` | Phase 2+ | SPF/DKIM 도메인 인증 상태 |
| `oauth.*` | Phase 3 | OAuth2 토큰 정보 (향후) |

---

## 9. 도메인 인증 (SPF/DKIM) — Phase 2+

### 9.1 필요성

Phase 1(플랫폼 발송)에서 테넌트 도메인이 아닌 SAM 도메인으로 발송하면 스팸 분류될 수 있다.
도메인 인증을 통해 SAM이 테넌트 도메인 대신 발송하는 것을 허용한다.

### 9.2 인증 항목

| 인증 | 역할 | 테넌트 조치 |
|------|------|------------|
| **SPF** | "이 IP에서 보내는 메일은 정상" | 테넌트 DNS에 SAM 발송 IP 추가 |
| **DKIM** | 메일 위변조 방지 서명 | SAM이 생성한 TXT 레코드를 DNS에 등록 |
| **DMARC** | SPF+DKIM 정책 정의 | 선택 사항 (권장) |

### 9.3 도메인 인증 흐름 (MNG 마법사)

```
본사 관리자가 MNG에서 도메인 인증 진행
    │
    ├── 1. 테넌트 도메인 입력 (예: juil-blind.co.kr)
    │
    ├── 2. SAM이 DNS 레코드 자동 생성
    │       ├── SPF: "v=spf1 include:sam.codebridge-x.com ~all"
    │       └── DKIM: sam2026._domainkey.juil-blind.co.kr → 공개키
    │
    ├── 3. 테넌트 IT 담당자에게 DNS 레코드 추가 요청
    │       (안내 메일 또는 텍스트로 전달)
    │
    ├── 4. [인증 확인] 버튼 → DNS 조회로 레코드 확인
    │       ├── 성공: domain_auth.spf_verified = true
    │       └── 실패: "DNS 전파 대기 중 (최대 48시간)"
    │
    └── 5. 인증 완료 시 Phase 1에서도 높은 도달률 확보
```

> **현실적 판단**: 대부분의 중소기업 테넌트는 DNS 관리 역량이 없으므로, Phase 2(SMTP 릴레이)를 기본으로 권장하고 도메인 인증은 선택 사항으로 제공한다.

---

## 10. API 엔드포인트

### 10.1 MNG 내부 라우트

| Method | Path | 설명 |
|--------|------|------|
| `GET` | `/system/tenants/{tenant}/mail-config` | 메일 설정 폼 화면 |
| `PUT` | `/system/tenants/{tenant}/mail-config` | 메일 설정 저장 |
| `POST` | `/system/tenants/{tenant}/mail-config/test` | SMTP 연결 테스트 |
| `GET` | `/system/tenants/mail-config/presets` | 프리셋 목록 JSON |
| `GET` | `/system/tenants/mail-config/overview` | 전체 테넌트 설정 현황 |

### 10.2 연결 테스트 API

**Request**:

```json
POST /system/tenants/1/mail-config/test
{
    "provider": "smtp",
    "preset": "gmail",
    "host": "smtp.gmail.com",
    "port": 587,
    "encryption": "tls",
    "username": "admin@juil-blind.co.kr",
    "password": "xxxx xxxx xxxx xxxx",
    "send_test_mail": true
}
```

**Response (성공)**:

```json
{
    "success": true,
    "message": "SMTP 연결 성공",
    "data": {
        "response_time_ms": 230,
        "server_banner": "220 smtp.gmail.com ESMTP",
        "test_mail_sent": true,
        "test_mail_to": "admin@juil-blind.co.kr"
    }
}
```

**Response (실패)**:

```json
{
    "success": false,
    "message": "인증 실패 — 앱 비밀번호를 확인하세요",
    "data": {
        "error_code": "AUTH_FAILED",
        "troubleshoot": "Gmail은 앱 비밀번호가 필요합니다. 2단계 인증 활성화 후 앱 비밀번호를 생성하세요.",
        "guide_url": "/docs/email-setup/gmail"
    }
}
```

---

## 11. 보안 규칙

### 11.1 필수 준수 사항

```
✅ SMTP 비밀번호는 encrypt()로 암호화 저장 (DB에 평문 금지)
✅ OAuth2 토큰도 encrypt()로 암호화 저장
✅ 연결 테스트 시 비밀번호는 HTTPS 전송만 허용
✅ MNG 관리자만 테넌트 메일 설정 접근 가능 (권한: system.tenant.mail)
✅ SMTP 비밀번호는 API 응답/뷰에서 마스킹 처리 (••••••••)
✅ 연결 테스트 결과는 mail_logs가 아닌 options.connection_test에 기록
```

### 11.2 금지 사항

```
❌ 테넌트가 직접 MNG에서 메일 설정 변경 금지 (본사만 가능)
❌ SMTP 비밀번호를 로그/콘솔에 출력 금지
❌ 암호화 없이 비밀번호 저장 금지
❌ 다른 테넌트의 SMTP 설정 조회 금지 (TenantScope 적용)
```

### 11.3 비밀번호 수명주기

```
비밀번호 입력 → encrypt() 암호화 → DB 저장
                                      │
연결 테스트 시 ← decrypt() 복호화 ────┘
메일 발송 시  ← decrypt() 복호화 ────┘
설정 폼 표시  → "••••••••" 마스킹 (원본 미노출)
```

---

## 12. 구현 체크리스트

### Phase 1: 플랫폼 발송 (기반)

- [ ] `tenant_mail_configs` 마이그레이션 (API)
- [ ] `TenantMailConfig` 모델 생성 (API + MNG)
- [ ] `TenantMailService` 생성 (MNG)
- [ ] MNG 관리 화면 — 기본 설정 폼 (from_name, reply_to)
- [ ] 기존 Mailable을 `TenantMailService` 경유로 전환

### Phase 2: SMTP 릴레이

- [ ] `config/mail-presets.php` 프리셋 설정 파일 생성
- [ ] MNG 관리 화면 — 프리셋 선택 + SMTP 설정 폼
- [ ] `SmtpConnectionTester` 서비스 구현
- [ ] SMTP 연결 테스트 API 구현
- [ ] 프리셋 선택 시 호스트/포트/암호화 자동 채움 (HTMX)
- [ ] SMTP 비밀번호 encrypt/decrypt 처리
- [ ] 테넌트별 앱 비밀번호 생성 가이드 페이지

### Phase 3: OAuth2 연동 (향후)

- [ ] Google OAuth2 연동 (Gmail API `gmail.send` scope)
- [ ] Microsoft Graph OAuth2 연동 (`Mail.Send` scope)
- [ ] OAuth 토큰 자동 갱신 (Refresh Token)
- [ ] MNG에서 "Google 연결" / "Microsoft 연결" 버튼

---

## 관련 문서

- [이메일 발송 정책](../standards/email-policy.md) — 내부 발송 아키텍처, 테이블 설계, 서비스 설계
- [테넌트 DB 구조](../../system/database/tenants.md) — 테넌트 테이블, 데이터 격리
- [options JSON 컬럼 정책](../standards/options-column-policy.md) — options 컬럼 사용 규칙
- [전자서명 기능](../../features/esign/README.md) — 메일 발송이 많은 주요 기능

---

**최종 업데이트**: 2026-03-11
