# 機能設計書 100-sendmail（メール配送）

## 概要

本ドキュメントは、FreeBSDのsendmailメール配送エージェント（MTA: Mail Transfer Agent）の機能設計を記述する。sendmailはSMTP（Simple Mail Transfer Protocol）によるメールの送受信・転送・配送を行うメール配送システムである。

### 本機能の処理概要

sendmailは、インターネットメール配送の標準的なMTA実装であり、SMTPプロトコルを使用したメールの受信・転送・ローカル配送を行う。複雑なメールルーティング、アドレス変換、メーリングリスト処理等に対応する高機能なメール配送システムである。

**業務上の目的・背景**：FreeBSDシステムにおいてメールの送受信機能を提供する必要がある。sendmailはシステムからの通知メール（cron出力、セキュリティ警告等）の配送、外部メールの受信・転送、ローカルユーザ間のメール配送等の基盤として使用される。

**機能の利用シーン**：cronジョブの実行結果通知、セキュリティ関連の自動通知メール、システム管理者への警告メール、外部メールサーバへのメール転送、ローカルユーザ間のメール配送などで使用される。

**主要な処理内容**：
1. SMTPサーバ機能：TCP ポート25でSMTP接続を受け付け、メール受信
2. メールキュー管理：配送待ちメールのキューイング・再送管理
3. メールルーティング：DNSのMXレコードに基づく配送先決定
4. アドレス変換：aliasesファイルによるアドレス変換
5. ローカル配送：mail.local経由でのローカルメールボックスへの配送
6. リレー制御：不正リレーの防止
7. SMTP認証（SMTP AUTH）
8. TLS/SSL暗号化（STARTTLS）
9. milter（メールフィルタ）インタフェース
10. メールサブミッション（ポート587）

**関連システム・外部連携**：DNS（MXレコード解決）、mail.local（ローカル配送プログラム）、milterフィルタ（SpamAssassin等）、TLS/SSL（OpenSSL）

**権限による制御**：sendmailはroot権限で起動し、setuid rootで動作する。メールボックスへの書き込みはmail.localがローカルユーザの権限で実行する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに直接の関連画面なし |

## 機能種別

ネットワークサービス（メール配送エージェント）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sendmail.cf | ファイル | Yes | メイン設定ファイル | 構文チェック |
| submit.cf | ファイル | Yes | サブミッション用設定 | 構文チェック |
| -t | フラグ | No | メールヘッダから宛先を抽出 | - |
| -f sender | string | No | エンベロープ送信者指定 | メールアドレス形式 |
| -q interval | string | No | キュー処理間隔 | 時間形式 |
| -bd | フラグ | No | デーモンモード起動 | - |

### 入力データソース

- SMTPクライアントからのSMTP接続（TCP ポート25/587）
- コマンドラインからのメール投入（sendmail -t < message）
- /etc/mail/sendmail.cf メイン設定ファイル
- /etc/mail/aliases エイリアスデータベース
- /etc/mail/access アクセス制御データベース
- DNS MXレコード

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| SMTP応答 | テキスト | SMTPプロトコルの応答コード・メッセージ |
| メールキュー | ファイル | /var/spool/mqueue/内のキューファイル |
| ローカル配送 | ファイル | mail.local経由でのメールボックス書き込み |
| ログ | syslog | メール配送ログ（facility: mail） |
| 統計 | ファイル | mailstats用統計ファイル |

### 出力先

- リモートSMTPサーバへのメール転送
- ローカルメールボックス（/var/mail/ユーザ名）
- /var/spool/mqueue/ メールキュー
- syslog（mail facility）

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ sendmail.cf読み込み、aliasesデータベースロード、ソケットオープン
2. SMTP接続受付
   └─ TCP ポート25/587でクライアント接続待ち受け
3. SMTPセッション処理
   └─ HELO/EHLO → MAIL FROM → RCPT TO → DATA → メッセージ受信
4. メッセージ処理
   └─ ヘッダ解析、アドレス変換、ルーティング決定
5. 配送
   └─ ローカル配送（mail.local）またはリモート転送（SMTP）
6. キュー処理
   └─ 一時エラー時のキューイング、定期的な再送試行
```

### フローチャート

```mermaid
flowchart TD
    A[SMTP接続受付 ポート25/587] --> B[SMTPハンドシェイク EHLO]
    B --> C{STARTTLS?}
    C -->|Yes| D[TLSネゴシエーション]
    C -->|No| E[MAIL FROM受信]
    D --> E
    E --> F[RCPT TO受信]
    F --> G[DATA受信]
    G --> H[メッセージ解析]
    H --> I{宛先種別}
    I -->|ローカル| J[aliases展開]
    J --> K[mail.localで配送]
    I -->|リモート| L[DNS MXレコード検索]
    L --> M[リモートSMTPサーバへ転送]
    M --> N{配送成功?}
    N -->|Yes| O[完了]
    N -->|一時エラー| P[キューに保存]
    P --> Q[定期再送]
    N -->|永久エラー| R[バウンスメール生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-100-1 | リレー制御 | デフォルトでオープンリレーは無効（認証されたユーザまたは許可されたホストのみ転送可） | メール転送時 |
| BR-100-2 | キュー再送間隔 | 一時エラー時はキューに保存し、設定された間隔で再送を試行 | 配送一時失敗時 |
| BR-100-3 | バウンス期限 | 設定された期間（通常5日）内に配送できない場合はバウンスメールを返送 | キュー滞留時 |
| BR-100-4 | aliases展開 | /etc/mail/aliasesに基づくアドレス展開を実施 | ローカル配送時 |
| BR-100-5 | サブミッションポート | メールサブミッションはポート587で受け付け | メール投入時 |

### 計算ロジック

特に複雑な計算ロジックはない。メールルーティングはDNS MXレコードの優先度に基づく。

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| aliases解決 | /etc/mail/aliases.db | SELECT | aliasesデータベースからアドレス展開情報を検索 |
| アクセス制御 | /etc/mail/access.db | SELECT | accessデータベースからリレー許可/拒否を判定 |
| 統計更新 | /etc/mail/statistics | UPDATE | メール送受信統計の更新 |

### テーブル別操作詳細

#### aliases.db

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | alias_value | キー: ローカルアドレス部分 | newaliasesコマンドで再構築 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 4xx | 一時エラー | リモートサーバ一時障害 | キューに保存し後で再送 |
| 5xx | 永久エラー | 宛先不明、配送拒否等 | バウンスメール生成 |
| 550 | ユーザ不明 | ローカルユーザが存在しない | バウンスメール返送 |
| 421 | サービス不可 | サーバ過負荷、シャットダウン | 一時エラーとして再送 |

### リトライ仕様

一時エラー（4xx）の場合、メールをキューに保存し、設定された間隔（デフォルト30分）で再送を試行する。再送間隔は指数的に延長される。

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

SMTPプロトコルレベルでは、DATAコマンド後の"."によりメッセージが確定する。sendmailは受信したメッセージをキューファイルに書き込み、fsync後にSMTP 250応答を返すことで、メッセージ喪失を防止する。

## パフォーマンス要件

- 同時SMTP接続数の制限（MaxDaemonChildren等で制御）
- キュー処理のスループット
- DNS解決のキャッシュ

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

- SMTP AUTH: CRAM-MD5、DIGEST-MD5、LOGIN、PLAIN等の認証メカニズム
- STARTTLS: SMTP通信のTLS暗号化
- オープンリレー防止: デフォルトでリレー制限が有効
- milter: 外部フィルタによるスパム/マルウェア対策
- access.db: IP/ドメインベースのアクセス制御
- setuid実行: sendmailはsetuid rootで動作するため、脆弱性の影響が大きい
- サンドボックス: smtpd_sandbox設定

## 備考

- sendmailはcontrib/sendmail/以下にアップストリームソースが配置
- mail.localはlibexec/mail.local/にローカル配送プログラムとして配置
- FreeBSDではデフォルトMTAとして提供されるが、PostfixやDMAへの移行も可能
- makemapコマンドでaliases.db、access.db等のデータベースを構築

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conf.h | `contrib/sendmail/src/conf.h` | sendmail内部設定構造体。コンパイル時オプション、パス定義等 |
| 1-2 | sendmail.h | `contrib/sendmail/include/sendmail/sendmail.h` | メール配送の基本構造体定義 |

**読解のコツ**: sendmailのソースコードは歴史的に複雑であり、大量のマクロとコンパイル時条件分岐が使用されている。conf.hで定義されるコンパイル時オプションを先に把握することが重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.c | `contrib/sendmail/src/main.c` | メインプログラム（4904行）。コマンドライン引数解析、動作モード決定（デーモン/コマンドライン）、初期化シーケンス |

**主要処理フロー**:
- main()関数: 引数解析 → 設定ファイル読み込み → モード判定 → デーモンモードまたはメール投入

#### Step 3: SMTP処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | daemon.c | `contrib/sendmail/src/daemon.c` | SMTPデーモン処理。接続受付、子プロセス生成 |
| 3-2 | control.c | `contrib/sendmail/src/control.c` | SMTP制御接続処理 |

#### Step 4: メッセージ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | collect.c | `contrib/sendmail/src/collect.c` | メッセージデータの収集・保存 |
| 4-2 | headers.c | `contrib/sendmail/src/headers.c` | メールヘッダの解析・生成 |
| 4-3 | envelope.c | `contrib/sendmail/src/envelope.c` | エンベロープ（送信者・受信者）の管理 |

#### Step 5: 配送処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | deliver.c | `contrib/sendmail/src/deliver.c` | メール配送の中核。ローカル/リモート配送の振り分け |
| 5-2 | domain.c | `contrib/sendmail/src/domain.c` | DNS MXレコード検索 |

#### Step 6: アドレス解決を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | alias.c | `contrib/sendmail/src/alias.c` | aliasesデータベースによるアドレス変換 |

#### Step 7: ローカル配送を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 7-1 | mail.local.c | `contrib/sendmail/mail.local/mail.local.c` | ローカルメールボックスへの配送プログラム |

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

```
sendmail main() [main.c]
    │
    ├─ conf.c: 設定ファイル読み込み (sendmail.cf)
    │
    ├─ daemon.c: デーモンモード
    │      └─ SMTP接続受付 (ポート25/587)
    │             │
    │             ├─ SMTPセッション処理
    │             │      ├─ EHLO/HELO
    │             │      ├─ STARTTLS (TLSネゴシエーション)
    │             │      ├─ AUTH (SMTP認証)
    │             │      ├─ MAIL FROM
    │             │      ├─ RCPT TO
    │             │      └─ DATA → collect.c: メッセージ収集
    │             │
    │             ├─ headers.c: ヘッダ解析
    │             ├─ envelope.c: エンベロープ管理
    │             │
    │             └─ deliver.c: 配送処理
    │                    ├─ alias.c: aliases展開
    │                    ├─ domain.c: MXレコード検索
    │                    ├─ リモート配送 (SMTP転送)
    │                    └─ ローカル配送
    │                           └─ mail.local: メールボックス書き込み
    │
    └─ キュー管理
           ├─ キューファイル作成 (/var/spool/mqueue/)
           └─ 定期再送処理
```

### データフロー図

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

SMTPクライアント          ───▶ daemon.c: 接続受付       ───▶ SMTPセッション
(ポート25/587)                  │
                          collect.c: メッセージ収集
                                │
                          headers.c: ヘッダ解析
                          envelope.c: エンベロープ処理
                                │
/etc/mail/aliases        ───▶ alias.c: アドレス展開
                                │
DNS MXレコード           ───▶ domain.c: ルーティング
                                │
                          deliver.c: 配送判定
                                │
                          ├─ リモートSMTPサーバ         ───▶ SMTP転送
                          └─ mail.local                 ───▶ /var/mail/user

sendmail.cf              ───▶ conf.c: 設定解析
/etc/mail/access         ───▶ アクセス制御判定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main.c | `contrib/sendmail/src/main.c` | ソース | メインプログラム |
| daemon.c | `contrib/sendmail/src/daemon.c` | ソース | SMTPデーモン処理 |
| deliver.c | `contrib/sendmail/src/deliver.c` | ソース | メール配送処理 |
| collect.c | `contrib/sendmail/src/collect.c` | ソース | メッセージ収集 |
| headers.c | `contrib/sendmail/src/headers.c` | ソース | ヘッダ解析 |
| envelope.c | `contrib/sendmail/src/envelope.c` | ソース | エンベロープ管理 |
| alias.c | `contrib/sendmail/src/alias.c` | ソース | エイリアス処理 |
| domain.c | `contrib/sendmail/src/domain.c` | ソース | DNS MX検索 |
| conf.c | `contrib/sendmail/src/conf.c` | ソース | 設定処理 |
| conf.h | `contrib/sendmail/src/conf.h` | ヘッダ | 設定定義 |
| control.c | `contrib/sendmail/src/control.c` | ソース | 制御接続処理 |
| err.c | `contrib/sendmail/src/err.c` | ソース | エラー処理 |
| macro.c | `contrib/sendmail/src/macro.c` | ソース | マクロ処理 |
| mail.local.c | `contrib/sendmail/mail.local/mail.local.c` | ソース | ローカル配送プログラム |
| Makefile | `contrib/sendmail/Makefile` | ビルド | ビルド設定 |
