gmail.comにメールが送信できない

最近、メールクライアントとして使用している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サーバに問い合わせ、正規のメールサーバから送信されたことを確認します。

perlモジュール関連インストール

# cd /usr/ports/mail/postfix-policyd-spf-perl
# make
# make install clean
mastar.cf

以下の行を追加する。

policy unix  -       n       n       -       -      spawn
  user=nobody argv=/usr/local/bin/perl /usr/local/postfix/sbin/postfix-policyd-spf-perl
main.cf
smtpd_recipient_restrictions =
        ・
        ・
        ・
        ・
        reject_unauth_destination,
        check_policy_service unix:private/policy,
        ・
        ・
        ・
        ・

必ず reject_unauth_destination よりも下に書くこと。

policyd-spfの起動
# service pyspf-milter enable
# service pyspf-milter start
# service postfix restart   ← Postfixの再起動

SPFはドメイン管理者がDNSサーバにTXTレコードとして必要な情報を記述します。
※TXTレコードの他にSPFレコードも記述可能ですが非推奨とされています。
例えば以下のようにDNSのzoneファイルに記述します。

IN TXT    "v=spf1 ip4:10.0.0.1 include:example.jp mx:example.com -all"

送信メールサーバの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を指定する場合は他の機構を使用しない方が良いみたいです。

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

戸塚

www.computer-service.jp

コンピュータ業界に30年近く身を置いていましたが、現在では建築関係、その他、まったくの異業種に。 コンピュータに関する『こまった』をサポートするべく事業を開始。