Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5応用編⑧】メール送信②

B美

「CakePHP」のメール送信機能については、以下の項目を一通りやっておきましょう
(あとあと必ず役に立つはずだから…)

①CakePHPから直接、外部のメールサーバを利用する方法
②メールの内容について、テンプレートファイルを利用する方法
③Mailerクラスを継承して新たなクラスを作成し、それを利用する方法

の3点ね

A子

えぇー、面倒くさそう

別にもう良いじゃん

B美

ダメよ

これは学習の一環として、必ず知識として持っておきたいって項目なの
(しかも、これで最低限だからね)

C菜

やはり私たち自身で調べるんですか~?

B美

ええ、できるだけやってみてちょうだい

ただし、私が横から口を挟むかもしれないけどね

A子

仕方ない…
やるかぁ

まずは公式ページを読むことからね
(クリックすると別ウィンドウで開きます)

C菜

まずは①ですけど~
前回のこのページを参考にするです~

A子

ここの「gmail」って箇所の設定をそのまま使えそうだね

'default' => [
    ・・・
],

の下に「default」とは別の名前で設定を書いて、「new Mailer()」の際の引数として渡せば良いんじゃないかしら?

C菜

ということは~

'isp' => [
    'host' => 'smtp-auth.□.ne.jp',
    'port' => 587,
    'username' => '□@mx2.□.ne.jp',
    'password' => '□',
    'className' => 'Smtp',
    'tls' => false,
],

…という感じで、どうでしょうか~?
(□の部分は伏字ですぅ~)

A子

お、良い感じじゃない?

てか、「isp」って何?

C菜

Internet Service Providerの頭文字を並べたものです~
(通称「プロバイダ」ですね~)

A子

なるほどね
で、あとは「PostsController.php」の「add」メソッドの中の以下の箇所を書き換えれば良いかな?

$mailer = new Mailer('default');

        ↓
$mailer = new Mailer('isp');
に…

C菜

良いと思います~

とりあえずテストしてみるです~

B美

あ、この開発環境上で動いているメールサーバについては、いったん止めておきましょうか
(念のためね)

MATE端末」を開いて、以下のコマンドを入力してちょうだい

su -[Enter]
systemctl stop exim4[Enter]

ちなみに、停止は「stop」だけど、起動は「start」、再起動は「restart」ね

A子

これで掲示板に投稿したあと、管理者宛てにメールが届いたら大成功…ってわけだね

C菜

テスト投稿してみるです~



A子

うわっ、エラーだ

なんで?
「isp」というメールの設定を知らない…ってどういうこと?

B美

実はこれって解決方法が二通りあるんだけど、そのどちらもネット上には書かれてないのよね

てか、公式のページにすら書かれてない…(苦笑)

A子

まじかよ

なぜそれをB美が知ってるのかが謎なんだけど、まぁB美だからと思うしかないか…

C菜

その二つって何ですか~?

B美

一つ目は「Email」セクションに「isp」項目を追加すること
二つ目は「Email」セクションの「default」項目の「transport」の値を「isp」に変更すること

どっちでも良いんだけど、私のお勧めは二つ目かな
(「PostsController.php」を書き換えなくて済むからね)

A子

えーっと、「bbsapp/config」の「app.php」の「Email」セクションは…

'Email' => [
    'default' => [
        'transport' => 'default',
        'from' => 'you@localhost',
    ],
],

…って箇所だよね?

C菜

一つ目の方法は~

'Email' => [
    'default' => [
        'transport' => 'default',
        'from' => 'you@localhost',
    ],
    'isp' => [
        'transport' => 'isp',
        'from' => 'you@localhost',
    ],

],

ということですか~?

B美

正解よ

それじゃ二つ目の方法についてはA子が答えてね

A子

あー、以下のように書き換えれば良いんじゃないかな?

'Email' => [
    'default' => [
        'transport' => 'isp',
        'from' => 'you@localhost',
    ],
],

B美

そういうこと

あ、二つ目の方法を採用する場合は、さっき書き換えた「PostsController.php」を元に戻しておいてね

$mailer = new Mailer('default');

C菜

まとめると、Mailerクラスのコンストラクタ引数として渡すのは、Emailセクションの値で、その中の「transport」の値がEmailTransportセクションの要素を指し示している…ってことになるのでしょうか~?

B美

大正解!

分かってしまえば簡単なんだけど、なぜか公式ページにも書かれてないのよね(苦笑)

A子

なんで書いてないんだろうね?

まぁ、良いけど…
(いや、良くはない(笑))

B美

次は、②のテンプレートファイルの利用方法よ

んじゃ、とりあえずはあなたたちでやってみて…

C菜

公式ページの中に「テンプレートメールの送信」ってありますよ~

A子

とりあえずはこのサンプルをそのまま使おうか
(とは言っても、ちょっとだけ書き換えてるけど…)

$mailer = new Mailer('default');
$mailer->setEmailFormat('html')
    ->setFrom([FROM_ADDRESS => FROM_NAME])
    ->setTo(TO_ADDRESS)
    ->viewBuilder()
        ->setTemplate('welcome')
        ->setLayout('fancy');
$mailer->deliver();

…って感じでどうかな?

C菜

テスト投稿してみたら、こんなエラーが出ました~

調べてみたら「templates/email/html」には「welcome.php」は存在しないし、「templates/layout/email/html」にも「fancy.php」というファイルは無かったですよ~
(あったのはどちらも「default.php」というファイルでした~)

A子

ん?だったら「welcome」と「fancy」の箇所を「default」に書き換えてみよう

C菜

メールが届きました~

ただし、件名と本文が空欄でしたけど~

A子

あー
件名については、さっき「setSubject()」を削っちゃったからね

あと、本文のほうは「templates/email/html」の中にある「default.php」を書き換えれば良いってことじゃないかな?
…ってことで、ちょっと書き換えてから「add.php」というファイル名で保存してみたよ



C菜

あと「setSubject()」を復活させるです~

$mailer = new Mailer('default');
$mailer->setEmailFormat('html')
    ->setFrom([FROM_ADDRESS => FROM_NAME])
    ->setTo(TO_ADDRESS)
    ->setSubject(MAIL_SUBJECT)
    ->viewBuilder()
        ->setTemplate('add')
        ->setLayout('default');
$mailer->deliver();

A子

んじゃ、テストしてみよう

お、きちんと届いたみたいだね
(件名と本文も問題なし)

C菜

ControllerコントローラーからViewビューへパラメータを渡すのは「$this->set()」でできますけど、同じことがメールのテンプレートでもできないんでしょうか~?

「投稿番号」や「画像ファイルの有無」を渡せれば便利だと思います~

A子

ん?
確かに…

ちょっとググってみよう
・・・
お、「setViewVars」メソッドか、ViewBuilderの「setVar」または「setVars」メソッドでできるみたいだね

B美

これまたネット上にサンプルコードがほとんど無いから、私のほうで例示しておくわ

$mailer = new Mailer('default');
$mailer->・・・
    ->viewBuilder()
        ->setVars(連想配列);

…って感じね

C菜

ということは~

$mailer = new Mailer('default');
$mailer->setEmailFormat('html')
    ->setFrom([FROM_ADDRESS => FROM_NAME])
    ->setTo(TO_ADDRESS)
    ->setSubject(MAIL_SUBJECT)
    ->viewBuilder()
        ->setTemplate('add')
        ->setLayout('default')
        ->setVars(['number' => $new_id, 'image' => $img_flag]);
$mailer->deliver();

で、どうでしょうか~?

あ、「$img_flag」というのは、初期値がfalseで、画像を保存したらtrueを代入する変数です~



A子

お、良いんじゃない?

…ってことは、テンプレートファイルのほうも変更しないとね

C菜

テストしてみましたけど、バッチリでした~

B美

さっきA子が書いたテンプレートファイルだけど、少しだけ補足しておくわね

if ($image) {
    echo '有り';
} else {
    echo '無し';
}
…って箇所だけど

・画像の有無:<?= $image ? '有り' : '無し' ?>
という風にも書けるのよ

これは条件演算子と呼ばれるもので、「条件式 ? 真の場合 : 偽の場合」という形式の演算子なの
(四則演算のように二項ではなく、三つの要素を指定するから三項演算子とも呼ばれているわ)

C菜

一行でまとめられるのは分かりやすいかもです~

A子

書き換えてみたよ
(確かに、こっちのほうが分かりやすいかも…)

C菜

変更したコードでのテストもOKでした~

B美

さて、最後は③ね

実はメール送信においては、これこそが大本命なのよ
(普通は③の方式を採用することが多いってこと)

A子

公式ページの中のここ(再利用可能なメールの作成)のことかな?

C菜

なんだか難しそうです~
簡単にまとめると~

1.「src/Mailer」ディレクトリの中に新しいファイルを作って、そこに「○○Mailer」クラスを記述
2.そのクラスの中にメール送信のメソッドを記述
3.「PostsController.php」の中では以下の形で呼出し

$this->getMailer('○○')->send('××', 引数の配列);

○○はクラス名の中の「Mailer」の左側で、××はメソッド名です~

A子

うん、それで正解っぽい
とりあえず、やってみよう

namespace App\Mailer;

use Cake\Mailer\Mailer;

class PostMailer extends Mailer
{
    public function add($number, $image)
    {
        $this->setEmailFormat('html')
            ->setFrom([FROM_ADDRESS => FROM_NAME])
            ->setTo(TO_ADDRESS)
            ->setSubject(MAIL_SUBJECT)
            ->viewBuilder()
                ->setTemplate('add')
                ->setLayout('default')
                ->setVars(['number' => $number, 'image' => $image]);
    }
}

ほとんどは、さっき「PostsController.php」の中に書いたものと同じだね
(微妙に変えてるけど…)

B美

ちょっと口を出させてもらうわよ

手作業でディレクトリやファイルを作っても良いんだけどさ
こういうときはbakeコマンドを使うと、ひな形を作ってくれるからめっちゃ便利よ

MATE端末」を開いて

cd html/bbsapp[Enter]
bin/cake bake mailer post[Enter]

…って打ち込んでね

A子

あ、ほんとだ
勝手にディレクトリ(src/Mailer)とファイル(PostMailer.php)が作られたよ

んじゃ、このファイルを開いて、さっきのコードを打ち込んでっと…



C菜

「PostsController.php」のほうはこうでしょうか~?

use Cake\Mailer\MailerAwareTrait;

class PostsController extends AppController
{
    use MailerAwareTrait;
    ・・・
    public function add()
    {
        ・・・
        $this->getMailer('Post')->send('add', [$new_id, $img_flag]);
        ・・・


A子

これでテストしてみよう

お、問題なくメールが届いたね

C菜

PostsController.php」の記述が簡潔になったのは良いですね~

まさにメール機能の部品化というか、オブジェクト指向って感じです~

A子

あっ、そうか!
そういうことなのかぁ

B美

そういうことよ

投稿時だけじゃなく、削除の際なんかにもメール通知するようにしたければ「PostMailer.php」の中に新たなメソッドを追加すればOKってわけ
(メール送信に関するもろもろを一ヶ所に集約できるのは便利だし、見通しも良くなるからね)

C菜

ただ、最初に出てきた「継承」という言葉の意味が今一つ分かってないですけどね~

B美

まぁ、それは特に気にする必要もないかな(苦笑)

さて、今回はここまでね
次回は本番環境への配置(デプロイ)とテストに関する話をしていきましょう

A子

ようやく終わりが見えてきたね

長かった…(苦笑)