
最近、メールクライアントとして使用しているBecky!からGMailアドレスへのメール送信が時々失敗するようになりました。というより、送信できることの方が少ない状態に陥りました。
原因調査
Googleがセキュリティを強化したためかと思い、ググってみました。確かに直近では2022年5月30日にGoogle以外のアプリからのパスワード(だけの)認証のサポートを終了する旨の記事は多々見つけました。しかし、あまり関係なさそうだと思っていました。
Postfixから返ってきた通知メールの中にGoogleメールサーバの返答に以下のような記述がありました。
<******@gmail.com>: host *******.google.com[xxx.xxx.xxx.xx] said: 550-5.7.1 [yyy.yyy.yyy.yyy] Our system has detected that this message is 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail, 550-5.7.1 this message has been blocked. Please visit 550-5.7.1 https://support.google.com/mail/?p=UnsolicitedMessageError 550 5.7.1 for more information.
メッセージの中にfor more information.とありURLが書かれていたのでアクセスしてみました。
見ていくと迷惑メール対策を強化していく旨の記述がありました。やはりブロックされている可能性が高くなりました。
さらに『メールが確実に認証されるようにする』が見出しの記事の中に、
- SPFレコードを公開する
- DKIM署名を有効にする
- DMARCレコードを公開する
とありました。
おそらくこれらを実装していないことが原因でSPAMと判断されてブロックされているのでしょう。
Googleが手動でセキュリティの高いインフラが出来上がっていくのは喜ばしいことではありますが、もう少し広告してからにしてもらえると助かるのですが、きっと私が気が付かなかっただけなのでしょうね。やれやれ。
と嘆いていても仕方がないので、3つのキーワードSPF、DKIM、DMARCを実装することにしました。
実装するにあたり
3つの機能を実装するにあたり、ひとつ大きな前提条件があります。
私の環境では、Postfix/Cyrus-IMAPDでメールシステムを構築しています。仕事の都合で仮想ドメインでメールの送受信ができるようになっています。
元々のドメインをexample.comとすると、仮想ドメインexample.jpでもメールの送受信ができるようになっています。
gmail.comには、仮想ドメインから送信することがほとんどです。
従って、仮想ドメインのメールアドレス user@example.jpからmail.example.comメールサーバでgmail.com宛に送信することができるようにすることが大前提となります。
SPF
まずは一番簡単にできそうなSPFから実装することにします。
SPFはSender Policy Frameworkの略。メールを受信したメールサーバは、送信元メールサーバのSPFをDNSサーバに問い合わせ、正規のメールサーバから送信されたことを確認します。
policyd-spf
PostfixにSPFの機能を追加します。
# /usr/ports/mail/py-spf-engine
# make install clean
/usr/local/etc/pyspf-milter/pyspf-milter.confを以下のようにしました。
debugLevel = 1
TestOnly = 1
HELO_reject = False
Mail_From_reject = False
PermError_reject = False
TempError_Defer = False
skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1
# Milter specific options
Socket = local:/var/run/pyspf-milter/pyspf-milter.sock
#Socket = inet:8893@localhost
PidFile = /var/run/pyspf-milter/pyspf-milter.pid
#UserID = pyspf-milter
UserID = postfix
InternalHosts = 127.0.0.1
#MacroListVerify =
Postfixに組み込みます。まずはmain.cfから。
smtpd_recipient_restrictions =
permit_mynetworks,
.
.
reject_unauth_destination,
check_policy_service unix:private/policyd-spf ←この行を追加
追加する行は、reject_unauth_destinationより下の行に書くことに注意してください。
続いてmaster.cf。
以下の行を追加してください。
policyd-spf unix - n n - 0 spawn
user=nobody argv=/usr/local/bin/policyd-spf
動作するユーザを変更したので、ディレクトリの所有者を変更します。
# chown postfix:postfix /var/run/pyspf-milter
DNSサーバのゾーンファイルに以下の行を追加します。
※シリアル番号の変更とrndc reloadをお忘れなく。
IN TXT "v=spf1 ip4:10.0.0.1 include:example.jp mx:example.com -all"
SPFはドメイン管理者がDNSサーバにTXTレコードとして必要な情報を記述します。※TXTレコードの他にSPFレコードも記述可能ですが非推奨とされています。←廃止されました。
例えば以下のようにDNSのzoneファイルに記述します。
送信メールサーバのIPアドレスやドメインを記述します。
上記の例の場合は、送信メールサーバのIPアドレスは10.0.0.1で、送信ドメインはexample.jpです。
v=spf1はお決まりの記述と考えてください。
また、記述した情報は左側から順に評価されます。
SPFとして構成されるもの(機構)
ip4/ip6
IPアドレスを引数にとります。
メールサーバのIPアドレスを記述します。192.168.1.0/24のような書き方もできます。
include
ドメイン名を引数にとります。
指定したドメインのSPFレコードで認証処理がOKであれば正規のドメインとして扱われます。
参照先のドメインのSPFにさらにincludeが記述されている場合は再帰的に評価します。
mx
ドメイン名を引数にとります。
指定されたドメインがMXレコードで解決される場合は正規のものとして扱われます。
a
ドメイン名を引数にとります。
送信メールサーバのIPアドレスが、指定されたドメインのAレコードもしくはAAAAレコードで解決される場合は正規のものとして扱われます。
all
送信メールサーバに係らず常に正規のものとして扱います。
通常、一番最後に“-all”として末尾に記述するのが通常です。“-”(マイナス)を指定することによって常に非正規として扱われます。
末尾に指定することで、左側に記述された情報に当てはまらないものは非正規とすることができます。
redirect
ドメイン名を引数にとります。redirectは変更子というらしいです。
指定されたドメインのSPFで認証を行います。
redirectを指定する場合は他の機構を使用しない方が良いみたいです。
最後にpfspf-milterの起動設定と起動を行います。
# service pyspf-milter enable
# service pyspf-milter start
/var/run/pyspf-milterディレクトリにソケットファイルが生成されていることを確認します。
DKIM署名
DKIM(DomainKey Idenfitied Mail)とは電子メールにおける送信ドメイン認証技術で、電子署名を利用してメールの内容がメールの作成時点から改ざんされていないことを検証するための仕組みです。
送信元ドメインはDNSに公開鍵を記述しておき、メールを送信する際にメール本文と一部のヘッダを基にしたDKIMの電子署名をメールヘッダに付与します。
メールを受信したメールサーバは、メールににDKIMの電子署名があれば送信ドメインのDNSから公開鍵を取得し、公開鍵を使って電子署名が正しいことを確認します。
送信メールサーバが送信時に秘密鍵で電子署名をメールのヘッダフィールドDKIM-signatureに付与します。受信メールサーバは、送信側のDNSサーバから公開鍵を取得しメールの電子署名を復号して改ざんされていないことを確認します。
FreeBSDでDKIMを利用するためには
FreeBSDでDKIMを使用するためにはOpenDKIMパッケージをインストールする必要があります。
私は基本的にportsを使用してアプリケーションをインストールします。
# cd /usr/ports/mail/opendkim # make install clean
もし、下記のような表示がされた場合は、何もせず[OK]ボタンを押してください。

install時に以下のメッセージが表示されました。
DKIMはメールフィルタとして動作しますので、メールサーバ設定のガイダンスが表示されました。
私はPostfixを使用していますので、下記の太字部分の設定をしてあげる必要があります。
※あとで設定します。
また、FreeBSD起動時にOpenDKIMも起動するために、/etc/rc.confに“milteropendkim_enable=”YES””を追記するように言われています。
ただ、最近のFreeBSDではservice milteropendkim enableとすれば自動的に記述が追加されます。直接/etc/rc.confを編集しなくてもよい方向に進んでいるようです。
if you use sendmail, add the milter socket `socketspec' in /etc/mail/<your_configuration>.mc: INPUT_MAIL_FILTER(`dkim-filter', `S=_YOUR_SOCKET_SPEC_, F=T, T=R:2m') or if you use postfix write your milter socket `socketspec' in /usr/local/etc/postfix/main.cf: smtpd_milters = _YOUR_SOCKET_SPEC_ And to run the milter from startup, add milteropendkim_enable="YES" in your /etc/rc.conf. Extra options can be found in startup script. Note: milter sockets must be accessible from postfix/smtpd; using inet sockets might be preferred.
/usr/local/etc/mail/opendkim.conf
インストールしたOpenDKIMの設定ファイルを編集します。
私は以下のようにしました。(修正した項目のみを記述しています。)
Selectorは、任意の文字列を指定可能ですが、日付yyyymmdd形式で指定するのが定番のようです。
※私の場合は複数ドメインで利用しますので、Domain・Selectorはコメントアウトして別ファイルに記述します。(ExternalIgnoreList、InternalHosts、KeyTable、SigningTableで指定したファイルに記述します。)
AutoRestart yes
Canonicalization simple/simple
#Domain example.com
ExternalIgnoreList refile:/usr/local/etc/mail/opendkim/TrustedHosts
InternalHosts refile:/usr/local/etc/mail/opendkim/TrustedHosts
KeyTable /usr/local/etc/mail/opendkim/KeyTable
Mode sv
MultipleSignatures yes
ReportAddress "DKIM Error Postmaster" <postmaster@example.jp>
Selector 20230319
SendReports yes
SigningTable refile:/usr/local/etc/mail/opendkim/SigningTable
Socket local:/var/run/milteropendkim/socket
SubDomains yes
SyslogFacility mail
SyslogSuccess yes
UMask 007
UserID mailnull
/etc/group
OpenDKIMデーモンとPostfixがUNIXソケットを通じて通信するための動作するユーザとしてmailnullを指定しています。Postfixユーザ(私の場合はpostfix)をmailnullグループに追加します。
mailnull:*:26:postfix
事前準備
OpenDKIMが使用するディレクトリを用意します。
# mkdir /var/db/dkim # chown mailnull:mailnull /var/db/dkim
鍵の生成
以下のコマンドを実行して公開鍵・秘密鍵を生成します。
# opendkim-genkey -D /var/db/dkim -d example.jp -s 20230319
-Dオプションは鍵を保存するディレクトリ、-d はドメイン名、-sはセレクタ(yyyymmdd形式が一般的)を指定します。
/var/db/dkimに秘密鍵(20230319.private)と公開鍵(20230319.txt)が生成されます。ちなみにファイル名なっている“20230319”の部分はセレクタを表します。opendkim-genkeyの-sオプションで指定した値になります。また、opendkim.confのSelectorで指定した文字列と同じである必要があります。
公開鍵20230319.txtにはDNSのzoneファイルに記述する形式で出力されていますので、DNSのzoneファイルに貼り付けます。
例えば下記のような形式のファイルとなっています。
※鍵はドメイン毎に作成する必要があります。セレクタを同じにしてしまうと、ファイルが上書きされそうですし、以下の設定をする際に混乱して間違いの原因になりますので別の名前にした方が良いでしょう。
ということで、ここではセレクタ20230319はexample.com、20230320はexample.jpで使用することとします。
20230319._domainkey IN TXT ( "v=DKIM1; k=rsa; p=MAigfhrweoipagjroopPFgjeripgosdfgvjsdkl;jkfsdpkjfweoaosfjawejiIAODFJWEOHGPIOWGHhiogprwehgoaHUPhgperiaohugfahJIOPFGg9wiowfjg34fhafh3w29i4y2urdf92340" )
p=xxx のxxxは自動的に生成される文字列です。(このサンプルは一部を変更していますので、使用することはできません。)
エディタにviを使用しているのであれば、:r /var/db/dkim/20230319.txtで読み込むことができます。
opendkim.confで指定したファイルの準備
設定ファイルに指定したファイルを用意します。
# cd /usr/local/etc/mail # mkdir opendkim # touch opendkim/TrustedHosts # touch opendkim/KeyTable # touch opendkim/SigningTable # chown -R mailnull:mailnull opendkim # chmod 750 opendkim # chmod 640 opendkim/*
/usr/local/etc/mail/opendkim/TrustedHost
信頼するメールサーバを指定します。
※ここで指定されたホストはDKIMによる検証は無条件で通過します。これを増やしすぎると何のための仕組なのかわからなくなってしまいます。最小限にしましょう。
127.0.0.1 ::1 mail.example.com
上記の例では、ローカルホスト(IPv4/IPv6アドレス)と、メールサーバホストmail.example.jpを指定しています。
/usr/local/etc/mail/opendkim/SigningTable
メールアドレス毎にどの署名を使用するかを指定します。
とはいっても、1メールアドレス毎ではなく、ワイルドカード(*)を使用してドメイン毎での指定にします。
*@example.com 20230319._domainkey.example.com *@example.jp 20230320._domainkey.example.jp
/usr/local/etc/mail/opendkim/KeyTable
秘密鍵の参照先を指定するファイルです。
20230319._domainkey.example.com example.com:20230319:/var/db/dkim/20230319.private 20230320._domainkey.example.jp example.jp:20230320:/var/db/dkim/20230320.private
メールフィルタとしての設定
まずは、PostfixにDKIMをメールフィルタとして使用できるようにします。
main.cf
smtpd_milters = unix:/var/run/milteropendkim/socket
ここで指定するパスはopendkim.confのSocketと一致させる必要があります。
smtpd_miltersに他のメールフィルタが指定されている場合は、カンマで区切ってunix:~を追加してください。
OS起動時にOpenDKIMが起動するようにする
# service milter-opendkim enable
OSを再起動しないで起動する場合は以下のようにします。
# service milter-opendkim start # service postfix restart
DMARC
DMARCとは何なのかについては、私のにわか知識より他の専門家のサイトを確認していただきたい。(逃走・・)
OpenDMARCをportsでインストールします。
# cd /usr/ports/mail/opendmarc # make install clean
設定ファイルを用意します。/usr/local/etc/mail ディレクトリにopendmarc.conf.sampleがありますのでコピーします。
# cd /usr/local/etc/mail # cp opendmarc.conf.sample opendmarc.conf
/usr/local/etc/mail/opendmarc.conf
opendmarc.conf.sampleから変更した項目のみ記述します。
AuthservID HOSTNAME AutoRestart true BaseDirectory /var/run/opendmarc FailureReports true FailureReportsBcc postmaster@example.com FailureReportsSentBy postmaster@example.com IgnoreAuthenticatedClients true IgnoreMailFrom example.com, example.jp RequiredHeaders false Socket local:/var/run/opendmarc/socket SPFSelfValidate true Syslog true SyslogFacility mail UMask 002 UserID mailnull:mailnull
メールフィルタとしての設定
DKIMと同様、Postfixのメールフィルタとして動作させます。
main.cfのsmtpd_miltersにソケットを指定(追記)します。
smtpd_milters = unix:/var/run/milteropendkim/socket, unix:/var/run/opendmarc/socket
ソケットのパスは設定ファイルopendmarc.confのSocketで指定したものと一致させる必要があります。
OS起動時にDMARCを起動する
OSの起動時に自動的に起動するようにします。
# service opendmarc enable
OSを再起動しないでOpenDMARCを起動する場合は以下のようにします。
# service opendmarc start # service postfix restart
参考サイト
https://www.nic.ad.jp/ja/basics/terms/dkim.html
https://sendgrid.kke.co.jp/blog/?p=3509