CakeEmail クラスを拡張して POP before SMTP に対応させる
ディズニーチャンネルで先行放送が始まっている『なんだかんだワンダー』がお気に入りです。前向きで哲学的。そしてあの耳について離れないオープニングテーマ…!みなさんこんにちは、 kagata です。
さて、今回は CakePHP でメールを送信する際のカスタマイズです。
先日、 CakePHP ベースのアプリケーションから POP before SMTP による認証が必要な SMTP サーバーを使ってメールを送信する機能を実装する機会がありました。CakePHP2 系に同梱されている CakeEmail クラスを拡張して、 POP before SMTP に対応させてみます。
CakeEmail クラスを拡張する
ということで、もうさっそくコードを載せてしまいます。
// /app/Vendor/CakeEmailPbs.php
App::uses('CakeEmail', 'Network/Email');
class CakeEmailPbs extends CakeEmail {
protected $_pop = array(
'host' => 'localhost',
'port' => 110,
'password' => ''
);
protected $_authenticated = false;
/*
* POP3認証情報を設定する
* @param array $config 認証情報(ホスト、ポート、パスワード)
* @return CakeEmailPbs インスタンス自身
*/
public function popConfig($config) {
$this->_pop = $config;
return $this;
}
/*
* POP3認証を実施する
* @return bool 認証の成否
*/
public function popAuth() {
$strMailbox = '{' . $this->_pop['host'] . ':' . $this->_pop['port'] . '/pop3}INBOX';
$stream = imap_open($strMailbox, $this->_config['username'], $this->_pop['password']);
$opened = (false !== $stream) ? true : false;
// POP3接続・切断の両方に成功したか
$this->_authenticated = ($opened && imap_close($stream));
return $this->_authenticated;
}
public function send($content = null) {
// 認証済みなら送信
return ($this->_authenticated) ? parent::send($content) : false;
}
}
CakeEmail クラスを継承して、 POP 認証情報を設定するメソッド popConfig() と認証を実施するメソッド popAuth() を追加しました。
ポイントは2つ。まず、 popConfig() の返り値をインスタンス自身としています。こうすることで、元の CakeEmail クラスに特徴的なメソッドチェーン記法に対応させることができます。
そして、2つ目のポイントは PHP から POP3 に接続する方法。今回は IMAP 関数を使いました。ほかにも次のような方法があります。お手元の環境と相談のうえ、お好みのものをどうぞ。
- ネットワーク関数を使う( fsockopen() )
…IMAP 関数を使った方がコードが簡潔になるので今回は使いませんでしたが、環境によってはこちらしか使えないという場合もあるかもしれません。 - PEAR のライブラリ Net_POP3 を使う
CakePHP では、自作したクラスファイルを /app/Vendor/ ディレクトリに置きます。今回は /app/Vendor/CakeEmailPbs.php というファイルを作り、上のコードを貼りつければ準備完了です。
では、コントローラー側でこのクラスを読み込んで実際に使ってみましょう。
POP before SMTP 認証を実施する
まず、メールを送信するコントローラーの冒頭で CakeEmailPbs クラスをインクルードしてやります。
// /app/Controller/SampleController.php
App::uses('CakeEmailPbs', 'Vendor');
Class SampleController extend AppController {
(…後略…)
これで、コントローラー内で CakeEmailPbs クラスが使えるようになります。
そして、この CakeEmailPbs クラスを使って実際に POP before SMTP 認証を試みます。コントローラーのアクション内で、次のように処理を記述します。
※メール送信の設定はあらかじめ /app/Config/email.php に書いておいてくださいね!
$email = new CakeEmailPbs();
$email->to('to@example.com'); // 送信先
$email->subject('テスト'); // 件名
// POP before SMTP
$email->popConfig(Configure::read('popConfig'));
$email->popAuth();
// 送信する
$successful = $email->send();
POP 認証に必要な情報は /app/Config/bootstrap.php で管理することにしてみました。ここへ Configure クラスを使って次のように書いておけば、あとで簡単に読み出せます。
// /app/Config/bootstrap.php
Configure::write('popConfig', array(
'host' => 'pop.example.com',
'port' => 110,
'password' => 'Wander-over-Yonder'
));
本当は、メールアカウントの設定と同じく /app/Config/email.php の EmailConfig クラスで管理できればスマートだと思ったのですが… EmailConfig クラスのプロパティに項目を追加する拡張がうまくいかず断念しました orz
CakeEmail クラスのコードを読んでみると、設定項目のラベルを決め打ちしてしまっているようですね。よい方法をご存じの方はお知らせください!
まとめ
- POP before SMTP とは、 SMTP サーバーを使う前に POP サーバーで認証する仕組みのこと。
- PHP で POP サーバに接続する方法は 3 通り。
- IMAP 関数( imap_open() )
- ネットワーク関数( fsockopen() )
- PEAR のライブラリ Net_POP3
- CakePHP では、自作のクラスファイルは /app/Vendor/ に置いて App::uses([クラス名], 'Vendor') でインクルードする。
- アプリケーション内部で使いまわす設定情報の配列は、 /app/Config/bootstrap.php で Configure::write([ラベル]) と定義して Configure::read([ラベル]) で呼び出す。