PostfixからSendGridへのリレーをカスタマイズする

はじめに

今回は、SendGridをSMTPのリレーサーバとして利用する際のテクニックをいくつかご紹介します。次のような課題解決のヒントになれば幸いです。

  • ケース1:宛先ドメイン毎のリレー制御
    例えば、特定ドメイン宛のメールのみSendGridを経由して送信し、他のドメイン宛のメールについては、自前のメールサーバから直接送信するといったケースです。
  • ケース2:SendGridへ移行時のウォームアップ
    既に自前のメールサーバから大量のメールを継続的に送信している状態からSendGrid経由での送信に切り替える場合、全トラフィックをいきなりSendGrid経由で送信するとウォームアップ不十分のため配信トラブルに陥る可能性があります。こういったトラブルを避けるために、はじめはSendGrid経由のメールを制限し、徐々にその割合を増やすことを目的としたケースです。
  • ケース3:SendGrid以外に複数のメール配信サービスを利用し可用性を向上する
    SendGrid含め複数のメール配信サービス経由で送信できるようにしておき、特定の配信サービスが利用できない場合に自動的に別の配信サービスに切り替えることを目的としたケースです。

対象としているメールサーバはPostfixで、Ubuntuを使って環境構築しました。また、ケース2と3ではリレー先を制御するのにbindというDNSを利用しています。

ケース1:宛先ドメイン毎のリレー制御

1. 構成イメージ

宛先ドメイン毎のリレー先制御はPostfix単体で実現できます。以降の説明はすべてPostfixをインストールしたホスト上での設定です。

ケース1:宛先ドメイン毎のリレー制御

2. main.cfの編集

/etc/postfix/main.cfファイルを以下のように設定します。

# SASL認証設定有効化
smtp_sasl_auth_enable = yes
# 匿名ログインを許可しない
smtp_sasl_security_options = noanonymous
# 日和見TLS
smtp_tls_security_level = may            
# ドメイン毎のリレー先設定
transport_maps = hash:/etc/postfix/transport
# リレー先毎のSMTP認証情報
smtp_sasl_password_maps = hash:/etc/postfix/relay_password
3. 宛先ドメイン毎リレー先設定

/etc/postfix/transportファイルにドメイン毎のリレー先設定を行います。以下の設定では、宛先ドメインが「@sink.sendgrid.net」の場合にSendGridにリレー(1行目)し、その他の宛先についてはリレーせずに直接送信(2行目)を行います。1行目を参考にして宛先ドメインとそのリレー先設定を追加していくことでSendGrid経由でリレーする宛先ドメインを増やしていくことができます。

sink.sendgrid.net       smtp:[smtp.sendgrid.net]:587
*                       :
4. リレー先毎のSMTP認証設定

/etc/postfix/relay_passwordファイルにSMTP認証を必要とするリレー先のために認証情報を設定します。SendGridのSMTP認証情報としてメール送信パーミッションを持ったAPIキーを利用することをお勧めします。

[smtp.sendgrid.net]:587 apikey:SendGridのAPIキー
5. 設定ファイルのハッシュ化

3と4で作成した設定ファイルをそれぞれハッシュ化します。

$ sudo postmap /etc/postfix/transport
$ sudo postmap /etc/postfix/relay_password
6. Postfixの再起動

Postfixを再起動して設定を反映させます。

$ sudo postfix stop
$ sudo postfix start

以上で設定完了です。

7. 動作確認

動作確認を行うため、mailコマンドをインストールして次のようにメールを送信します。メールのリレー経路は、受信したメールヘッダで確認できます。SendGrid経由でリレーしたものはダッシュボードのActivity上にも表示されます。

$ sudo apt-get install mailutils
$ echo "Hello sink" | mail -s "Hello sink" -aFrom:from@example.com to@sink.sendgrid.net
$ echo "Hello kke" | mail -s "Hello kke" -aFrom:from@example.com to@kke.co.jp

ケース2:SendGridへ移行時のウォームアップ

1. 構成イメージ

今回は、同一優先度のMXレコードを複数用意して、Postfixがランダム配送する仕組みを利用してリレー先を分散します。以下のような構成にします。

  • mail
    クライアントからのメール送信リクエストを受け付けます。また、ローカルにインストールしたbindからMXレコードを参照してrelay1またはrelay2にメールをリレーします。パブリックなDNSサービスを利用しても良いのですが、影響範囲を最小化するためにローカルのbindを利用しています。
  • relay1およびrelay2
    mailホストからリレーされたメールをそれぞれ設定に従ってリレーします。今回はrelay1をSendGridへのリレー用とし、relay2からは宛先サーバに直接送信(既存のリレー経路を想定)します。

ケース2:SendGridへ移行時のウォームアップ

2. mailホスト上のPostfix設定

mailホストのPostfixでリレー先のホストを設定(/etc/postfix/main.cfファイル)します。ここで設定するリレー先「relay.example.local」はこの後設定します。

relayhost = relay.example.local

次にmailホストのPostfixがローカルのbindを参照して名前解決するようレゾルバ設定(/var/spool/postfix/etc/resolv.conf)を次のように変更します。

nameserver 127.0.0.1
domain example.local

Postfixを再起動して設定を反映させます。

$ sudo postfix stop
$ sudo postfix start
3. mail上のbind設定

mailホストのbindを設定します。/etc/bind/named.conf.default-zonesファイルにexample.localという名前でゾーンを作成します。ゾーン名はローカルに閉じた環境で利用するものなので何でも構いません。

zone "example.local" {
        type master;
        file "/etc/bind/example.local.zone";
};

example.localゾーン内のレコードは/etc/bind/example.local.zoneファイルに記述します。
例えば、MXレコード5つのうち、1つだけをrelay1ホストに、残りをrelay2となるよう設定した例は以下の通りです。これで理論上、全体の20%のメールがrelay1ホストを経由してSendGridにリレーされるはずです。ウォームアップスケジュールに合わせてSendGrid経由でリレーするMXレコードの割合を増やしていくことで徐々にその割合を増やしていくことができます。

$TTL    86400
@       IN      SOA     example.local. root.example.local. (
                                2017063002      ; Serial
                                3600            ; Refresh
                                900             ; Retry
                                3600000         ; Expire
                                86400 )         ; Minimum
        IN      NS      ns.example.local.
ns      IN      A       10.1.0.4
relay   IN      MX      10      relay10.example.local.
relay   IN      MX      10      relay20.example.local.
relay   IN      MX      10      relay21.example.local.
relay   IN      MX      10      relay22.example.local.
relay   IN      MX      10      relay23.example.local.
relay10 IN      A       10.1.0.5
relay20 IN      A       10.1.0.6
relay21 IN      A       10.1.0.6
relay22 IN      A       10.1.0.6
relay23 IN      A       10.1.0.6

bindの設定が完了したので起動します。

$ sudo systemctl enable bind9
$ sudo systemctl start bind9
4. relay1およびrelay2上のPostfix設定

relay1ホストのPostfixはSendGridにリレーするよう設定/etc/postfix/main.cfファイル)します。

# ホスト名を指定
myhostname = relay1.example.local

# mynetworksに現在のネットワークアドレスを追加
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.1.0.0/24

# mynetworksからのアクセスを許可
smtpd_client_restrictions = permit_mynetworks, reject

# SendGrid向けのリレー設定
smtp_sasl_password_maps = static:apikey:SendGridのAPIキー
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
relayhost = [smtp.sendgrid.net]:587

一方、relay2ホストのPostfixはリレーせずに直接宛先に配信するよう設定(/etc/postfix/main.cfファイル)します。

# ホスト名を指定
myhostname = relay2.example.local

# mynetworksに現在のネットワークアドレスを追加
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.1.0.0/24

# mynetworksからのアクセスを許可
smtpd_client_restrictions = permit_mynetworks, reject

それぞれPostfixを再起動して設定を反映させます。

$ sudo postfix stop
$ sudo postfix start
5. 動作確認

動作確認を行うため、mailホスト上からメールを送信します。メールを繰り返し送信すると、リレー先が分散されるはずです。リレー経路は実際に届いたメールのヘッダで確認できます。

$ sudo apt-get install mailutils
$ echo "Hello kke" | mail -s "Hello kke" -aFrom:from@example.com to@kke.co.jp
$ echo "Hello kke" | mail -s "Hello kke" -aFrom:from@example.com to@kke.co.jp
$ echo "Hello kke" | mail -s "Hello kke" -aFrom:from@example.com to@kke.co.jp
:

ケース3:SendGrid以外に複数のメール配信サービスを利用し可用性を向上する

基本的な構成はケース2と同じですが、relay1とrelay2のMXレコードの優先度に差をつけることで優先度の高いサーバに優先的にリレーすることができます。こうすると、優先度の高いサーバが利用できない場合は、自動的に次に優先度の高いサーバにリレーします。この挙動を利用してメインのメール配信サービスが利用できない場合に自動的にフォールバックしてサブの配信サービスに切り替えることが可能になります。

/etc/bind/example.local.zoneファイルを以下のように設定すると、通常はrelay10.example.localにリレーされますが、relay10.example.localに問題がある場合はrelay20.example.localに自動的にリレーします。

$TTL    86400
@       IN      SOA     example.local. root.example.local. (
                                2017063003      ; Serial
                                3600            ; Refresh
                                900             ; Retry
                                3600000         ; Expire
                                86400 )         ; Minimum
        IN      NS      ns.example.local.
ns      IN      A       10.1.0.4
relay   IN      MX      10      relay10.example.local.
relay   IN      MX      20      relay20.example.local.
relay10 IN      A       10.1.0.5
relay20 IN      A       10.1.0.6

さいごに

アプリケーションから簡単にメール送信できるのが特徴のSendGridですが、元々SMTPリレーサービスですので、複雑なリレー構成の中にも柔軟に組み込むことができます。SendGridを経由することで、送信ドメイン認証設定(SPFやDKIM)やバウンス管理、トラッキングデータの一元化など、「送信用メールゲートウェイ」的な使い方もできますのでぜひお試しください