OP25B環境下における非常駐sendmail用submit.mcの設定方法

目次


はじめに

これまでのメールでは,ユーザが用いる各種メールソフト(Mail User Agent, MUA)からのメールを受け付けるメールサーバ(Mail Submission Agent, MSA)と,メールの送受信を行うメールサーバ(Mail Transfer Agent, MTA)が,伝統的に同じ25番ポートを用いてきました. (上記のメールサーバはハードウェアそのものではなく,sendmailpostfixといったdaemonを意味しています.) そして,迷惑メールの対策として以下の制限が行われてきました.

  1. 宛先が自ドメイン以外(MUAからMSAとして接続)の場合
    自ドメインのIPアドレスであることが必要.
  2. 宛先が自ドメイン(他ドメインのMTAからMTAとして接続)の場合
    宛先が自ドメインの正規のユーザ名であることが必要.

しかし,上記の制限では現在,以下の事項が問題となっています.

これらの問題の原因は結局,MTAもMSAも同じ25番ポートを用いるので,メールサーバがMTAとして働くかMSAとして働くかは,宛先メールアドレスと接続元のIPアドレスで判断するしかないという点にあります. そこで,最近ではMSAは25番ポートを使用するのではなく,587番ポート(あるいはSMTP over SSLとして465番ポート)を認証(SMTP-AUTH)付きで使用し,従来の25番ポートはMTA同士の通信にのみ使用するという対策が取られつつあります. この流れの中で現在のところ,インターネット接続業者(ISP)では,他ネットワークへの25番ポートの接続を禁止するOutbound Port 25 Blocking(OP25B)を採用する例が増えており,そして,将来的にはMTAの認証という方向に向かうようです. (参考: Japan Email Anti-Abuse Group)

認証付きのMSAが主流となることにより,従来の無認証のMSAが採用しているIPアドレスによる制限が廃止されると思いますので,これからはドメインのメールの送受信を行う正規のメールサーバを除くとメールサーバを起動する必要がなくなります. さらに,上記のOP25BやMTAの認証により,普通のユーザが25番ポートを使えなくなりますので,メールサーバを立ち上げてもメールが送信できなくなります.

最近にバージョンアップされたMUAは,たいていSMTP-AUTHやSMTP over SSLに対応しているのであまり問題はありません. しかし,UNIXのcronやスクリプトなどのメールの送信で用いられる対話的でないコマンドラインのmailやmailxなど(通称binmailやucbmail)では,送信時に内部でsendmailを呼び出すだけなので,SMTP-AUTHやSMTP over SSLへの対応はsendmailで行う必要があります. (メールサーバとしてのsendmailを使っていない場合には,postfixなどが提供するsendmailコマンドが起動されます.)

前置きが非常に長かったのですが,この文章はSMTP-AUTHやSMTP over SSLの環境の中で,binmailによりメールを送信するためのsendmailの設定方法を記したものです. 使用するメールサーバとしてはsendmailではなくpostfixなどでも良いのですが,MXレコードによるメールの自力配送を行わず送信サーバに転送するだけの場合には,sendmailはdaemonとして起動していなくてもbinmailの送信を処理できるという特長がありますので,リソースをなるべく節約するという思想のもと,sendmailの設定方法について述べます. また,本文章でのsendmailはv8.12以降を想定し,各種設定ファイルの場所やデータベースのバイナリファイル形式はLinuxを基準としております.

なお,MTAとMSAの分離に伴い,MSAではメールの送信数制限が実施されるようなので,本文書で述べる方法は,サーバの稼働状況確認などの定時メールや,CGIに伴うメールを送信する方法であり,この方法を用いても迷惑メールの大量送信はできません.


従来の無認証25番ポート接続のための非常駐sendmailの設定

はじめにで書いたとおり今後は使用できなくなる方法ですが,参考のため記述します. 従来の25番ポートを認証無しで用いる場合には,システムに付属する標準状態のsubmit.mcの末尾の"FEATURE(`msp', `[127.0.0.1]')dnl"の代わりに以下を記述します.

      define(`confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')dnl
      MODIFY_MAILER_FLAGS(`LOCAL', `+@ij')dnl
      FEATURE(`msp', `smtp.server.example.org')dnl
    

(上記のsmtp.server.example.orgはMSAサーバのホスト名に変更して下さい.) そして,submit.cfを生成しておけば,sendmailを起動しておかなくても,binmailによるメールをsmtp.server.example.orgに転送します. "MODIFY_MAILER_FLAGS"の最初の+は追加を意味し,残りの文字は"MAIL_SETTINGS_DIR"に置かれた"userdb"ファイルによるアドレスの書き換えの指定です. これについては本文章内のuserdbによるメールアドレスの書き換えを見て下さい.

なお,"MODIFY_MAILER_FLAGS"では以下のフラグも利用できるはずなのですが,試してみたところ,"A"以外はsubmit.mcでは無効なようです. aliasesファイルは結局envelope toの書き換えしかできませんので,"userdb"で全て指定する方が設定の見通しがよくなるのではないかと思います.

フラグ意味
A aliasesによる転送を有効にする.
| aliasesでコマンドに対する転送を有効にする.
/ aliasesでファイルに対する追記を有効にする.
: aliasesで他ファイルのインクルードを有効にする.

また,"aliases"による転送は"FEATURE(`msp', `smtp.server.example.org')dnl"を指定すると無効化されてしまいますので,有効にしたいときは"MODIFY_MAILER_FLAGS"で"A"フラグを追加するとともに以下の順番で指定する必要があります.

      FEATURE(`msp', `smtp.server.example.org')dnl
      define(`ALIAS_FILE', `/etc/aliases')dnl
    

userdbによるメールアドレスの書き換え

前述の通り,これから先にはMTAの認証が導入されようとしているので,ISPが指定したMSAを用いてメールを送信するためには,そのISPが発行したメールアドレスを発信元アドレスに指定しなければならなくなると思います. しかし,binmailにより発信されるメールの発信元のアドレスは,"ユーザ名@ホスト名"というアドレスであり,ホスト名がドメイン名でないので有効なメールアドレスではありません. sendmailでは"userdb"というリストを用いて,ユーザ名に応じて発信元と宛先のアドレスを書き換える機能があり,"MODIFY_MAILER_FLAGS"に以下を追加すると"userdb"によるアドレスの書き換えが有効になります.

フラグ意味
@ userdbを用いたheader fromenvelope toのアドレスの書き換えを有効にする.
i @と同時に指定することで,envelope fromのアドレスも書き換える.
j @と同時に指定することで,header toのアドレスも書き換える.

"userdb"ファイルの書式として,例えばrootのアドレスを管理者のメールアドレス(例えば,kobaia@example.org)に書き換える場合には以下となります.

      root:mailname     kobaia@example.org
      root:maildrop     kobaia@example.org
    

上記の"MODIFY_MAILER_FLAGS"による書き換えでは,envelope toにのみ"maildrop"で指定したアドレスが使われ,その他のheader/envelope fromheader toには"mailname"で指定したアドレスが用いられます.

最初に述べた通り,発信元のアドレス,特にenvelope fromを確実に書き換える必要がありますので,binmailを起動するユーザ全てに対して少なくとも"mailname"で適切なメールアドレスを指定した"userdb"を"MAIL_SETTINGS_DIR"で指定されたディレクトリに作成し,

      # makemap btree userdb < userdb
      # chown root:smmsp userdb*
    

として,データベースを作成しておきます. sendmailはsmmspグループにset gidされており,binmailから起動するとsmmspグループの権限しか持っていないため,"userdb.db"がsmmspグループから読めるようにしておかなければなりません.

MTAの認証のためだけならば,"MODIFY_MAILER_FLAGS"の"j"や"userdb"の"maildrop"で指定する宛先のアドレスの書き換えは不要ですが,メールの迷子を防ぐためになるべく宛先アドレスも書き換えるようにしておく方が良いと思います.


587番ポートへのSMTP-AUTH接続のための非常駐sendmailの設定

接続先を標準の25番ポートから587番ポートに変更し,SMTP-AUTHに対応させるためには,上記と同様に"MAIL_SETTINGS_DIR"で指定されるディレクトリにuserdb, userdb.dbを作成して,"FEATURE(`msp', `[127.0.0.1]')dnl"の代わりにsubmit.mcに記述する内容を

      define(`confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')dnl
      MODIFY_MAILER_FLAGS(`LOCAL', `+@ij')dnl
      FEATURE(`authinfo')dnl
      FEATURE(`msp', `msa.server.example.org', `MSA')dnl
    

とし,さらに認証データを入れる/etc/mail/authinfoとして,

      AuthInfo:msa.server.example.org "U:ユーザ名" "P:パスワード" "M:認証方法"
    

を作ります. (submit.mc, authinfoのmsa.server.example.orgには実際のMSAサーバのホスト名に書き換えて下さい.)

そして,submit.cfを作成して,/etc/mail内で

      # makemap hash authinfo < authinfo
      # chmod 640 authinfo*
      # chown root:smmsp authinfo*
    

として,authinfoのデータベースファイル(authinfo.db)を作成して,所有者/グループを変更します. 上記のuserdbの項で述べた通り,sendmailはsmmspグループにset gidされており,binmailから起動するとsmmspグループの権限しか持っていないので,authinfoはsmmspグループから読めるようにしておく必要があります. また,パスワードが書かれているので一般ユーザからはアクセスできないようにした方がよいでしょう.

authinfoに複数の認証方法を記述し,実際にどれが使われているのか知りたい場合には,submit.mcに

      define(`confLOG_LEVEL', 10)dnl
    

という行を追加して,ログ・レベルを上げておくとログ・ファイルに認証方法が記録されます.


SMTP-AUTH & SMTP over SSLへの接続のための非常駐sendmailの設定

SSLを用いたSMTPの暗号化には,通常と同じ25番ポートや587番ポートを用いて"STARTTLS"以降のセッションを暗号化するTLS(Transport Layer Security)と,465番ポートを用いてセッション全てを暗号化するSMTP over SSLがあります. これらのうち,TLSを用いた暗号化はMUAからMSAの通信およびMTA同士の通信の両方に用いられますが,SMTP over SSLは基本的にMUAからMSAの通信のみに用いられ,MTA同士の通信では用いられていないようです.

この事情のもと,sendmailはTLSには比較的早期のv8.11の頃からMSAの受信とMTAの配送の両方の対応を始めたようです. しかし,SMTP over SSLはv8.13で"DAEMON_OPTIONS"に"M=s"を指定することでMSAの受信に対応しましたが,MTAの配送時に相当する"CLIENT_OPTIONS"では同じオプションの"M=s"は指定しても効果がなく対応していないようです.

そこで,stunnelを使ってSMTP-AUTHをトンネルさせることでsendmailからの配送時におけるSMTP over SSLに対応させます. (本文章ではstunnelのバージョンを4と想定しています.)

まず,stunnelに付属するpop3-redirectを参考にして,以下の内容のsubmission-redirectを/etc/xinet.dに作り,xinetd をreloadします. (xinetdにより587番ポートが開いてしまうので,"only_from"により通信元をlocalhostのみに制限することが重要です. また,sendmailを立ち上げないならば,25番ポート(smtp)に割り当てても構わないのですが,ここでは,常駐sendmailによるSMTP-AUTHプロキシの設定と共存させるため,587番ポート(submission)に割り当てます.)

      service submission
      {
              disable        = no
              only_from      = 127.0.0.1
              socket_type    = stream
              wait           = no
              user           = root
              server         = /usr/sbin/stunnel
              server_args    = /etc/stunnel/xinetd-smtps-client.conf
      }
    

次に,やはりstunnelに付属するstunnel-pop3s-client.confを参考にして,/etc/stunnelに以下の内容のxinetd-smtps-client.confを作ります.

      client = yes
      connect = msa.server.example.org:smtps
      ...
    

前述の例と同様にmsa.server.example.orgは,実際のMSAサーバのホスト名に置き換えて下さい. また,...の部分には,certificateの方法やファイルなどを記述します.

そして,システム付属のsubmit.mcの"FEATURE(`msp', `[127.0.0.1]')dnl"の代わりに以下を記述します.

      define(`confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')dnl
      MODIFY_MAILER_FLAGS(`LOCAL', `+@ij')dnl
      FEATURE(`authinfo')dnl
      CLIENT_OPTIONS(`M=S')dnl
      FEATURE(`msp', `[127.0.0.1]', `MSA')dnl
    

"CLIENT_OPTIONS"の"M=S"は,SMTP over SSLと2重に暗号化するのはあまり意味がないので,TLSによる暗号化を使わないということです.

そして,authinfoを

      AuthInfo:127.0.0.1 "U:ユーザ名" "P:パスワード" "M:認証方法"
    

として,上記と同様にauthinfo.db, さらにuserdb, userdb.dbを作成し, 最後にsubmit.cfを作成すればOKです.


常駐sendmailによるSMTP-AUTHプロキシの設定

非常駐sendmailを使うという本ページの趣旨からは外れますが,これまでの手順を使うと,常駐sendmailによりSMTP-AUTHに対応していなかったり,メールサーバとメーラの提供するSMTP-AUTHが整合していない場合に対する,25番ポートからのSMTPプロキシを立てることができます.

常駐sendmailのアクセス制限

まず,sendmailを常駐させますので,メールの転送を許容するIPアドレスを例えば192.168.1.*とするならば,127.0.0.1と加えて,下記のみの内容の/etc/mail/accessを作成して下さい.

      Connect:127.0.0.1    RELAY
      Connect:192.168.1    RELAY
    

そして,/etc/mail内で

      # makemap hash access < access
    

としてaccessのデータベースファイル(access.db)を作成し,127.0.0.1と192.168.1.*以外はメールの転送を禁止するという設定をします.

なお,Linuxのsendmailはtcp_wrappersをリンクしてビルドされている場合(特にRedHat系)があるので,その時には/etc/hosts.allow, /etc/hosts.denyにも対応する記述が必要となります.

SMTP-AUTH接続の場合

メールサーバが587番ポートへのSMTP-AUTH接続を提供している場合には,最低限必要なsendmail.mcは以下となります.

      OSTYPE(`linux')dnl
      DOMAIN(`generic')dnl
      FEATURE(`access_db')dnl
      FEATURE(`no_default_msa')dnl
      define(`SMART_HOST', `smtp.server.example.org')dnl
      define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl
      FEATURE(`authinfo')dnl
      MAILER(local)dnl
      MAILER(smtp)dnl
    

(上記のsmtp.server.example.orgはMSAサーバのホスト名に変更して下さい.) あとは,SMTP-AUTH接続の場合のauthinfo.dbを作成した後,sendmail.cfを作成して,sendmailを起動すると25番ポートのみを見張り,25番ポートへの認証無しのSMTP接続を,smtp.server.example.orgへのSMTP-AUTH接続へ変換します.

SMTP-AUTH & SMTP over SSL接続の場合

また,メールサーバがSMTP over SSL接続を提供している場合には,上記のようにstunnelを通さなければならないのですが,sendmail.mcの"SMART_HOST"ではlocalhostに送ることができません. そのため,まず以下の/etc/mail/mailertableファイルを準備します. (先頭のピリオドが重要です.)

      .    relay:localhost
    

次に,/etc/mail内で,以下のコマンドによりmailertable.dbを作成します.

      # makemap hash mailertable < mailertable
    

この状況での最低限のsendmail.mcは以下となります.

      OSTYPE(`linux')dnl
      DOMAIN(`generic')dnl
      FEATURE(`access_db')dnl
      FEATURE(`no_default_msa')dnl
      FEATURE(`mailertable')dnl
      define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl
      CLIENT_OPTIONS(`M=S')dnl
      FEATURE(`authinfo')dnl
      MAILER(local)dnl
      MAILER(smtp)dnl
    

あとは,SMTP-AUTH & SMTP over SSL接続の場合の設定の手順でstunnelを設定してauthinfo.dbを作成した後,sendmail.cfを作成して,sendmailを起動すると25番ポートのみを見張り,25番ポートへの認証無しのSMTP接続を,msa.server.example.orgへのSMTP-AUTH & SMTP over SSL接続へ変換します.


うまく送信できない場合の対処法

以上の方法でうまく送信できない場合は何が原因となっているかを確認するため,SMTPのネゴシエーション手順を確認するのが一番の早道と思います. SMTPのネゴシエーション手順を表示するには,rootで以下のように直接sendmailを立ち上げて送信を行います. (参考:Craig Hunt著, TCP/IPネットワーク管理,第3版,オライリー・ジャパン,2003.村井 純,土本 康生 監訳, 林 秀幸 訳.)

      sendmail -Csubmit.cf -v kobaia@example.org
    

"-C"はcfファイルを指定するオプションであり,"-v"は冗長出力のオプションです. 最後に,送信チェックに使用するメールアドレス(上記の例ではkobaia@example.org)を指定します. すると,標準入力からの入力待ちとなりますので,1行程度のメッセージを打ち込み,最後にCtrl-Dあるいは半角ピリオド+Enterでメッセージの終わりを伝えます. すると,送信先のSMTP-AUTHサーバのやり取りが全て表示され,送信先が何故メールを受け取らないかが表示されますので,具体的な対応を考えることができます. なお,SMTP-AUTH認証方法にLOGINやPLAINを使っているときは,上記のネゴシエーションにbase64でコード化したユーザ名とパスワードが表示されているので,掲示板等で質問する際にはネゴシエーションをそのままアップロードしてはいけません. また,送信が拒絶されたメールは送信キュー(submit.cfならば/var/spool/clientmqueue, sendmail.cfならば/var/spool/mqueue)に入るので,拒絶メールを忘れずに削除する必要があります.

一部のプロバイダにおいてメールが送信できない原因としては,587番ポートを待っているMSAではMTAからの送信を想定しておらず,ヘッダに"Received:"が一つでもあると"Too many hops"として拒絶するというものがあります. sendmail.mcやsubmit.mcでは,"Received:"ヘッダの表示内容は変更できますが,"Received:"ヘッダをまったく追加しないことはできないので,筆者はcfファイルからさらに"Received:"ヘッダを削除するためのsedスクリプトとして以下のようなものを作って対応しています. また,転送するMSAサーバにおいてSPF (Sender Policy Framework) が導入されている場合,"Received:"ヘッダがあると送信したIPアドレスが送信メールサーバとして正しいかどうかのチェックが行われるため,同様に"Received:"ヘッダを削除する必要があります.

SMTPの認証方法が分からない場合には下記のようにMSAサーバの587番ポートにtelnetクライアントで接続し,"ehlo"に対する返答を利用して調べる方法があります.

      telnet msa.server.example.org 587
    

ただし,最近はTLSを使わないと認証方法を表示しないサーバーが多いので,その場合は以下のようにopensslを使って接続する必要があります.

      openssl s_client -starttls smtp -crlf -connect msa.server.example.org:587
    

このようにtelnetやopensslで接続した場合,"quit"で接続を終了します.


キューに溜まったメールの配送

メールを送ったときにネットワークが不調だったりメールサーバが止まっていると,sendmailがしばらく送信を試した後,配送できないメールを/var/spool/clientmqueueに保存します. sendmailをデーモンとして動かしている場合には一定時間間隔でキューのメールの処理を行いますが,本文書のようにsendmailを常駐させていないとキューのメールの処理はいつまで経っても行われません. (別のメールを送信する時に一緒にキューのメールを処理しても良さそうなものですが,そういったことは行いません.)

/var/spool/clientmqueueに溜まったメールを一括で送信するためには,rootで以下のコマンドを実行します.

      sendmail -Ac -q
    

SMTP-AUTHに対して本文書で説明した方法のセキュリティ上の問題

本文書でSMTP-AUTHに対して説明した方法には以下のセキュリティの問題があります.

"authinfo"ファイルにおいて,"P:"や"U:"の代わりに"P="や"U="と指定することにより,クリアテキストではなくbase64で符号化して記述することもできますが,スキルがあれば復号は簡単なため,ある程度の抑止力にしかなりません. そのため,これらの方法は個人用のUNIX端末など,端末のrootパスワードを知っている管理者が全員信頼できる場合にのみ用いて下さい. 共用のサーバで上記を設定して他の管理者に自分のメールを盗み読みされても,筆者は一切の責任を持ちません.

また,SMTP-AUTHプロキシについては,SMTP-AUTHに対応していないメーラを使っている特定の個人のためのSMTPプロキシサーバと使うにとどめて下さい. SMTP-AUTHの認証に用いるアカウントとメールの送り主のアドレスが異なる場合に,メールサーバに正常に受理されるかどうか,筆者は一切関知しません.

Last update: 2015.3.19

[機械力学研究室ホームページに戻る]   [田村のホームページに戻る]