## 設定 設定 — milter-manager.confの書き方 |

## このドキュメントについて

milter-managerの設定ファイルmilter-manager.confの書き方について説明します。

## 場所

ここでは/usr/local/以下にインストールされたものとして説明します。configure時に--prefix=/usr/local/オプションを指定するか、--prefixオプションを省略した場合は/usr/local/以下にインストールされます。

この場合は、設定ファイルは/usr/local/etc/milter-manager/milter-manager.confになります。インストールが成功していれば、もうすでにファイルが存在するはずです。

## 概要

設定ファイルの先頭は以下のようになっています。

    # -*- ruby -*-

    load("applicable-conditions/*.conf")
    load_default
    load_if_exist("milter-manager.local.conf")

通常は、この部分はそのままにしておき、milter-manager.confと同じディレクトリにmilter-manager.local.confというファイルを作成し、そのファイルに設定を記述します。

設定項目は以下のように分類されています。

- パッケージ関連

- セキュリティ関連

- milter-manager関連

- コントローラ関連

- 子milter関連

- 適用条件関連

このうち、適用条件関連はRubyの知識が必要になります。 S25R などの有用な適用条件は標準で提供されているので、必ずしも自分で適用条件を定義できる必要はありません。そのため、適用条件の説明は一番最後にあります。適用条件を定義する必要がない場合は、適用条件関連の部分は読み飛ばしても構いません。

それぞれ順に説明する前に、設定をする上で便利なmilter-manager機能を紹介します。milter-managerを--show-configオプションを付きで起動すると、現在の設定内容が表示されます。

    % /usr/local/sbin/milter-manager --show-config
    package.platform = "debian"
    package.options = nil

    security.privilege_mode = false
    security.effective_user = nil
    security.effective_group = nil

    manager.connection_spec = nil
    manager.unix_socket_mode = 0660
    manager.unix_socket_group = nil
    manager.remove_unix_socket_on_create = true
    manager.remove_unix_socket_on_close = true
    manager.daemon = false
    manager.pid_file = nil
    manager.maintenance_interval = 100
    manager.suspend_time_on_unacceptable = 5
    manager.max_connections = 0
    manager.custom_configuration_directory = nil

    controller.connection_spec = nil
    controller.unix_socket_mode = 0660
    controller.remove_unix_socket_on_create = true
    controller.remove_unix_socket_on_close = true

    define_applicable_condition("S25R") do |condition|
      condition.description = "Selective SMTP Rejection"
    end

    define_applicable_condition("Remote Network") do |condition|
      condition.description = "Check only remote network"
    end

この内容で設定内容を確認することができます。

また、この書式はそのまま設定ファイルの書式になっているので、設定の書き方を忘れたときにはこの内容をヒントにすることができます。

それでは、それぞれの分類毎に説明します。

## パッケージ関連

package.platform | この項目は通常は変更する必要はありません。 milterの自動検出方法はプラットフォーム毎に異なります。自動検出はmilterがプラットフォームで用いているパッケージシステムでインストールされていることを前提としています。そのため、実際のプラットフォームとmilter-managerが認識しているプラットフォームが異なると、自動検出がうまく動きません。 プラットフォームはビルド時に検出しています。検出結果が間違っている場合は、ビルド時に修正することができます。検出結果が間違っているが、ビルドをやり直すことができない場合に、この設定項目を利用します。 現在、標準で利用可能なプラットフォームは以下の通りです。 debian: Debian GNU/LinuxやUbuntu LinuxなどDebian系Linux用 redhat: CentOSなどRedHat系Linux freebsd: FreeBSD用 pkgsrc: NetBSDやDragonFly BSDなどpkgsrcを利用している*BSD用 プラットフォーム名は「"」で囲んて"debian"というように指定します。 注意: 変更する場合はload_defaultの 前 に行って下さい。 例:
    package.platform = "pkgsrc"
既定値:
    package.platform = "debian" # 環境に依存
package.options | この項目は通常は変更する必要はありません。 package.platformと同様にビルド時に決定しています。 milter自動検出処理へ付加情報を渡すための項目です。"名前1=値1,名前2=値2,.."という形式で複数の情報を渡すことができます。 現在、この付加情報を使っているのはpkgsrcプラットフォームのときだけで、"prefix=rc.dがあるディレクトリのパス"という情報を使っています。例えば、/etc/rc.d/以下に起動スクリプトをインストールしている時は、"prefix=/etc"と指定します。 注意: 変更する場合はload_defaultの 前 に行って下さい。 例:
    package.options = "prefix=/etc,name=value"
既定値:
    package.options = nil # 環境に依存

## セキュリティ関連

security.privilege_mode | 特権モードで動作するかどうかを指定します。子milter自動起動機能を利用する場合は有効にする必要があります。 有効にする場合はtrueを指定します。無効にする場合はfalseを指定します。 例:
    security.privilege_mode = true
既定値:
    security.privilege_mode = false
security.effective_user | milter-managerプロセスの実効ユーザを指定します。ユーザを切り替えるにはmilter-managerコマンドをroot権限で起動する必要があります。 実効ユーザは「"」で囲んて"nobody"というように指定します。ユーザを指定しない場合はnilを指定します。 例:
    security.effective_user = "nobody"
既定値:
    security.effective_user = nil
security.effective_group | milter-managerプロセスの実効グループを指定します。グループを切り替えるにはmilter-managerコマンドをroot権限で起動する必要があります。 実効グループは「"」で囲んて"nogroup"というように指定します。グループを指定しない場合はnilを指定します。 例:
    security.effective_group = "nogroup"
既定値:
    security.effective_group = nil

## milter-manager関連

manager.connection_spec | milter-managerが接続を受け付けるソケットを指定します。 ソケットは「"」で囲んて"inet:10025"というように指定します。指定できる書式は以下の通りです。 UNIXドメインソケット: unix:パス 例: unix:/var/run/milter/milter-manager.sock IPv4ソケット: inet:ポート番号 例: inet:10025 IPv4ソケット: inet:ポート番号@ホスト名 例: inet:10025@localhost IPv4ソケット: inet:ポート番号@[アドレス] 例: inet:10025@[127.0.0.1] IPv6ソケット: inet6:ポート番号 例: inet6:10025 IPv6ソケット: inet6:ポート番号@ホスト名 例: inet6:10025@localhost IPv6ソケット: inet6:ポート番号@[アドレス] 例: inet6:10025@[::1] もし、security.effective_user, security.effective_groupを指定している場合は、その権限でUNIXドメインソケットを作成します。ソケットを作成するディレクトリのパーミッションに注意してください。 IPv4ソケット・IPv6ソケットでホスト名を省略した場合は、すべてのネットワークインターフェイスから接続を受け付けます。ホスト名やアドレスを指定した場合はそのアドレスからのみ接続を受け付けます。 例:
    manager.connection_spec = "unix:/var/run/milter/milter-manager.sock"
既定値:
    manager.connection_spec = "inet:10025@[127.0.0.1]"
manager.unix_socket_mode | milter-managerが接続を受け付けるUNIXドメインソケットのパーミッションを指定します。manager.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 8進数で値を指定するために、先頭に「0」をつけることを忘れないでください。 例:
    manager.unix_socket_mode = 0600
既定値:
    manager.unix_socket_mode = 0660
manager.unix_socket_group | milter-managerが接続を受け付けるUNIXドメインソケットのグループを指定します。manager.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 ソケットのグループはsecurity.effective_user/security.effective_group権限で作成された後に、chown(2)で変更します。そのため、指定するグループはsecurity.effective_userの補助グループである必要があります。 グループは「"」で囲んて"nogroup"というように指定します。グループを指定しない場合はnilを指定します。 例:
    manager.unix_socket_group = "nobody"
既定値:
    manager.unix_socket_group = nil
manager.remove_unix_socket_on_create | milter-managerが接続を受け付けるUNIXドメインソケットを作成する前にすでにファイルが存在した場合、削除するかどうかを指定します。manager.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 削除する場合はtrueを指定します。削除しない場合はfalseを指定します。 例:
    manager.remove_unix_socket_on_create = false
既定値:
    manager.remove_unix_socket_on_create = true
manager.remove_unix_socket_on_close | milter-managerが終了するときに、接続を受け付けていたUNIXドメインソケットを削除するかどうかを指定します。manager.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 削除する場合はtrueを指定します。削除しない場合はfalseを指定します。 例:
    manager.remove_unix_socket_on_close = false
既定値:
    manager.remove_unix_socket_on_close = true
manager.daemon | デーモンプロセスとして動作するかどうかを指定します。デーモンプロセスで動作する場合は、端末を切り離し、バックグラウンドで動作します。運用時はバックグラウンドで起動することをお勧めします。この設定項目はmilter-managerの--daemonコマンドラインオプションで上書きできるため、必ずしも設定ファイル内で設定する必要はありません。 デーモンプロセスとして動作する場合はtrueを指定します。そうでない場合はfalseを指定します。 例:
    manager.daemon = true
既定値:
    manager.daemon = false
manager.pid_file | 起動したmilter-managerのプロセスIDを保存するファイルを指定します。 もし、security.effective_user, security.effective_groupを指定して場合は、その権限でファイルへ書き込みます。ファイルのパーミッションに注意してください。 ファイルのパスは「"」で囲んで"/var/run/milter/milter-manager.pid"というように指定します。保存しない場合はnilを指定します。 例:
    manager.pid_file = "/var/run/milter/milter-manager.pid"
既定値:
    manager.pid_file = nil
manager.maintenance_interval | 何セッション終了毎にメンテナンス処理を実行するかを指定します。 現時点でのメンテナンス処理とはメモリ解放処理のことです。同時アクセス数が少ない環境では各セッション終了毎にメンテナンス処理を実行することによりメモリ使用量を抑えることができます。同時アクセス数が多い環境では複数セッション終了毎にまとめてメンテナンス処理を実行することにより処理効率をあげることができます。 0またはnilを指定した場合はメンテナンス処理を実行しません。 例:
    manager.maintenance_interval = nil
既定値:
    manager.maintenance_interval = 100
manager.suspend_time_on_unacceptable | 同時に多数の接続があり、MTAからの接続を受け付けることができないときに何秒待つかを指定します。ulimitやlimitで同時に開くことができるファイルディスクリプタ数を増やすことも検討してください。 例:
    manager.suspend_time_on_unacceptable = 10
既定値:
    manager.suspend_time_on_unacceptable = 5
manager.max_connections | 1.3.1から使用可能。 最大同時接続数を指定します。0を指定すると無制限になります。既定値では無制限です。 最大同時接続数の処理を行っているときに新しく接続要求があると、処理中の接続が終了するのを待ちます。処理中の接続が終了したかどうかは manager.suspend_time_on_unacceptable で指定した秒数毎に確認します。 例:
    manager.max_connections = 10 # 同時に最大10接続のみ受け付ける
既定値:
    manager.max_connections = 5
manager.max_file_descriptors | 1.3.1から使用可能。 プロセスが開くことができるファイルディスクリプタ数を指定します。0を指定するとシステムの既定値を変更しません。既定値は0なので、システムの既定値をそのまま使います。 milter-managerは1つのリクエストに対して「子milter数 + 1（MTAとの接続用）」個のファイルディスクリプタを開きます。milter-manager内部でも数個のファイルディスクリプタを開くので少なくとも以下の個数のファイルディスクリプタが開けるようにしてください。
    (子milter数 + 1) * 最大同時接続数 + 10（milter-manager内部で使用 + α）
プロセスが開くことができるファイルディスクリプタ数はsetrlimit(2)でソフトリミットを変更します。 例:
    manager.max_file_descriptors = 65535
既定値:
    manager.max_file_descriptors = 0
manager.custom_configuration_directory | Webインターフェイスから変更した設定内容を保存するディレクトリを指定します。 ディレクトリのパスは「"」で囲んで"/tmp/milter-manager/"というように指定します。 nilを指定した場合は実効ユーザのホームディレクトリ直下に".milter-manager"というディレクトリを作成し、そのディレクトリを利用します。 例:
    manager.custom_configuration_directory = "/tmp/milter-manager/"
既定値:
    manager.custom_configuration_directory = nil

## コントローラ関連

controller.connection_spec | milter-managerを制御するための接続を受け付けるソケットを指定します。 書式はmanager.connection_specと同じです。 例:
    controller.connection_spec = "inet:10026@localhost"
既定値:
    controller.connection_spec = nil
controller.unix_socket_mode | milter-managerを制御するための接続を受け付けるUNIXドメインソケットのパーミッションを指定します。controller.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 8進数で値を指定するために、先頭に「0」をつけることを忘れないでください。 例:
    controller.unix_socket_mode = 0600
既定値:
    controller.unix_socket_mode = 0660
controller.remove_unix_socket_on_create | milter-managerを制御するための接続を受け付けるUNIXドメインソケットを作成する前にすでにファイルが存在した場合、削除するかどうかを指定します。controller.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 削除する場合はtrueを指定します。削除しない場合はfalseを指定します。 例:
    controller.remove_unix_socket_on_create = false
既定値:
    controller.remove_unix_socket_on_create = true
controller.remove_unix_socket_on_close | milter-managerが終了するときに、milter-managerを制御するための接続を受け付けていたUNIXドメインソケットを削除するかどうかを指定します。controller.connection_specでUNIXドメインソケットを使用している場合のみ利用されます。 削除する場合はtrueを指定します。削除しない場合はfalseを指定します。 例:
    controller.remove_unix_socket_on_close = false
既定値:
    controller.remove_unix_socket_on_close = true

## 子milter関連

子milterに関連する設定項目について説明します。

### 子milter定義

子milterは以下の書式で登録します。

    define_milter("名前") do |milter|
      milter.XXX = ...
      milter.YYY = ...
      milter.ZZZ = ...
    end

例えば、「inet:10026@localhost」で接続待ちしているmilterを「test-milter」という名前で登録する場合は以下のようになります。

    define_milter("test-milter") do |milter|
      milter.connection_spec = "inet:10026@localhost"
    end

define_milter do ... end内で設定できる項目は以下の通りです。

必須の項目はmilter.connection_specだけです。

milter.connection_spec | 子milterが接続待ちしているソケットを指定します。 必須項目 です。 書式はmanager.connection_specと同じです。 例:
    milter.connection_spec = "inet:10026@localhost"
既定値:
    milter.connection_spec = nil
milter.description | 子milterの説明を指定します。 説明は「"」で囲んで"test milter"というように指定します。 例:
    milter.description = "test milter"
既定値:
    milter.description = nil
milter.enabled | 子milterを利用するかどうかを指定します。 利用する場合はtrueを指定します。利用しない場合はfalseを指定します。 例:
    milter.enabled = false
既定値:
    milter.enabled = true
milter.fallback_status | 子milterに問題があったとき、指定したステータスを返したとして扱います。 指定できる値は以下のいずれかの値です。 "accept": メールを受信します。既定値です。 "temporary-failure": メールを一時的に拒否します。 "reject": メールを拒否します。 "discard": メールを破棄します。 例:
    milter.fallback_status = "temporary-failure"
既定値:
    milter.fallback_status = "accept"
milter.evaluation_mode | 1.3.1から使用可能。 評価モードにするかどうかを指定します。評価モードでは子milterの結果をMTAに返さないので、既存のメールシステムには影響を与えません。 評価モードでも統計用のログが出力されるため、本来なら子milterがMTAにどのような結果を返していたかを視覚化できます。 評価モードにする場合はtrueを指定します。 false（既定値）の場合は、子milterがrejectを返すとMTAにrejectと返し、処理が終了してします。trueの場合は子milterがrejectを返してもMTAにはrejectを返さず、処理が継続します。継続している処理の中では「子milterがrejectを返した」という情報を利用できます。その情報を利用して適用条件を記述することができます。 例:
    milter.evaluation_mode = true
既定値:
    milter.evaluation_mode = false
milter.applicable_conditions | 子milterを適用する条件を指定します。条件は複数指定できます。1つでも条件を満たさない場合は子milterの適用は中止されます。 利用可能は適用条件は以下のコマンドで確認できます。
    % /usr/local/sbin/milter-manager --show-config | grep define_applicable_condition
    define_applicable_condition("S25R") do |condition|
    define_applicable_condition("Remote Network") do |condition|
この場合は"S25R"と"Remote Network"が利用可能です。 適用条件は標準で提供されているだけではなく、独自に定義することもできます。定義方法については 適用条件関連 を見てください。ただし、独自に定義する場合にはRubyの知識が必要になります。 適用条件は以下のように「,」でくぎって複数指定できます。
    milter.applicable_conditions = ["S25R", "Remote Network"]
例:
    milter.applicable_conditions = ["S25R"]
既定値:
    milter.applicable_conditions = []
milter.add_applicable_condition(name) | 子milterを適用する条件を追加します。適用する条件についてはmilter.applicable_conditionsを見てください。 例:
    milter.add_applicable_condition("S25R")
milter.command | 子milterを起動するコマンドを指定します。security.privilege_modeがtrueでmilter-managerコマンドがroot権限で実行されている場合、milter.connection_specへの接続が失敗した時に、子milterを自動で起動します。そのときに利用するコマンドです。 /etc/init.d/以下や/usr/local/etc/rc.d/以下にある起動スクリプトを指定することを想定しています。 コマンドは「"」で囲んで"/etc/init.d/milter-greylist"というように指定します。自動で起動しない場合はnilを指定します。 例:
    milter.command = "/etc/init.d/milter-greylist"
既定値:
    milter.command = nil
milter.command_options | milter.commandに渡すオプションを指定します。 オプションは「"」で囲んで"start"というように指定します。複数のオプションを指定するときは"--option1 --option2"というように指定します。あるいは、全体を「[]」で囲み、それぞれのオプションを「,」で区切り、["--option1", "--option2"]というように指定することもできます。 例:
    milter.command_options = "start"
    milter.command_options = ["--option1", "--option2"]
既定値:
    milter.command_options = nil
milter.user_name | milter.commandを実行するユーザ名を指定します。 ユーザ名は「"」で囲んで"nobody"というように指定します。root権限で実行する場合はnilを指定します。 例:
    milter.user_name = "nobody"
既定値:
    milter.user_name = nil
milter.connection_timeout | 子milterに接続したときのタイムアウト時間を秒単位で指定します。 例:
    milter.connection_timeout = 60
既定値:
    milter.connection_timeout = 300.0
milter.writing_timeout | 子milterへデータを送信したときのタイムアウト時間を秒単位で指定します。 例:
    milter.writing_timeout = 15
既定値:
    milter.writing_timeout = 10.0
milter.reading_timeout | 子milterからデータを受信するときのタイムアウト時間を秒単位で指定します。 例:
    milter.reading_timeout = 15
既定値:
    milter.reading_timeout = 10.0
milter.end_of_message_timeout | 子milterからxxfi_eom()のレスポンスを受信するときのタイムアウト時間を秒単位で指定します。 例:
    milter.end_of_message_timeout = 300
既定値:
    milter.end_of_message_timeout = 200.0

### 子milter操作

定義された子milterを操作するために便利な機能があります。ただし、これらの機能を利用するには多少Rubyの知識が必要になります。

定義されている子milter名の一覧を取得することができます。

    define_milter("milter1") do |milter|
      ...
    end

    define_milter("milter2") do |milter|
      ...
    end

    defined_milters # => ["milter1", "milter2"]

これを利用することにより、すべての子milterの設定をまとめて変更するということが簡単にできるようになります。

以下はすべての子milterを無効にする例です。

    defined_milters.each do |name|
      define_milter(name) do |milter|
        milter.enabled = false
      end
    end

以下はすべての子milterの適用条件にS25Rを追加する例です。

    defined_milters.each do |name|
      define_milter(name) do |milter|
        milter.add_applicable_condition("S25R")
      end
    end

defined_milters | 定義されている子milterの名前の一覧を返します。返される値は文字列の配列です。 例:
    defined_milters # => ["milter1", "milter2"]

## 適用条件関連

ここからは本格的にRubyの知識が必要になります。標準でS25Rなどの有用な適用条件は用意されています。それらで十分ではない場合は、適用条件を定義することができます。適用条件を定義することにより、子milterを適用するかを動的に判断することができます。

適用条件は以下の書式で定義します。適用条件の定義にはRubyの知識が必要になります。

    define_applicable_condition("名前") do |condition|
      condition.description = ...
      condition.define_connect_stopper do |...|
        ...
      end
      ...
    end

例えば、S25Rを実現する適用条件は以下のようになります。

    define_applicable_condition("S25R") do |condition|
      condition.description = "Selective SMTP Rejection"

      condition.define_connect_stopper do |context, host, socket_address|
        case host
        when "unknown",
          /\A\[.+\]\z/,
          /\A[^.]*\d[^\d.]+\d.*\./,
          /\A[^.]*\d{5}/,
          /\A(?:[^.]+\.)?\d[^.]*\.[^.]+\..+\.[a-z]/i,
          /\A[^.]*\d\.[^.]*\d-\d/,
          /\A[^.]*\d\.[^.]*\d\.[^.]+\..+\./,
          /\A(?:dhcp|dialup|ppp|[achrsvx]?dsl)[^.]*\d/i
          false
        else
          true
        end
      end
    end

名前解決ができなかったときはhostは"unknown"ではなく、"[IPアドレス]"になります。そのため、本当は"unknown"は必要なく、/\A\[.+\]\z/で十分ですが、念のため入れています。 :-)

define_applicable_condition do ... end内で設定できる項目は以下の通りです。

必須の項目はありません。

condition.description | 適用条件の説明を指定します。 説明は「"」で囲んで"test condition"というように指定します。 例:
    condition.description = "test condition"
既定値:
    condition.description = nil
condition.define_connect_stopper {|context, host, socket_address| ...} | SMTPクライアントがSMTPサーバに接続してきたときのホスト名とIPアドレスを利用して子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_connectで利用可能な情報と同じです。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
host | 接続してきたIPアドレスを名前解決して得られたホスト名（文字列）です。名前解決に失敗した場合はIPアドレスが「[]」で囲まれた文字列になります。例えば、"[1.2.3.4]"となります。
socket_address | 接続してきIPアドレスを表すオブジェクトです。詳細は後述します。
以下はクライアントからの接続が名前解決できた場合はmilterを適用しない例です。
    condition.define_connect_stopper do |context, host, socket_address|
      if /\A\[.+\]\z/ =~ host
        false
      else
        true
      end
    end
condition.define_helo_stopper {|context, fqdn| ...} | SMTPクライアントがHELO/EHLOのときに送ってきたFQDNを利用して子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_heloで利用可能な情報と同じです。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
fqdn | SMTPクライアントがHELO/EHLOのときに送ってきたFQDNです。
以下はクライアントから送られてきたFQDNが"localhost.localdomain"の場合はmilterを適用しない例です。
    condition.define_helo_stopper do |context, helo|
      helo == "localhost.localdomain"
    end
define_envelope_from_stopper {|context, from| ...} | SMTPのMAIL FROMコマンドで渡された送信元アドレスを利用して子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_envfromで利用可能な情報と同じです。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
from | MAIL FROMコマンドに渡された送信元です。例えば、"<sender@example.com>"となります。
以下はexample.comから送信された場合はmilterを適用しない例です。
    condition.define_envelope_from_stopper do |context, from|
      if /@example.com>\z/ =~ from
        true
      else
        false
      end
    end
define_envelope_recipient_stopper {|context, recipient| ...} | SMTPのRCPT TOコマンドで渡された宛先アドレスを利用して子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_envrcptで利用可能な情報と同じです。宛先が複数ある場合は複数回呼ばれます。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
recipient | RCPT TOコマンドに渡された宛先です。例えば、"<receiver@example.com>"となります。
以下はml.example.com宛の場合はmilterを適用しない例です。
    condition.define_envelope_recipient_stopper do |context, recipient|
      if /@ml.example.com>\z/ =~ recipient
        true
      else
        false
      end
    end
condition.define_data_stopper {|context| ...} | SMTPクライアントがDATAを送ってきたときに子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_dataで利用可能な情報と同じです。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
以下はDATAまで処理が進んだらmilterを終了する例です。milterがヘッダや本文を書き換えるのはメール全体を処理した後です。DATAの時点でmilterを終了させることにより、milterがヘッダや本文を書き換えないことが保証されます。milterによっては途中の処理結果をログに出力するので、それを見てDATAまでのmilterの動作を確認することができます。
    condition.define_data_stopper do |context|
      true
    end
define_header_stopper {|context, name, value| ...} | メールのヘッダを利用して子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_headerで利用可能な情報と同じです。各ヘッダ毎に呼ばれます。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
name | ヘッダ名です。例えば、"From"となります。
value | ヘッダの値です。例えば、"sender@example.com"となります。
以下は"X-Spam-Flag"ヘッダの値が"YES"の場合はmilterを適用しない例です。
    condition.define_header_stopper do |context, name, value|
      if ["X-Spam-Flag", "YES"] == [name, value]
        true
      else
        false
      end
    end
condition.define_end_of_header_stopper {|context| ...} | ヘッダをすべて処理した後に子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_eohで利用可能な情報と同じです。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
以下はヘッダの処理が完了したらmilterを終了する例です。
    condition.define_end_of_header_stopper do |context|
      true
    end
condition.define_body_stopper {|context, chunk| ...} | 本文の一部を利用して子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_bodyで利用可能な情報と同じです。本文が大きい場合は複数回呼ばれます。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
chunk | 本文の一部です。サイズが大きな本文は一度には処理されずに、いくつかの固まりに分割されて処理されます。最大で65535バイトのデータになります。
以下は本文が署名されていたらmilterを終了する例です。
    condition.define_body_stopper do |context, chunk|
      if /^-----BEGIN PGP SIGNATURE-----$/ =~ chunk
        true
      else
        false
      end
    end
condition.define_end_of_message_stopper {|context| ...} | 本文をすべて処理した後に子milterを適用するかどうかを判断します。このときに利用できる情報はmilterのxxfi_eomで利用可能な情報と同じです。 子milterの適用を中止する場合はtrueを返し、続ける場合はfalseを返します。
context | その時点での様々な情報を持ったオブジェクトです。詳細は後述します。
以下は本文の処理が完了したらmilterを終了する例です。
    condition.define_end_of_message_stopper do |context|
      true
    end

### context

子milterを適用するかどうかを判断する時点での様々な情報を持ったオブジェクトです。（クラスはMilter::Manager::ChildContextです。）

以下の情報を持っています。

context.name | 子milterの名前です。define_milterで使った名前になります。 例:
    context.name # -> "clamav-milter"
context[name] | 子milterが利用可能なマクロの値を返します。libmilterのAPIでは1文字より長いマクロ名の場合は「{}」で囲まなければいけませんが、context[]では囲んでも囲まなくてもどちらでも構いません。 例:
    context["j"] # -> "mail.example.com"
    context["rcpt_address"] # -> "receiver@example.com"
    context["{rcpt_address}"] # -> "receiver@example.com"
context.reject? | 子milterがrejectを返したときにtrueを返します。子milterは milter.evaluation_mode を有効にしてください。 引数として渡ってくるcontextは処理中のため、context.reject?がtrueを返すことはありません。context.children[]で取得した別の子milterの結果を利用するときに有用です。 例:
    context.reject? # -> false
    context.children["milter-greylist"].reject? # -> true or false
context.temporary_failure? | 子milterがtemporary failureを返したときにtrueを返します。子milterは milter.evaluation_mode を有効にしてください。 引数として渡ってくるcontextは処理中のため、context.temporary_failure?がtrueを返すことはありません。context.children[]で取得した別の子milterの結果を利用するときに有用です。 例:
    context.temporary_failure? # -> false
    context.children["milter-greylist"].temporary_failure? # -> true or false
context.accept? | 子milterがacceptを返したときにtrueを返します。 引数として渡ってくるcontextは処理中のため、context.accept?がtrueを返すことはありません。context.children[]で取得した別の子milterの結果を利用するときに有用です。 例:
    context.accept? # -> false
    context.children["milter-greylist"].accept? # -> true or false
context.discard? | 子milterがdiscardを返したときにtrueを返します。子milterは milter.evaluation_mode を有効にしてください。 引数として渡ってくるcontextは処理中のため、context.discard?がtrueを返すことはありません。context.children[]で取得した別の子milterの結果を利用するときに有用です。 例:
    context.discard? # -> false
    context.children["milter-greylist"].discard? # -> true or false
context.quitted? | 子milterの処理が終了している場合にtrueを返します。 引数として渡ってくるcontextは処理中のため、context.quitted?は常にfalseです。context.children[]で取得した別の子milterの結果を利用するときに有用です。 例:
    context.quitted? # -> false
    context.children["milter-greylist"].quitted? # -> true or false
context.children[name] | 別の子milterのcontextを取得します。 別の子milterを参照するときに利用する名前はdefine_milterで使った名前（context.nameで取得できる名前）になります。 存在しない名前で参照しようとした場合はnilが返ります。 例:
    context.children["milter-greylist"] # -> milter-greylistのcontext
    context.children["nonexistent"]     # -> nil
    context.children[context.name]      # -> 自分のcontext
context.postfix? | MTAがPostfixの場合に真を返します。Postfixかどうかは「v」マクロの値に「Postfix」という文字列が含まれるかどうかで判断します。 Postfixの場合はtrue、そうでない場合はfalseが返ります。 例:
    context["v"]     # -> "Postfix 2.5.5"
    context.postfix? # -> true

    context["v"]     # -> "2.5.5"
    context.postfix? # -> false

    context["v"]     # -> nil
    context.postfix? # -> false
context.authenticated? | 送信元が認証されている場合に真を返します。認証されているかどうかは「auto_type」マクロか「auth_authen」マクロの値があるかで判断します。これらのマクロはMAIL FROM以降でのみ使えるので、それ以前の場合は常に偽を返します。Postfixの場合はmain.cfに以下を追加することを忘れないで下さい。
    milter_mail_macros = {auth_author} {auth_type} {auth_authen}
認証されている場合はtrue、そうでない場合はfalseが返ります。 Example:
    context["auth_type"]   # -> nil
    context["auth_authen"] # -> nil
    context.authenticated? # -> false

    context["auth_type"]   # -> "CRAM-MD5"
    context["auth_authen"] # -> nil
    context.authenticated? # -> true

    context["auth_type"]   # -> nil
    context["auth_authen"] # -> "sender"
    context.authenticated? # -> true

### socket_address

ソケットのアドレスを表現しているオブジェクトです。IPv4ソケット、IPv6ソケット、UNIXドメインソケットそれぞれで別々のオブジェクトになります。

#### Milter::SocketAddress::IPv4

IPv4ソケットのアドレスを表現するオブジェクトです。以下のメソッドを持ちます。

address | ドット表記のIPv4アドレスを返します。 例:
    socket_address.address # -> "192.168.1.1"
port | ポート番号を返します。 例:
    socket_address.port # -> 12345
to_s | connection_specと同じ書式で表現したIPv4アドレスを返します。 例:
    socket_address.to_s # -> "inet:12345@[192.168.1.1]"
local? | プライベートなネットワークのアドレスの場合はtrueを返します。 例:
    socket_address.to_s   # -> "inet:12345@[127.0.0.1]"
    socket_address.local? # -> true

    socket_address.to_s   # -> "inet:12345@[192.168.1.1]"
    socket_address.local? # -> true

    socket_address.to_s   # -> "inet:12345@[160.XXX.XXX.XXX]"
    socket_address.local? # -> false

#### Milter::SocketAddress::IPv6

IPv6ソケットのアドレスを表現するオブジェクトです。以下のメソッドを持ちます。

address | コロン表記のIPv6アドレスを返します。 例:
    socket_address.address # -> "::1"
port | ポート番号を返します。 例:
    socket_address.port # -> 12345
to_s | connection_specと同じ書式で表現したIPv6アドレスを返します。 例:
    socket_address.to_s # -> "inet6:12345@[::1]"
local? | プライベートなネットワークのアドレスの場合はtrueを返します。 例:
    socket_address.to_s   # -> "inet6:12345@[::1]"
    socket_address.local? # -> true

    socket_address.to_s   # -> "inet6:12345@[fe80::XXXX]"
    socket_address.local? # -> true

    socket_address.to_s   # -> "inet6:12345@[2001::XXXX]"
    socket_address.local? # -> false

#### Milter::SocketAddress::Unix

UNIXドメインソケットのアドレスを表現するオブジェクトです。以下のメソッドを持ちます。

path | ソケットのパスを返します。 例:
    socket_address.path # -> "/tmp/local.sock"
to_s | connection_specと同じ書式で表現したUNIXドメインソケットアドレスを返します。 例:
    socket_address.to_s # -> "unix:/tmp/local.sock"
local? | 常にtrueを返します。 例:
    socket_address.local? # -> true