CakePHP3 のメールの使い方

ババっと調べても痒いところに手が届かない記事ばかりヒットするので自分用にまとめます。 この記事もきっと痒いところに手が届かない記事です。長いです。

2018/7/14 変更
Email の非推奨メソッドを修正
s/from/setFrom/ s/to/setTo/ s/subject/setSubject/

基本的な使い方

これは CookBook の通り

<?php
$email = new Email('default');
$email->setFrom(['me@example.com' => 'My Site'])
    ->setTo('you@example.com')
    ->setSubject('About')
    ->send('My message');

ここでつまづくのが new Email('default')default ってなんなのかってことです。 app.php に記述してある設定のキーになるんです。

設定

ここで app.default.php の設定を見てみましょう。

<?php
'EmailTransport' => [
    'default' => [
        'className' => 'Mail',
        // The following keys are used in SMTP transports
        'host' => 'localhost',
        'port' => 25,
        'timeout' => 30,
        'username' => null,
        'password' => null,
        'client' => null,
        'tls' => null,
        'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
    ],
],

'Email' => [
    'default' => [
        'transport' => 'default',
        'from' => 'you@localhost',
        //'charset' => 'utf-8',
        //'headerCharset' => 'utf-8',
    ],
],

Email はメールの設定、EmailTransport はメール送信の設定を記述します。 各設定項目については app.php のコメント読んで下さい。

で、new Email('default')default は設定の ['Email']['default'] を参照します。

Email

エラー通知とか宛先や件名が固定できるメールについてはここで設定しておくと楽ですね。

<?php
'Email' => [
    'system' => [
        'transport' => 'default',
        'from' => 'system@localhost',
    ],
    'info' => [
        'transport' => 'default',
        'from' => 'info@localhost',
    ],
    'error' => [
        'transport' => 'default',
        'from' => ['error@localhost' => 'Error mail sender'],
        'to' => 'admin@localhost',
        'subject' => 'Error occurred!!!!!',
    ],
],

$email = new Email('error'); // エラー通知メール
$email->send('My message'); // from, to, subject は設定の値が使われる

で、['Email']['default']['transport'] の値をキーにして、['EmailTransport'][default] がメール送信の手段に利用されます。

EmailTransport

EmailTransport については .env で値を設定できるようにしておくのが実用的だと思います。

<?php
'EmailTransport' => [
    'default' => [
        'className' => env('EMAIL_TRANSPORT_DEFAULT_CLASS_NAME', 'Mail'),
        // The following keys are used in SMTP transports
        'host' => env('EMAIL_TRANSPORT_DEFAULT_HOST', 'localhost'),
        'port' => env('EMAIL_TRANSPORT_DEFAULT_PORT', 25),
        'timeout' => env('EMAIL_TRANSPORT_DEFAULT_TIMEOUT', 30),
        'username' => env('EMAIL_TRANSPORT_DEFAULT_USERNAME', null),
        'password' => env('EMAIL_TRANSPORT_DEFAULT_PASSWORD', null),
        'client' => env('EMAIL_TRANSPORT_DEFAULT_CLIENT', null),
        'tls' => env('EMAIL_TRANSPORT_DEFAULT_TLS', null),
        'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
    ],
],

メール送信のコードをあんまり書かないようにする

<?php
$email = new Email('default');
$email->setFrom(['me@example.com' => 'My Site'])
    ->setTo('you@example.com')
    ->setSubject('About')
    ->send('My message');

って長い。長くないです?

再利用可能なメールの作成 を参考にします。 Mailer にまとめてスッキリ & DRY にしよう!ってことが書いてあります。

トレイト初体験だったので、理解に結構な時間を使ってしまった箇所です。

トレイト

Wikipedia によるとトレイトを言語自体がサポートしてるのは PHP だけみたいですね。 Scala もできるんです?

メソッドを別ファイルに定義して use するとオブジェクトがメソッドもってることになります。

Mailer

トレイトの説明しといてあれですが、トレイトは一旦忘れてください。

メールの細かい設定を Mailer にまとめます。 src/Mailer/ に書いていきます。

src/Mailer/SystemMailer.php

<?php
namespace App\Mailer;

use Cake\Mailer\Mailer;

class SystemMailer extends Mailer
{
    public function errorNotice($e)
    {
        $this // $this は Email オブジェクト
            ->profile('error')
            ->set(['msg' => $e->getMessage()]);
    }
}

メールテンプレートはメソッド名と同じものが使われます。 今回の場合は src/Template/Email/text/error_notice.ctp です。

src/Template/Email/text/error_notice.ctp

<?= $msg ?>

使いたいとこで使う

後はトレイトを利用することでいつでもどこでもエラー通知メールを送ることができます!

<?php
namespace App\Controller;

use Cake\Mailer\MailerAwareTrait; // トレイトを使えるようにするよ

class ErrorController extends AppController
{
    use MailerAwareTrait; // トレイトを使うよ

    public function index()
    {
        // SystemMailer の errorNotice に new \Exception('Error!!!!!!!!!!!') を渡してメール送信
        $this->getMailer('System')->send('errorNotice', [(new \Exception('Error!!!!!!!!!!!'))]);
    }
}

2回 use を書かないといけないけど、一つの php ファイルに複数のクラスが記述できる仕様だし仕方なさそうです。

use MailerAwareTrait;getMailer() が使えるようになります。 引数には Mailer のクラス名を渡します。今回は SystemMailer を使うので getMailer('System') です。

send() には Mailer のメソッド名と引数の配列を渡します。SystemMailer::errorNotice($e) を使うので、send('errorNotice', [(new \Exception('Error!!!!!!!!!!!'))]) となります。

そして

短くなりました!設定が一箇所にまとまってて修正も楽!