送信専用メールアカウントのためのメールサーバー構築

私は開発中の Web アプリケーションから、たくさんのメールを不特定多数に送信したい。そのためにはメール送受信用のメールサーバーを構築すればよいのだが、これが思った以上に大変な作業だった。私が今回必要だったこと、最終的な構成。その経緯をここに記しておこうと思う。

最終的に選択した構成

いわゆる、システムの要件というやつは次のようなものだ。

  • 不特定多数のユーザーに対して、システムの URL を通知するためのメールを送信したい
  • メールの送信タイミングは、年間に数えるほどしかしない
  • ただし1度の送信では数百通のメールを同時送信するような使い方をする
  • 送信用のメールアドレス(例:no-reply@example.com)のようなアドレスから送信出来ればよい
  • なるべく導入コスト、運用コストが小さい構成にしたい

いろいろ検討した結果、次の構成に落ち着いた

  • メールサーバー1台
    • Postfix をインストール
    • POP/IMAP サーバー は特別用意しないことにした(※ 例えば Dovecot などは使わない)
  • Amazon SES(AWS バルクメール配信サービス)を利用
    • これは大量のメールを一括送信するために使用

メールサーバーの構築を始める前に

メールサーバー構築は、今回が初めての経験だったので、いろいろと勉強しながらの作業となった。私は作業を進める中で「メールサーバー構築は大変面倒で、難しい。やらなくて済むのであれば、やらないほうが得」という考えに至った。もし、あなたがこの問題に対して、どのようにするべきか選択することができるのであれば、下記の選択肢を一度検討して欲しい。

Google Apps for Business は、現在では有料のサービスだが、1ユーザーたった 600円/月 で利用できる。このサービスは、あなたの持っている好きなドメインGmail が使えるというものだが、メールサーバー構築に関する厄介な部分を包み隠して、うまくやってくれる。ブラウザでアクセスして、シンプルな設定をいくつか行うだけで、安定したメールインフラを手に入れることができる。
注意しなければいけないのは、Google のメール一括送信に対する次のポリシーである。

メールの一括送信に対して、送信の遅延やアカウントロックなどのペナルティが科されることもあるという。これでは、今回やりたい事として上がっていた「不特定多数のユーザーに数百通のメールを、一斉送信する」という要件を満たすことができない!メールの一括送信というのは、どうやら敏感で面倒な問題らしく、メールの一括送信を解決するソリューションを販売している企業もいくつかあるぐらいだ。(今回、採択した Amazon SES もそのいくつかのソリューションの中の1つということになる)

前提知識

Google Apps は要件に合わなかったため、自分でメールサーバーを構築することになった。前にも話したが、この辺りの知識は全然なかったので、これに関しては勉強しながらの作業となった。実際にやった内容についても、この記事で紹介するつもりだが、やっていることを理解していただくために、みなさんにも抑えておいて欲しい知識がいくつかある。以下に、自分の備忘録としてもまとめておくことにする。

Postfix(ポストフィックス)とは

メールサーバーアプリケーション。代表的な MTA の sendmail の後継となるべく開発された。MTA と MDA の領域の処理を引き受ける。

MUA とは

Massage User Agent の略。ユーザーがメールを扱うためのインターフェースを提供するツール。俗にいう、メールクライアントは MUA と同義。

メールサーバー関連のプロトコルについて

下記の3つのプロトコルについて軽く押さえておくと、混乱が少なくなる。

SMTP とは Simple Mail Transfer Protocol の略で、メールサーバーが電子メールを他のサーバーへ送信したり、自分で受け取ったりするときのためのプロトコル

POP とは Post Office Protocol の略で、メールサーバー内のメールスプールに含まれているメッセージを受け取ったり、削除するためのプロトコル

IMAP とは Internet Message Access Protocol の略で、役割は POP と似ているが、メールスプールのメッセージに対して、移動や検索等を行うことが出来るプロトコル

メールスプールとは

MUA がメールを取り出すまでの保管庫のこと。

DNS サーバー

ホスト名、ドメイン名、IP などのヒモ付けを所有しているサーバー。私たちがホスト名を使って、ネットワークからコンピューターを探しているときに、ホスト名に対応する IP を教えてくれる存在。

MTA とは

Message Transfer Agent の略で、MUA からメールを受け取ってそれを送信したり、外からきたメールを受信し、ローカルの MDA へ仕向けるような働きをする。

MDA とは

Mail Delivery Agent の略で、MTA からメールを受け取って、それをローカルのメールスプールへ書き込む。もしくは、他のメールサーバーへメールを配送したりする。

バーチャルメールボックス(仮想メールボックス)とは

伝統的な Linux のメールサーバーは、1つのサーバーに対して1つのドメイン(例えば example.com など)を割り当て、Linux のユーザー1人に対し、1つのメールアカウントとメールボックスを割り当てる。この場合、メールアカウントを増やすたびに Linux のユーザーを追加して行かなければならない。ユーザーを増やさずにメールアカウントを増減させる仕組みを、バーチャルメールボックスといい、Postfix もこの機能に対応している。


ほとんどのメールサーバーの構成ではバーチャルメールボックスを設定する必要があるだろう。メールサーバーで複数のドメインや、複数のアカウントを気軽に増減させることが出来る。だがしかし、今回の私の構成ではバーチャルメールボックスは利用していない。要件を繰り返すことになるが、必要なのは送信専用の「no-replay@example.com」というアカウントだけであり、これは Linux に「no-reply」というユーザーを増やすだけだ。不要なまでに高度な機能は、安全で安易な方法に置き換えられるならばそうしている。


話は変わるが、思い出したので、ここでもう一つ言及させていただきたい。PostfixAmazon SES の機能をどのように使い分けを行うのかについての、私の方針だ。Postfix はメールの送信・受信に関して、多彩なことを実行できる。その Postfix があるのにわざわざ Amazon SES を利用するのか?


私の環境では、明確に次の役割で使い分けるようにした。

Postfix ... no-reply@example.com と その他 example.com ドメイン宛の全てのメールを受信するためだけに使う。このメールサーバーが、他のサーバーに対してメールを送信することはない。

Aamazon SES ... no-reply@example.com 名義のメールを、不特定多数のユーザーに対して送信するために使う。おそらく Web アプリケーションからメール送信機能を実装するときは、Amazon SES の API を利用することになるだろう。不特定多数にメールを配送するときに、問題が発生し、バウンスメールが返ってくることが考えられる。バウンスメール等は Postfix が動いているメールサーバー側が受け取ることになる。


恥ずかしい話、Postfix についてしっかりとした知識を持っているわけではないため、大量の一括メール送信を行うと、どういう問題が起きるのか、検討がつかない。お手軽な方法ということで、今回 Amazon SES の一括送信機能を利用している。

Step By Step - サーバーで Postfix が使えるようにする

サーバーには作成したばかりの Amazon EC2 インスタンスを利用する。

まずシステムのアップデートと、私の経験上とりあえず入れておいたほうがいいと考えているソフトウェアを yum install する。

$ sudo yum update
$ sudo yum -y install gcc gcc-c++ make zlib zlib-devel openssl openssl-devel \
apr-devel readline readline-devel curl-devel libxml2 libxml2-devel libxslt libxslt-devel

次に、受信したメールを CUI から確認できるように軽量な MUA をインストールする。

# 存在しているかを確認する
$ yum search mailx
...
> mailx.x86_64 : Enhanced implementation of the mailx command
...

# インストール
$ sudo yum install mailx

# 動かしてみる
 $ mail
Heirloom Mail version 12.4 7/29/08. Type ? for help.
"/var/spool/mail/ec2-user": 1 message 1 unread
>U 1 ec2-user@ip-xx-xxx-xx Fri Apr 5 06:06 15/541 "ec2-user”

&

mail コマンドの操作方法は、次のものを押さえておけばとりあえず OK。

  1. q ... 'q' と 'x' はメール画面を終了する。'q' は読んだメールを既読フォルダへ移動して終了する。
  2. x ... 'x' は読んだメールを未読のままにして終了する。
  3. メールを読むときは、読みたいメールの番号を数字で入力する

mail コマンドは標準では、/var/spool/mail にあるメールスプール(Mailbox)を読み込んでいる。

そもそもメールスプールには、2つの種類がある。ひとつは Mailbox 形式、もうひとつは Maildir 形式である。Postfix に何の設定していない場合は、Mailbox 形式が使われている。2つの形式の違いは、大雑把位に説明すると次のようなものであるらしい。

Mailbox 形式 ... ユーザーが受信したすべてのメールを、Linux 上の1つのファイルに追加していく
Maildir 形式 ... ユーザーが受信したメールごとに、ファイルを作成して保存していく

Mailbox 形式は、ファイルが何らかの原因で欠損したりすると、すべてのメールが読み込めなくなるという問題が発生するらしいので、基本的には Maildir 形式を使うようにしたい。

mail コマンドで Maildir 形式のスプールを読み込みたい場合は、次のコマンドを実行する。

# カレントディレクトリに 'Maildir' というスプールがある場合
$ mail -f Maildir/


次に、MTA として Postfix をインストールしていく。もし現在のサーバーで「sendmail」が動作していたら、それを停止して、Postfix を使うように設定を変更する。

# sendmail が動いているかどうか
$ chkconfig | grep sendmail

# もし動いているならば STOP して、自動起動も OFF にする
$ sudo /etc/rc.d/init.d/sendmail stop # STOP
$ sudo chkconfig sendmail off # 自動起動をOFF

# 確認
$ chkconfig | grep sendmail

Postfix のインストールは、yum install を使う。

$ yum install postfix

サーバーは自分が利用する MTA に関する情報を別に持っている。この状態を確認し、sendmail を使うようになっている場合は、Postfix を使うように変更する。

# 状態を確認する
$ sudo alternatives --config mta

There are 2 programs which provide ‘mta’.
  Selection Command
-----------------------------------------------
*+ 1      /usr/sbin/sendmail.sendmail
   2      /usr/sbin/sendmail.postfix

Enter to keep the current selection[+], or type selection number: 2 # ← postfix を使うようにする

# もう一度状態を確認する
$ sudo alternatives --config mta


$ sudo alternatives --config mta

There are 2 programs which provide ‘mta’.
  Selection Command
-----------------------------------------------
*  1      /usr/sbin/sendmail.sendmail
 + 2      /usr/sbin/sendmail.postfix # ← こちらが active になっている

Enter to keep the current selection[+], or type selection number:

この alternatives コマンドによる MTA 変更を、対話型ではなく、ワンライナーにすると次のようになる。【追記:2013-10-29】

# ワンライナー版(※ 実行しても、画面にはなにも出力されません)
$ sudo alternatives --set mta /usr/sbin/sendmail.postfix

Postfix の起動と、自動起動も設定しておきます。

$ sudo postfix start

# 自動起動
$ sudo chkconfig postfix on
$ chkconfig | grep postfix # 変更を確認

Postfix のログは「/var/log/maillog」に出力されます。試験中は問題が発生したときに原因が探れるように、別のウィンドウから「tail」コマンドなどでログを監視しておくとよいです。

$ sudo tail -f /var/log/maillog

試しにメール送信を実行してみます。この時点で、そもそも問題が発生しないかどうかをチェックするためです。ローカルのユーザー 'ec2-user' から自分自身にメールを送信してみます。

$ sendmail ec2-user
From: ec2-user
To: ec2-user
Subject: test

test
.

Postfix の設定ファイルを変更します。初期の設定ファイルから変更したのは次のとおりです。

$ sudo vi /etc/postfix/main.cf

# no-reply@example.com というメールアドレスを作成したい時、
# まず DNS に対して xxx.example.com (今回は例として mail.example.com とする)という
# メールの宛先はどのサーバーなのかを指定する必要がある。
# サーバーにメールがやってきたときに、メールサーバーが自分の管理するメールアカウントかどうかを
# 確認するための設定が いかの mail.example.com というやつ
myhostname = mail.example.com

# no-reply@mail.example.com ではなく no-reply@example.com としたい
# という意味で次の行を追加
mydomain = example.com
myorigin = $mydomain

# このサーバーに外からやって来るメールを受信させるかどうか。
# 受信させるときは 'all' を設定する。
inet_interfaces = all

# メールの送信を利用するのは自分自身だけにする(実際は Amazon SES しか行わないので)
# 「127.0.0.0/8」は「localhost」を表すIPで、「127.0.0.0〜127.255.255.255」の範囲を表すらしい。
mynetworks = 127.0.0.0/8

# Maildir 形式を施用する
home_mailbox = Maildir/

# 自分の管理するドメインのメールを処理対象にする
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain

# 受信するメールの1通あたりの最大サイズ(バイト数)ここでは 1MB に設定
message_size_limit = 1048576
# ユーザーが受信するメールの総容量サイズ(バイト数)ここでは 100MB に設定
mailbox_size_limit = 104857600

変更した設定を Postfix に反映させる。今回は、Postfix を restart しなければいけない設定の変更を行なっているので、stop & start を実行する。普段は reload コマンドで良い。

# inet_interfaces など、重要な設定が変更されたときは reload だと反映されないので restart する
$ sudo postfix stop
$ sudo postfix start

# 普段のちょっとした設定の変更
$ sudo postfix reload

ドメイン付きのメールが受信できるか?ローカルの sendmail でテストして、問題なければ、外部のメーラーから ec2-user@example.com 宛にメール送信してみること。正しく受信できていれば、今回からはホームディレクトリの 'Maildir' という所に保管されていくはず。

$ sendmail ec2-user@example.com
From: ec2-user
To: ec2-user@example.com
Subject: test

test
.

ローカルからは受信が成功するのに、外部からのメールが受信できないときは、DNS の設定をチェック。もしくは SMTP ポート 25 がちゃんと開いているかどうかをチェックすること。ポート開放チェックには次のサイトが便利である。

私は no-reply@example.com というアカウントを作りたいので、「no-reply」という Linux ユーザーを作っておく。メールの内容を確認できるようにログイン可能な、シンプルなユーザーとして追加する。

$ useradd no-reply


これで no-reply@example.com は利用可能になる。メールの不正中継のチェックもしておいたほうがいいので、下記のサイトを参考に検証作業を行う。

以上で、Postfix 側の設定は完了である。なお Amazon SES のバルクメッセージ送信に関しては、この記事の中では紹介しない。

将来考えるべきこと

SPF(Sender Policy Framework)について
http://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/spf/