CentOS7 nginx postfix phpという環境でWebからメール送信する仕組みを構築
環境は、
CentOS7 nginx postfix php7 opendkim といったところです。Amazon Linux 2でも同じやり方でできました。
SendGridのブログに、世の中の主要なメールサーバーの受信するメールの95%は迷惑メールだというデータがあるようです。正しい設定をしていても、誤って迷惑メールに判断されないように、最大限の対応はしておきたいですね。
ここではエンジニアとしての最大限のできることをまとめています。それでも迷惑メールになる場合は、メールの文章に問題があると思ってください。
総務省が出しているメールの文章の書き方についてもあります。
http://www.soumu.go.jp/main_sosiki/joho_tsusin/d_syohi/pdf/m_mail_081114_1.pdf
以下抜粋。
ちなみに、受信側が迷惑メールとして判断する方法として
迷惑メール相談センターにEメールヘッダ情報の確認方法があります。
https://www.dekyo.or.jp/soudan/contents/ihan/header.html
ということは、この対策は最低限しておかないとメールサーバーは迷惑メールとして判定されやすいと思ったらいいですね。
では、以下、サーバーの設定からメールヘッダの書き方まで説明します。
postfix null client
送信するだけのメールサーバーのことをnull clientといいます。
こちらの方の設定でばっちりです!
NullクライアントのPostfix環境の作成(Qiita)
SPF
Sender Policy Framework(SPF)は、SMTPを利用したインターネット電子メールの送受信において送信者のドメインの偽称を防ぎ、正当性を検証する仕組みのひとつとして元Pobox社のMeng Wong氏により提唱された送信ドメイン認証方式である。(迷惑メール対策委員会より)
SPFはDNSに設定するものである。正しい設定方法は各DNSプロバイダに聞くのもよいし、検索してみましょうね。
参考
example.jp. IN SPF "v=spf1 ip4:192.0.2.1 -all"
192.0.2.1は、Web Serverからメール送信の仕組みを入れる場合は、そのWeb ServerのIPアドレスに書き換えてください。
DKIM
DKIM (Domainkeys Identified Mail) : 迷惑メール対策委員会
これは、証明書を作成してそれをDNSに登録します。メールを送信するWeb ServerとDNS間でDNSが言っていることは正しいということを証明するためのものです。
opendkim インストール
opendkimはepel repoにあります。
#(root)
yum -y install epel-release
yum info opendkim
yum -y install opendkim
暗号化キー保存用ディレクトリの作成
複数ドメイン運用を考慮してドメイン毎に暗号化キーの保存ディレクトリを作成します。
mkdir /etc/opendkim/keys/sample.com
暗号化キーの作成
[opendkim-genkey]
http://www.opendkim.org/opendkim-genkey.8.html
/usr/sbin/opendkim-genkey -D /etc/opendkim/keys/sample.com/ -d sample.com -s default
Ownerの変更
Ownerを変更します。またdefault.privateが秘密鍵、default.txtがDNSに設定する公開鍵になります。
chown -R opendkim:opendkim /etc/opendkim/keys
ls -l /etc/opendkim/keys/sample.com/
-rw------- 1 opendkim opendkim 887 May 8 16:25 default.private
-rw------- 1 opendkim opendkim 317 May 8 16:25 default.txt
opendkim.confの設定
/etc/opendkim.confShell
vi /etc/opendkim.conf
Mode sv
#KeyFile /etc/opendkim/keys/default.private
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
Socket inet:8891@localhost # ここほ確認だけ。localhostで8891ポートで動作することを確認。
KeyTableの設定
複数ドメイン運用の場合にはこのファイル/etc/opendkim/KeyTableに暗号化キー情報を追加していきます。
/etc/opendkim/KeyTable
vi /etc/opendkim/KeyTable
default._domainkey.sample.com sample.com:default:/etc/opendkim/keys/sample.com/default.private
TrustedHostsの設定
/etc/opendkim/TrustedHosts
vi /etc/opendkim/TrustedHosts
127.0.0.1
::1
smtp.sample.com
SigningTableの設定
署名するドメイン情報を/etc/opendkim/SigningTableに追加します。
/etc/opendkim/SigningTableShell
vi /etc/opendkim/SigningTable
*@sample.com default._domainkey.sample.com
DNSの設定
公開鍵をDNSのzoneファイルに設定します。当然外部からの問い合わせに応答するためにインターネット公開用Zoneファイルに/etc/opendkim/keys/sample.com/default.txtの内容をそのままコピーします。またキーとは別にDKIMポリシーも追記します。
「"」から「”」までをTXTに。「”」も含めて。
2レコード追加ですよ
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIGf............................" ) ; ----- DKIM key default for sample.com
_adsp._domainkey.sample.com IN TXT "dkim=unknown"
※AWS Route 53への設定についてtips (2024/03/04 追記)
Route53には、MAX255文字制限があるため登録できないです。ただ、面白いことにダブルコーテーションで囲んで分割してRoute53上では、1レコードとして定義でOKです。
digってみると、2レコードとしてAnswerします。
postfixの設定
postfixにopendkimを使用するように設定追加します。
milterとは、postfixの Mail Filterという意味。opendkimの動作しているIP:portを指定する。
vi /etc/postfix/main.cf
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
opendkimの有効、起動
systemctl enable opendkim
systemctl start opendkim
systemctl status opendkim
postfixのreload
systemctl reload postfix
or
postfix reload
DMARC設定
DNSにTXTレコードを追加です。最小設定
_dmarc.sample.com TXT "v=DMARC1; p=none;"
php側の設定
php mb_send_mail関数でメール送信する際の注意点
php.iniの設定がJapaneseとUTF-8になっているか確認する
[mbstring]
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
もし、変更できないならメール送信処理前に以下を書いてもOK
mb_language("ja");
mb_internal_encoding("UTF-8");
mb_send_mailは、第5引数が大事らしい。
ここに
-ffrom@sapmle.com
という-fからスペースなしでfromメールアドレスを記述するパラメータを付与する必要がある。
ここではちょっとややこしいけど、from@sample.comからメールを送っているとする。
これは、メールエンベローブであり、メールヘッダーのReturn-Pathで指定されるものとは別。
メールヘッダーで指定するFromやReturn-PathとエンベローブのReturn-Pathが異なることで迷惑メールに分類される可能性があるとの記事もあったので設定しておくとよいです。
※メールのエンベロープとメールのヘッダーの2か所にReturn-Pathがあることを知っておくこと。
Return-Path: <nginx@sample.com>
$param = "-ffrom@sample.com;
// 送信者情報の設定
$headers = '';
$headers .= "Content-Type: text/plain \r\n"; // HTML メールなら text/htmlで
$headers .= "Return-Path: from@sample.com \r\n";
$headers .= "From: " . mb_encode_mimeheader($name) . " " . "<from@sample.com> \r\n";
$headers .= "Sender: " . mb_encode_mimeheader($name) . " " . "<to@sample.net> \r\n";
$headers .= "Reply-To: from@sample.com \r\n";
$headers .= "Organization: " . mb_encode_mimeheader($name) . " \r\n";
$headers .= "Precedence: bulk \r\n"; // 大量メール送信時にはあったほうがよい
$headers .= "X-Sender: from@sample.com \r\n";
$headers .= "X-Priority: 3 \r\n";
// 送信先
$to = "to@sample.net";
//
$body = "本文書いて下しされ";
// メール送信します。
mb_send_mail($to, $subject, $body, $headers, $param);
同じメールをたくさんの人に送るときは、とりあえず、bulkメールですよって教えてあげると、安全かも。
似たようなメールをたくさんの人に送るわけだし、宛先違っても似たようなメールを複数受け付けると怪しまれれる=迷惑ーメールに思われる可能性もありそうなので、HeaderにPrecedence: bulkを追加してあげるとよいです。
もひとつついでに、X-Priority: 3くらいで。普通のメールですよと。ここまで設定して迷惑メールに入るとするならば、文章中に、外部(他ドメイン)リンクたくさんあったり、あやしいスクリプトが埋め込まれてたり、いろんなひとが迷惑メールとして報告してたりする可能性しかないのかなと。
主要なメールサーバーは、95%が迷惑メール扱いするという昨今なので、5%のメールを目指すためすくなくとも上記の対策はやっておきたいところですね。
Precedence: bulk