PHP(mb_send_mail)でメールが送信できない

WEBサーバを利用して、メールを送信したい思ったことはないでしょうか。

 

このWEBサーバからメールを送信したいというニーズは、一般的には大きく以下の2つかと思います。

 

サイトからのアクションがあった場合に自分宛に通知を受け取る

問い合わせフォームなど用意していて、ユーザから問い合わせがなされた場合などが該当します。

 

第三者のメールアドレス宛に情報を発信したい

代表的なものはメールマガジンですね。

また、ECサイトで商品を購入したら、購入者に対して詳細情報をメールで送信するケースもあります。

 

PHPであればメール送信用の関数が用意されているので、どちらの場合であっても実現することは簡単です。

 

ところが、利用するサーバの環境やメールサーバによっては、メール送信プログラムを作っても

icatch_.nopng

動かないですけど、、、

 

ってこともよくあります。

 

おそらく、このページをみている方はPHPでうまくメールが送信できていない人かと思います。(そういう人に向けた記事だからあたりまえですが。。。)

 

何を隠そう、僕も大ハマリした一人です(汗)

 

解消するにあたり結構調べたので、本日は

 

PHPでメールが送信できない!

 

という時に、疑うべきポイントを紹介したいと思います。

 

PHPのメール送信の関数

PHPでメールの送信する方法がわからない人もいるかもしれないので、まず手始めに、PHPのメール送信の関数を説明します。

 

PHPのメール関数は一般的には2つがあり、それぞれ以下の特徴があります。

  • mail() : 添付データを扱うことができる
  • mb_send_mail() : マルチバイトに適している

 

利用用途によりますが、日本語(マルチバイト)で添付データを扱わない場合がほとんどかと思いますので、このページではmb_send_mail()を利用する前提で話をしていきます。

 

mb_send_mail()の使い方

こちらもご存知の方はすみません。

おさらいを兼ねてパラメータの説明です。

 

mb_send_mail(“toのメールアドレス” ,  “件名” , “メール本文” , “メールヘッダー” , “-f  エラーが起きた際のメール送信先”);

 

普通にPHPファイルにこの関数を指定してやれば動作するはずなのですが、なぜか動かない。。。

 

さて、前置きが長くなりました。

 

以下、被疑のポイントを説明していきます。

 

メールが送信されない原因

上記説明した通り、mb_send_mail自体は難しい指定はないのでパラメータの指定で間違えることはないと思います。

 

メールが送信されない多くの場合は、実は外部要因が原因です。

利用しているサーバ環境や、送信先のメールサーバのセキュリティによってメールが届かないため、本気で原因調査をするとすごく大変です。

 

多くの場合は、以下のポイントで解消できるかと思いますので一つづつ説明していきます。

  • PHPが使えるか、またsendmailが使えるか
  • Fromがメールアドレスの形式ではない
  • FromとReturn-Pathのメールアドレスが異なる
  • メールヘッダーを正しく設定する
  • 送信先のメールサーバにブロックされている

 

PHPが使えるか、またsendmailが使えるか

専用サーバや無料のレンタルサーバを利用している方は該当するかもしれません。

無料のレンタルサーバは広告が表示されるだけではなく、機能を制限されていることも多いです。

 

PHPでメールを送信する場合は、PHPとは別に「sendmail」がインストールされていないと使うことができません。

 

無料サーバの場合は、sendmailやPHP、さらにデータベースやが使えないということが多いので、確認しましょう。

 

また、機能制限には「PHPは使えるけど一部の関数は使えない」という場合もあります。

 

これはレンタルサーバの運営者が、迷惑メールの配信として利用されないようにしているためです。(そりゃそうですよね。。。。)

 

PHPが使えるけど、メール送信系の関数が使えるかどうかわからない場合は、運営者の利用規約やサポートページに記載があると思いますが、もし説明がない場合はphpinfo()で確認しましょう。

 

mb_send_mailは、mbstring拡張モジュールが入っていないと使えません。

phpinfo の上の方にあるConfigure Commandの中に–enable-mbstring–という記述があれば問題なく利用できます。

 

もし上記の記述がなければ、インストールしましょう。

(レンタルサーバの場合は無理かと思うので諦めるか、mail関数を利用しましょう)

 

余談ですが、最近は月額100円のレンタルサーバでもPHPは使えるところは多いので、有料のレンタルサーバを利用している場合はおそらく大丈夫かと思います。

 

Fromがメールアドレスの形式ではない

mb_send_mailはFromのメールアドレスがメールアドレスの形式(@が存在し、@以降に「.」が一つ以上含まれる)にしないとエラーになります。

 

こちらは結構ありがちですが、テストする際、Toには実際に受信できるメールアドレスを指定する必要がありますが、Fromは適当な文字列にしていないか確認しましょう。

 

ちなみに僕はテストで利用する際、Fromを「test@test.com」とすることが多いです。

 

FromとToが同じメールアドレス

Toだけではなく、Fromも送受信できるメールアドレスを指定するのが良いのですが、送信先のメールサーバによっては、FromとToが同じだとエラーにするケースがあるようです。

 

FromとReturn-Pathのメールアドレスが異なる

受け取ったメールに返信する場合、「Return-Path」に指定されたメールアドレスが返信先となります。

 

そのため、FromとReturn-Pathに別々のメールアドレスを指定すると、送信できないようにするメールサーバも存在しています。

 

メールヘッダーを正しく設定する

上記の設定だけではNGとされる可能性があります。

 

メールヘッダーにはもっと詳細な指定をすることが可能なため、以下を参考に赤字の部分を自分の環境に合わせて試してください。

 

$subject = "タイトル";
$body = "本文";

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

$header = "MIME-Version: 1.0\n";
$header .= "Content-Transfer-Encoding: 7bit\n";
$header .= "Content-Type: text/plain; charset=ISO-2022-JP\n";
$header .= "Message-Id: <" . md5(uniqid(microtime())) . "@【ドメイン名】>\n";
$header .= "from: 【メールアドレス】\n";
$header .= "Reply-To: 【メールアドレス】\n";
$header .= "Return-Path:【メールアドレス】\n";
$header .= "X-Mailer: PHP/". phpversion();

mb_send_mail(【toのメールアドレス】, $subject, $body, $header, "-f 【メールアドレス】");

 

簡単に説明をしていきます。

動けばいいやって方は読み飛ばしてもらってOKです。

 

一番上の2行にある、「mb_language」「mb_internal_encoding」は文字エンコードの指定です。

この指定をしないと、メールの件名、本文、またFROMに日本語で差出人を表示させる場合に文字化けします。

 

MIME-Version」は、その下の「Content-Transfer-Encoding」「Content-Type」を指定する場合は必須です。細かい説明は割愛しますので、Google先生に聞いてみてください。

 

Content-Transfer-Encoding」は、ビットの指定です。昔は、メールは7ビットしかNGだったのですが、最近は8ビットであってもUTF-8でエンコードした情報をメールで送れば問題なく送信できたりするので、もしかしたら指定の必要はないかもしれません。

(誰か詳しい人がいたら教えてください!)

 

Content-Type」は、MIME タイプの指定です。日本語のシンプルなメールであれば、「text/plain」で「charset」には「ISO-2022-JP」を指定してください。

 

Message-Id」はメールと一対一に対応する文字列を指定します。メールを作成したホストの FQDN (正式ホスト名) と時刻、 プロセス/スレッド ID、ランダム文字列などを使って作るのが一般的です。

 

Reply-To」「Return-Path」はそれぞれ返信先の指定をします。両者の違いですが、「Reply-to」はメーラーに返信先を指定をさせますが、「Return-Path」はメールサーバ側に指定をさせます。

 

X−Mailer」はメーラーを指定するものです。PHPで送信する場合は、例の記述をしてください。

まったく関係ないですが僕は、メーラーにBecky!を使っています。

 

この対応をすれば7割くらいは、届くようになると思います。

 

不達の可能性を下げるために

最近はメールでの表現の幅が広がって自由度がかなり高いです。

 

ですが、HTMLメールや、添付データ付きのメールをPHPで送信しようとすると、相手のメールサーバのセキュリティに引っかかる可能性も高くなります。

 

そういう場合は、別途HTMLページをサーバに用意し、プレーンテキストのメールで添付などはなしにして、URLをアドレスに打ち込んでアクセスしてもらうことで必要な情報を伝える方法があります。

 

送信先のメールサーバにブロックされている

冒頭で挙げた「サイトからのアクションがあった場合に自分宛に通知を受け取る」というケースであればフリーメールなども含めて、いくつか試せば実現できるかと思います。

 

ところが、メールマガジンなどのように「第三者のメールアドレス宛に情報を発信したい」という場合には、相手の利用するメールサーバのセキュリティ次第で、どうしても「相手にメールが届かない」という事象は発生します。

 

その場合は、別で「メール配信機能」を準備する必要があります。

 

メールマガジンのように、送信者の決めたタイミングで指定のメールアドレス宛に一括して送信するような場合は、メルマガ配信システム利用すれば解決できると思います。

(「メルマガ配信システム」でgoogle先生に聞くとたくさん出てきます)

 

ところが、匿名掲示板などの場合はユーザのアクションに対して都度、投稿者のメールアドレス宛にメールを送信する必要があるため、別の方法が必要になります。

 

最近では、APIが充実しており、有名なところだとGmailがメール送信用のWEB APIが存在するため、そういった外部機能連携をすることで解消することになります。

 

実は僕も第三者にメールを通知する必要のあるサイトを運用しています。

 

最初GmailのAPIを使おうと考えていたのですが、Fromの部分がGmailで取得したアカウントになってしまうため、独自ドメインでの利用ができません。

 

そのため、僕は有料ですが「Amazon SES」というサービスと連携することで実現しています。

(それでも「メールが届かない」問題は発生していますが、今の所全体の1%程度のため許容してしまっています)

 

こちらについては紹介するとかなり長くなってしまうので、後日紹介することにします。

 

最後に

最近は、利用するサーバ環境に問題がなければ、WordPressの問い合わせプラグインや、EC-CUBEなどちょっとした設定でメール送信ができるようになっています。

 

ところが、未だに携帯キャリアのメールアドレスには問題がおきます。

 

それも、同じキャリア、同じ機種であっても人によってメールが届いたり届かなかったりするため完璧に不達をなくすことが難しいと思います。

 

そのため、メール送信の不達を完璧になくすのではなく、不達の場合であってもサービスに影響がないよう、サイトのコミュニケーションを考えておくことも重要です。

 

Author:yukio iizuka
プロフィール画像
フリーランスとしてUX視点で業務支援しています。 HCD-Net認定 人間中心設計専門家 LEGO®︎ SERIOUS PLAY®︎ メソッドと教材活用トレーニング修了認定ファシリテーター Hi-Standard好きです。
http://yukioiizuka.com
mislead
MISLEADの記事に共感いただけましたら
いいねをお願いします。

コメント一覧

  • 美藤博文

    大変参考になりました。私も自作サイトの中で不特定多数のサイト参照者にメールを発信しようと、返信機能を作成しています。ところがPC相手のメールやGmail相手では送信できるのですが、ドコモ携帯ではスパム扱いとなり全てブロックされてしまいます。原因が判らず、スマホやiPhoneへの送信は不可能なのかと諦めかけてます。
    これらに限定したスパム対応の情報を発信して頂ければありがたいのですが・・・。
    宜しくお願いいたします。

    • mislead

      コメントありがとうございます。
      お役に立てて光栄です。

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください



       

© yukio iizuka All Rights Reserved...