ブログblog

PHPでメールを送る際の文字化けや迷惑メール対策

Writer: noda 更新日:2019/09/26

こんにちは、野田です。

今回はメール送信のプログラムについて書いていきます。

先日、PHPのプログラムの中でメール送信の実装をしました。
その際、躓いた問題が2つ。
・ヘッダー情報の文字化け
・送ったメールが迷惑メールに振り分けられる。

ネットでかなり調べましたが、情報にけっこうばらつきがあったので自分なりにまとめてみます。
今回はPHPで実装したので、文章中のコードや関数はPHPになります。

まず問題解決の前にPHPでメールを送る際の設定についてまとめます。
使う関数はmb_send_mail()
PHPファイル自体の文字コードとメールヘッダーのcharsetを合わせます。
ちなみにこの作業をした時のファイルの文字コードはUTF-8です。
以下をPHPファイルに記述します。

mb_language("Japanese");
mb_internal_encoding("UTF-8");

ヘッダー情報に加える記述は以下です。

Content-Type: text/plain; charset=UTF-8

こちらに関しては、あとでまとめてソースコード記述します。
以上で下準備完了。
問題の対策をしていきます。

【文字化け】
前提として、メールのヘッダーにはアスキー文字しか書けません。
アスキー文字はASCII文字コードで表現される半角英数字や記号などです。
つまりひらがなや漢字は書くことができません。
具体的には、メールの送信者の欄に送信元アドレスと送信者の名前を書いたりすると思いますが、
きちんと処理しないとこの送信者の名前(日本語の場合)が文字化けします。
PHPでヘッダーに日本語を使う場合は以下のようにします。

mb_encode_mimeheader("文字列", "UTF-8")

この例では省略していますが、
本来は第3引数にMIMEエンコーディングの方式を指定できます。
指定できるのは
・B(Base64)
・Q(Quoted-Printable)です
実際書くとこうなります。

mb_encode_mimeheader("文字列", "UTF-8", "B")

ただし省略した場合デフォルトではBase64になっていますので、今回は省略しました。
メールヘッダに日本語を書く場合は、この関数を使用してBase64方式で
エンコードする必要があります。

【迷惑メール】
次に、送ったメールが迷惑メールにならないようにするための設定です。
確認するのは3点
・SPFの設定がされているか
・IPがブラックリストに載っていないか
・エンベロープFromアドレスの設定

1つ目のSPF設定についてですが、
Sender Policy Frameworkの略です。
これはDNSで設定するレコードのことで、なりすましを防ぐためにあります。
例えばAのメールサーバからBのメールサーバにメールを送ったとします。
このときBのメールサーバはメールがなりすましでないかをAのDNSサーバに確認しにいきます。
ここで登場するのがSPFレコード。
例としてドメインをexample.jpとします。
Aはexample.jpのDNS設定で以下のようにSPFレコードを設定しておきます。(一例)
v=spf1 ip4:111.222.333.444 -all
これはexample.jpはIPアドレス111.222.333.444のサーバ以外はメールサーバとして認証しませんという意味です。
逆に言うとほかに認証OKにしたいサーバがある場合はここにIPアドレスを追加します。
これでBのメールサーバはIPアドレス111.222.333.444から来たメールはexample.jpが認めている正当なサーバ
だということを認識して迷惑メールと判断されなくなります。

2つ目のブラックリストについてです。
メールの大量送信などでIPアドレスがブラックリストに載る場合があります。
これは自分がそういったことをしなくても、過去に自分が現在使っているIPアドレスから、
ブラックリストに載るような行為がされている可能性もあります。
「IP ブラックリスト」などで検索すると、自分のIPアドレスがブラックリスト入りしていないか
調べるサイトが出てくるので、そちらを利用し調べます。

最後に3つ目のエンベロープFromアドレスについて
私がいろいろ試したときは最後にここで引っかかりました。
メール送信の際にヘッダ情報を書いて送りますが、
ここでヘッダに書くFromアドレスとは別にエンベロープアドレスを設定しないといけません。
ネットで検索したらたくさん出てきましたが、
手紙でいうと
ヘッダのFromアドレスは便箋に書いてある送り主で、
エンベロープアドレスは「封筒」に書いてある送り主です。
メールクライアントソフトなどでメールを見る時は
ヘッダのFromアドレスの方が表示されます。
しかし受け取ったメールサーバはエンベロープアドレスで送信者を判断するので、
これがしっかり設定されてないと迷惑メールになる可能性があります。
この設定は簡単でmb_send_mailの第5引数に「-f」に続けて送信者のメールアドレスを記述します。

以上を踏まえてヘッダーに日本語を交えてPHPでメール送信する際のソースコードはこのようになります。
尚、mb_send_mailの引数は
mb_send_mail(送信先アドレス, タイトル, 本文, ヘッダー情報, オプション)です。

mb_language("Japanese");
mb_internal_encoding("UTF-8");

define("MAIL_TO_ADDRESS", "noda@example.jp");
define("MAIL_SUBJECT", "タイトル");
define("MAIL_BODY", "ここに本文が入ります");
define("MAIL_FROM_ADDRESS", "designare@example.jp");
define("MAIL_FROM_NAME", mb_encode_mimeheader("デジナーレ" , "UTF-8"));
define("MAIL_HEADER", "Content-Type: text/plain; charset=UTF-8 \n".
                      "From: " . MAIL_FROM_NAME . "<" .MAIL_FROM_ADDRESS . "> \n".
                      "Sender: " . MAIL_FROM_ADDRESS ." \n".
                      "Return-Path: " . MAIL_FROM_ADDRESS . " \n".
                      "Reply-To: " . MAIL_FROM_ADDRESS . " \n".
                      "Content-Transfer-Encoding: BASE64\n");

mb_send_mail(MAIL_TO_ADDRESS , MAIL_SUBJECT , MAIL_BODY , MAIL_HEADER, "-f ".MAIL_FROM_ADDRESS);

ここではそれぞれの設定値に定数を使っていますが、変数でも大丈夫です。
タイトルや本文などヘッダーに載せない項目はmb_encode_mimeheaderで変換する必要はないです。
ヘッダーの説明としては、
・それぞれの行の末尾に改行「\n」をつける
・Content-Transfer-Encodingはエンコード方式を表しています。

あとはそれぞれの環境によるところもありますが、
原理としてはこれで送れるようになります。

原理さえ分かれば、他言語で実装する際も解決が早くなりそうなので
これから何かしら問題が起こった場合は根本的なところを調べながら解決していくようにしたいです。

デジナーレへのご質問、求人に関するお問い合わせなどございましたら、
お問い合わせフォームよりご送信ください。担当者より改めてご連絡させていただきます。