Postfixによるメール送信設定

僕がLinuxサーバーを構築する際に行う、Postfixによるメール送信設定について、細かく書きます。

ここでいう「メール送信」は、サーバー上で稼働するアプリケーションからのメール送信や、OSやミドルウェアが何らかの情報を通知するためのメール送信のことをいいます。
(PC等からのメールリレーで使用するための)SMTPサーバーやメールの受信、およびメールボックスの構築は含んでいませんのでご注意ください。

サーバーOSはCentOS 6,7やAmazon Linuxで、インターネットへの外向きアクセスが可能な状態を想定しています。

isdアクセス制御

まず、上位のファイアウォールやiptablesで、TCP/25のOutbound通信を許可します。
外部からのメールの受信やメールリレーはしないので、TCP/25のInbound通信は許可する必要はありません。

AWS EC2のサーバーを使用する場合は、TCP/25のOutbound通信制限がかかっているので、必ずEメール上限緩和申請を行いましょう。
申請手順はAWSの以下の資料がわかりやすいです。

・AWS EC2 Eメール上限緩和 / 逆引き(rDNS)設定 申請手順
https://www.slideshare.net/AmazonWebServicesJapan/aws-42885668

isdPostfixの設定

また、Postfix main.cfの各設定パラメータの意味については、次の日本語リファレンスマニュアルが詳しいです。
(少し古いバージョンのものですが、パラメータの意味は変わっていないと思います。)

・Postfix設定パラメータ
http://www.postfix-jp.info/trans-2.3/jhtml/postconf.5.html
 

なお、Postfixのデフォルト設定値は、postfix -d コマンドで確認できます。

 $ postconf -d

2bounce_notice_recipient = postmaster
access_map_defer_code = 450
access_map_reject_code = 554
address_verify_default_transport = $default_transport
...

 

以下、アプリケーションからのメール送信時に、Fromアドレスのドメインとして、@example.jp を使用する場合のPostfixの設定について、CentOS 6でのデフォルト設定からの変更点のみ記述します。
CentOS 7やAmazon Linuxも同じでよいはずです。

 # vi /etc/postfix/main.cf

...
myhostname = example.jp
mydomain = example.jp
myorigin = $mydomain
append_at_myorigin = yes
append_dot_mydomain = yes
inet_interfaces = localhost
inet_protocols = ipv4
mydestination = localhost
mynetworks = 127.0.0.1

 

これぐらいです。
少ないですね。

パラメータをひとつずつ見ていきます。

  • myhostname = example.jp

myhostnameパラメータで、ホスト名をFQDNで指定します。
、、、と言われても、ホスト名として何を設定するのが適切か、迷ってしまうこともありますね。

Postfixのリファレンスやデフォルト設定値を見ると、myhostnameはそれ自体が何かの動作に関連するのではなく、他のパラメータから参照されるデフォルト値として使われます。
「他のパラメータのデフォルト値として使われる」中でも一番影響が大きいのは、これ↓だと思います。

smtp_helo_name = $myhostname

 

smtp_helo_nameパラメータは「宛先のメールサーバーとSMTP接続した際に、SMTP EHLOコマンドで送るホスト名」です。
このとき、このホスト名がDNSで正引きできないと、宛先のメールサーバーから受信拒否されます。
ですので、ここでは、DNSで正引きできる(=Aレコードが存在する)ホスト名を指定します。
「アプリケーションからのメール送信時にFromアドレスのドメインとして使用する名前」を設定するのが確実だと思います。

もしこのサーバーでマルチドメインのWebサービスを稼働させ、Fromアドレスも複数のドメインを使用するなら、何でもよいので自社で管理するドメインの、DNSで正引きできるホスト名を指定します。

なお、DNS正引きのIPアドレスと、Postfixを設定するサーバーのIPアドレスが一致する必要はありません。
 

  • mydomain = example.jp

mydomainパラメータで、ドメイン名をFQDNで指定します。
mydomainも、それ自体が何かの動作に関連するのではなく、他のパラメータから参照されます。
「他のパラメータで使われる」中でも影響が大きいのは、myoriginとappend_at_mydomainだと思いますが、それぞれのパラメータのところで説明します。

メール送信サーバーでは、ここはあまり深く考えず、「アプリケーションからのメール送信時にFromアドレスのドメインとして使用する名前(つまりmyhostnameと同じ名前)」を設定するのが確実だと思います。
 

  • myorigin = $mydomain
  • append_at_myorigin = yes
  • append_dot_mydomain = yes

myoriginも、append_at_myorigin等の他のパラメータから参照されます。

append_at_myoriginパラメータで、「ドメイン情報のないFrom/To/Ccアドレスに ‘@<$myorigin>‘ を付与するかどうか、を指定します。
このパラメータが意味を持つのは、OSやミドルウェアが何らかの情報を通知するためのメールを送信する場合です。
このときのメールは、Fromアドレス(やToアドレス)が「root」や「当該プロセスの実行ユーザー」となり、@以下のドメイン名がついていないので、多くの場合、「送信元メールアドレスが不正」という理由で宛先のメールサーバーに受信拒否されます。
それを防ぐために ‘@<$myorigin>‘ を付与する、というわけです。

myoriginとしては、$myhostnameか$mydomainを指定することが多いです。
今回は$myhostnameも$mydomainも同じ名前にしているので、どちらでも構いません。

append_dot_mydomainパラメータで、メール送信時に、.domainのない(=FQDNとなっていない)From/To/Ccアドレスに ‘@<$mydomain>‘ を付与するかどうかを指定します。

※append_at_myoriginとappend_dot_mydomainはデフォルトがyesなので、わざわざmain.cfに追記しなくてもよいのですが、重要な意味を持つので、僕は明記するようにしています。
 

  • inet_interfaces = localhost

inet_interfacesパラメータで、待ち受ける(=Listenする)ネットワークアドレスを指定します。
今回のサーバーではメールを送信するのみで、外部からは一切受信、リレーせずサーバー自身でのローカル配送のみ処理するので、localhostとします。
 

  • inet_protocols = ipv4

inet_protocolsで、Postfixが使用するインターネットプロトコルを指定します。
IPv6を使用しない場合、かつデフォルトではIPv6にも対応するよう all となっている場合は、IPv4のみ使用する設定に変更します。
 

  • mydestination = localhost

mydestinationでは、メールを外部に送信せずに、このサーバーローカルで配送処理するドメインのリストを指定します。
$mydomain, $myhostname を含めると、~@example.jp 宛のメールを外部に送信しなくなってしまうので、ここには含めず、localhostのみ許可するようにします。
 

  • mynetworks = 127.0.0.1

mynetworksパラメータで、メールリレーを許可するホストのIPアドレスリスト、レンジを指定します。
今回のサーバーではメールを送信するのみで、外部からは一切受信せず、サーバー自身でのローカル配送のみ行うので、ローカルループバックアドレス 127.0.0.1 とします。
仮にここで全IPアドレスを表す 0.0.0.0/0 として、ファイアウォールの設定でTCP/25のInbound通信を許可すると、いわゆる「オープンリレー」サーバーとなりスパムメール送信の踏み台となり得るので注意が必要です。

※mynetworks_style = host でも同じ意味となるのですが、mynetworksパラメータで値を設定するとmynetworks_styleの設定値が無視されてしまうので、セキュリティ強化の意味では、mynetworksでしっかり制限するのが確実だと思います。

※余談になりますが、重要そうなmyhostnameやmydomainが他のパラメータで参照されるだけだったり、「パラメータBが設定されるとAの設定が無視される」といったところが、Postfixの設定が難しい、面倒、と思われる要因のひとつのような気がします。

以上がメール送信のためのPostfixの設定となります。

isdPostfixの起動と動作確認

起動する前に、文法チェックを行います。
何も出力されなければOKですが、メッセージが出力されたときは、何らかの問題があるのでメッセージに従って対処します。

 # /etc/init.d/postfix check

 

Postfixを起動します。
(クラウド環境等で、デフォルトでPostfixが起動している場合は、restartで再起動します。)

 # /etc/init.d/postfix start

 

メールログで、何かエラーがないか確認します。

 # less /var/log/maillog

--
Jun 17 18:15:55 mailtest postfix/postfix-script[1552]: starting the Postfix mail system
Jun 17 18:15:55 mailtest postfix/master[1553]: daemon started -- version 2.6.6, configuration /etc/postfix
--

 

動作確認のため、一般ユーザでmailコマンドを使用してテストメールを送信します。
メール本文はechoコマンドでmailコマンドに渡します。
-sオプションでサブジェクトを指定し、最後に宛先アドレスを指定します。

 $ echo "This is Test Mail from example.jp server." |\
    mail -s "test mail from example.jp server." <宛先アドレス>

 

テストメールが正しく届いたことと、メールログを確認します。

 # less /var/log/maillog

--
Jun 17 18:19:43 mailtest postfix/pickup[26754]: 75217403D7: uid=1099 from=<user1>
Jun 17 18:19:43 mailtest postfix/cleanup[26762]: 75217403D7: message-id=<20160617xxxxxxxx.75217403D7@example.jp>
Jun 17 18:19:43 mailtest postfix/qmgr[26755]: 75217403D7: from=<user1@example.jp>, size=539, nrcpt=1 (queue active)
Jun 17 18:19:43 mailtest postfix/smtp[26764]: 75217403D7: to=<宛先アドレス>, relay=<宛先のメールサーバー>[<宛先メールサーバーのIPアドレス>]:25, delay=0.35, delays=0.07/0.02/0.17/0.09, dsn=2.0.0, status=sent (250 2.0.0 u0Q6hhdxxxxxxx Message accepted for delivery)
Jun 17 18:19:43 mailtest postfix/qmgr[26755]: 75217403D7: removed
--

 

問題なければ、自動起動設定を行います。

 # chkconfig postfix on

 # chkconfig --list postfix

postfix         0:off   1:off   2:on    3:on    4:on    5:on    6:off

 

これで、サーバー上のアプリケーションからは、SMTPサーバーとして localhost または 127.0.0.1 を指定するだけで、インターネット上の任意のアドレス宛にメールを送信できます。
認証は不要です。

 アプリケーション –> Postfix –> 宛先アドレスのメールサーバー

Postfixのメール送信設定と動作確認は完了!
、、、ではなくまだ続きがあります。

isdroot宛メールの転送設定

Linuxサーバーでは、OSやミドルウェアが何らかの情報をroot宛のメールで通知することがあります。
細かくいうと、OS上で動作する基本的なソフトウェアやミドルウェアのデフォルト設定で、root宛になっているんですね。
(root宛ではなく各プロセスの実行ユーザー宛になっているものもあります。)

サーバーを運用するうえで重要な情報ですので、このメールはサーバー管理者のメールアドレスに転送するべきです。

サーバー上でPostfixやsendmail等のメール配送サービスが動作していなければ、このメールはどこにも送信されません。
Postfixやsendmailがデフォルト設定のまま起動していれば、サーバー上のrootユーザーのメールボックスにメールが溜まります。

上記のように、

mydomain = example.jp
myorigin = $mydomain
append_at_myorigin = yes

 

と設定すると、宛先の「root」にmyoriginを付与して「root@example.jp」に送信しようとするのですが、example.jpドメインのメールボックスで「root@example.jp」のメールアドレスが用意されていないと、送信エラーとなります。

そこで、サーバー上のPostfixのtransportというメール配送マッピング設定とメールエイリアス設定で、root宛メールの転送設定を行います。
「いったん強制的にローカルに配送してから、メールエイリアス設定に従って転送させる」という方針です。

Postfixの設定で、transport_mapsパラメータを追記します。

 # vi /etc/postfix/main.cf

...
transport_maps = hash:/etc/postfix/transport

 

  • transport_maps = hash:/etc/postfix/transport

transport_mapsパラメータで、マッピングテーブルのファイルを指定します。
 

次に、transportテーブルを作成します。
1行目はroot@example.jp 宛のメールはローカルに配送する
2行目は、それ以外のメールはすべて外部に送信する
という意味です。

 # vi /etc/postfix/transport

root@example.jp local:
* :

 

ハッシュ形式のマッピングテーブルファイルを生成します。

 # /usr/sbin/postmap /etc/postfix/transport

 # ls -l /etc/postfix/transport*

-rw-r--r-- 1 root root 12538  6月 17 18:42 2016 /etc/postfix/transport
-rw-r--r-- 1 root root 12288  6月 17 18:42 2016 /etc/postfix/transport.db

 

最後に、メールエイリアステーブル/etc/aliasesに、root宛メールの転送先アドレスを記述します。
複数のアドレスに転送する場合は、カンマ区切りで指定します。

 # vi /etc/aliases

...
root:       <転送先アドレス1>,<転送先アドレス2>

 

newaliasesコマンドでエイリアスハッシュファイルを更新します。

 # newaliases

 # ls -l /etc/aliases*

-rw-r--r--. 1 root root  1548  6月 17 18:45 2016 /etc/aliases
-rw-r--r--  1 root root 12288  6月 17 18:45 2016 /etc/aliases.db

 

動作確認のため、mailコマンドでroot宛にテストメールを送信してみます。

 # echo "This is Test Mail from example.jp server." |\
    mail -s "test mail from example.jp server." root

 

テストメールが正しく転送先アドレスに届いたことと、メールログを確認します。

 # less /var/log/maillog

--
Jun 17 18:44:56 maitest postfix/pickup[1673]: 8C2C37C1F: uid=0 from=<root>
Jun 17 18:44:56 maitest postfix/cleanup[1682]: 8C2C37C1F: message-id=<20160617xxxxxx.8C2C37C1F@example.jp>
Jun 17 18:44:56 maitest postfix/qmgr[1674]: 8C2C37C1F: from=<root@example.jp>, size=515, nrcpt=1 (queue active)
Jun 17 18:44:56 maitest postfix/cleanup[1682]: 918247C19: message-id=<20160617xxxxxx.8C2C37C1F@example.jp>
Jun 17 18:44:56 maitest postfix/qmgr[1674]: 918247C19: from=<root@example.jp>, size=657, nrcpt=1 (queue active)
Jun 17 18:44:56 maitest postfix/local[1693]: 8C2C37C1F: to=<転送先アドレス>, orig_to=<root>, relay=local, delay=0.03, delays=0.01/0.01/0/0, dsn=2.0.0, status=sent (forwarded as 918247C19)
Jun 17 18:44:56 maitest postfix/qmgr[1674]: 8C2C37C1F: removed
Jun 17 18:44:56 maitest postfix/smtp[1684]: 918247C19: to=<転送先アドレス>, orig_to=<root>, relay=<転送先のメールサーバー>[<転送先メールサーバーのIPアドレス>]:25, delay=0.19, delays=0/0/0.13/0.06, dsn=2.0.0, status=sent (250 2.0.0 u5K3iuMd0xxxxx Message accepted for delivery)
Jun 17 18::56 maitest postfix/qmgr[1674]: 918247C19: removed
--

 

これで、サーバーのroot宛メールを自動転送し、サーバー管理者がサーバー側で発生した何らかの情報を受信できるようになります。

※root以外のユーザー宛メールを自動転送する場合は、transportテーブルで <ユーザー名>@example.jp のエントリーを、メールエイリアステーブル /etc/aliases で <ユーザー名>と転送先アドレスのエントリーをそれぞれ追加すればよいです。

このように「サーバーのroot宛メールを、受信側のメールサーバーに拒否されないようにしつつうまく転送する方法」は案外難しくずっと悩んでいて、最終的にこの方法にたどりつきました。
もっとスマートな方法があれば教えてほしいです(笑)

isd迷惑メールとみなされないための対策

サーバーから送信するメールが迷惑メールとみなされないようにする(=受信メールサーバー側での迷惑メール判定スコアを下げる)ための、Postfixの設定以外の有効な対策としては、SPFレコードの登録と、DNS逆引き設定があります。

SPFレコードの登録

SPFによる送信ドメイン認証として、DNSのSPF(TXT)レコードに、Fromアドレスのドメインと、メール送信元サーバーのIPアドレスやホスト名の組み合わせを登録します。
SPFレコードについては、以前このブログでも記事を書きました。

・SPFレコードの登録を忘れずに
https://inaba-serverdesign.jp/blog/20150909/spf_send_mail.html

SPFレコードを登録する際は、Fromアドレスのドメインを使用してメール送信するすべてのサーバーの情報を登録するのを忘れずに。
たとえば、サービス用のドメイン(example.jpなど)とは異なる自社ドメイン(example.co.jpなど)をFromアドレスに使用するのに、自社ドメインのSPFレコードへの追加設定が抜けていて迷惑メールとみなされてしまう、というのはよくあるケースです。

DNS逆引き設定

DNS逆引きについては、基本的には「どんな名前でもよいので、逆引きができれば(=逆引きレコードが登録されていれば)OK」のはずです。
「メール送信時にFromアドレスのドメインとして使用する名前」が1つに決まっていて、逆引き登録が可能であれば、その名前を登録すると、迷惑メールの判定スコアが下がると思われます。

isd外部メールサービスの利用について

Postfixの設定を行わずに、Gmailや「さくらのメールボックス」など、すでに契約・利用している外部メールサービスのSMTP機能をそのまま利用して、アプリケーションからメールを送信するケースも多いようです。

 アプリケーション –> 外部メールサービスのメールサーバー –> 宛先アドレスのメールサーバー

Fromアドレスのドメインを使用した送信実績があるメールサービスをそのまま使えば、迷惑メールとみなされないでしょうし、Postfix等のメール送信サーバーの設定が不要となるので一見便利ですが、個人的には、次の点でおすすめしません。

  1. 外部メールサービス側の何らかの制限でメールが送信できない場合がある。
  2. メール送信ログを見れないので調査できない。
  3. root宛メールを見逃す。

1.の「外部メールサービス側の何らかの制限」については、「通数制限」や「IPアドレス制限」があるでしょう。
GmailのSMTPリレーについては、「1日あたり1万通または1万宛先アドレス」と公表されています。

・Google Apps管理者ヘルプ SMTPリレーサービスの送信制限
https://support.google.com/a/answer/2956491

「さくらのメールボックス」は非公表のようですが、他の方から「○分あたり○通」という制限があると聞いたことがあります。

また、IPアドレス制限については、「さくらのメールボックス」で「国外IPアドレスフィルタ」を有効にしていると、AWS TokyoリージョンのEC2のサーバーから送信しても拒否される、というのがわりと有名な話です。

(参考)
・さくらインターネットのレンタルサーバ経由でメールが送れなくなった。
http://d.hatena.ne.jp/y_fudi/20140320/1395268800

・さくらのサポート情報 国外IPアドレスフィルタ
https://help.sakura.ad.jp/app/answers/detail/a_id/2258

このように外部メールサービスの何らかの制限でメール送信に失敗した場合、アプリケーションから外部のメールサーバーに直接アクセスするので、アプリケーションのログには何か記録されているかもしれませんが、サーバーのメールログには記録されませんから、サーバー構築担当者としては調査しにくいんですね。

3.については、先に記載したとおり、Postfix(またはsendmail)でメール送信サーバーの設定や転送設定を行わないと、アプリケーション以外のOSやミドルウェアが発信する何らかのメールが送信されないか、メールボックスに溜まってしまい、重要な情報を見逃してしまう可能性があります。

ですので、上記のディメリットを踏まえたうえで、アプリケーションから外部メールサービス経由でメールを送信するのはそれはそれでよいのですが、やはりPostfixによるメール送信設定・転送設定も行うべきだと考えます。

isdまとめ

Postfixによるメール送信設定と、メール送信にあたってPostfix以外に考慮すべきポイントについてまとめました。

今さらPostfixの設定手順って、、という気もしますが、
「Postfixの設定は難しい、めんどくさい」
「外部のSMTPサービスを使用するのでメール送信の設定は不要」
という話をたまに聞くので、書いてみました。
ここに記載した設定は、root宛メールの転送方法など、ベストではないかもしれませんが、ベターな設定だと自分では思っています。

なお、メール受信、メールボックスについては、サーバー構築・運用の人員体制が整っていない限り、「さくらのメールボックス」「カゴヤのメールサーバー」「CPI共用レンタルサーバー」等のメールサービスの利用をおすすめします。
SMTPサーバーやメールボックスについては、認証、スパム・ウイルス対策等、とくにセキュリティ面で、Webサーバーよりはるかに構築や運用が大変だと思います。
「メールが使えない」のは「Webサーバーがダウンしている」と同等かそれ以上にインパクトが大きいのではないでしょうか。

また、Webサーバーとメールサーバーは、それぞれの影響を受けないよう分離することをおすすめします。
これは、どちらかの不具合でWeb、メールの両方がダウンしてしまうことを防ぐためです。
「Webサーバーに何らかの不具合が発生しているが、不具合に関するユーザー、顧客、関係者からの問い合わせや連絡のメールを受信できない」
というような事態は避けたいところです。

※CPIの共用レンタルサーバーは、Webサーバーとメールサーバーが分離されているのがいいですね。

(関連記事)
・Postfixによるメール転送設定
https://inaba-serverdesign.jp/blog/20160623/postfix_relay_mail.html

・SPFレコードの登録を忘れずに
https://inaba-serverdesign.jp/blog/20150909/spf_send_mail.html
 

Follow me!