【CakePHP】 CakeEmail クラスに RFC 非準拠のメールアドレスを許容させる
機動戦士ガンダム 35 周年ということで、BS や CS で特集放映されるシリーズ作品のチェックに余念がない kagata です。『機動戦士ガンダム0080 ポケットの中の戦争』と『機動戦士ガンダム0083―ジオンの残光―』と『機動戦士ガンダム 逆襲のシャア』と『機動戦士ガンダムUC』と『機動戦士ガンダムF91』、あと『機動武闘伝Gガンダム』も楽しみです。
さて、今回は CakePHP の話題です。CakePHP2 系でメールを送信する際に使う CakeEmail クラスでは、メールの送受信に指定するメールアドレスのバリデーションを内部で実行するようになりました。このため、初期状態では日本の携帯電話に見られるような RFC に準拠しないメールアドレスへメールを送信することができません。そこで、CakePHP2.4 で追加されたメソッド CakeEmail::emailPattern() を使って、このようなメールアドレスにも問題なくメールを送信できるようにしてみます。
メール送信できない例
どんなメールアドレスで送信エラーになってしまうか、アクションの例を示します。
<?php
App::uses('CakeEmail', 'Network/Email');
class MailController extends AppController {
public function index() {
$email = new CakeEmail();
$email->subject('test');
// ローカルパートで '.' が連続しているのでRFC非準拠
$email->from('nihon..no..keitai@example.jp');
// ローカルパートが '.' で終わるのでRFC非準拠
$email->to('japanese.cellphone.@example.com');
// Debugモードでメール送信をテスト、結果をビューに渡す
$email->transport('Debug');
$message = $email->send('it\'s only a test.');
$this->set('message', $message);
}
}
差出人・宛先ともに RFC に準拠しないメールアドレスとしてはよくあるパターンですね。
このアクションを実行すると、結果は次のとおり。
"Invalid email" というエラーを発して、処理を中断してしまいます。メールは送信されません。
CakeEmail クラスのソースコードをのぞいてみると、内部で Validation::email() を使ってメールアドレスのバリデーションが実行されているのがわかります。モデルのメールアドレスバリデーションと同じルールが適用されるわけですね。モデルのバリデーションなら独自ルールを使えばすみますが、クラス内部にバリデーション処理が埋め込まれてしまうと対応に困ってしまいます。
ということで、バージョン 2.4 からは CakeEmail クラスがメールアドレスのバリデーションに使う正規表現をユーザー側で指定できるようになりました。それが、次にご紹介する CakeEmail::emailPattern() による方法です。
CakeEmail::emailPattern() でバリデーションを緩和する
ではさっそく、CakeEmail::emailPattern() を使ってみましょう。基本的には、先ほどのコードに1行追加するだけです。
<?php
App::uses('CakeEmail', 'Network/Email');
class MailController extends AppController {
public function index() {
$email = new CakeEmail();
$email->subject('test');
// メールアドレスのバリデーションルールを緩和:任意の文字列を受け入れる
$email->emailPattern('/^.+$/');
// ローカルパートで '.' が連続しているのでRFC非準拠
$email->from('nihon..no..keitai@example.jp');
// ローカルパートが '.' で終わるのでRFC非準拠
$email->to('japanese.cellphone.@example.com');
// Debugモードでメール送信をテスト、結果をビューに渡す
$email->transport('Debug');
$message = $email->send('it\'s only a test.');
$this->set('message', $message);
}
}
とりあえず、任意の(1文字以上の)文字列をメールアドレスとして受け入れてやることにします。ずいぶん乱暴ではありますが、まあテストということで…。
実行結果は次のとおりです。
正しく送信できました。
実際のシステムでは、送信のたびに CakeEmail::emailPattern() を実行するのは煩雑です。コンポーネントや CakeEmail のサブクラスなどを作ってまとめておくとよいでしょう。
ちなみに、CakePHP の公式ドキュメントにある CakeEmail::emailPattern() の説明が、日本の携帯電話キャリアのせいでこんな機能が必要になったと言わんばかりでちょっと哀愁を誘います。
This is sometimes necessary when dealing with some Japanese ISP's:
補足:メールアドレスの正規表現について
メールアドレスの正規表現については、今回の主題ではないということで上のとおりお茶を濁しておきます。どうしても深入りしたい方は次のような記事を参照されるといいんじゃないかと思います。
- 404 Blog Not Found:「PHP使いはもう正規表現をblogに書くな」と言わせないでくれ
- [PHP]実用的なメールアドレスの正規表現 | DevAchieve
- HTML - メールアドレスを表す現実的な正規表現 - Qiita
個人的には、ユーザーが持っているメールアドレスを入力させるくらいのシステムであれば、実際にメールをやり取りしてアドレスが実在することを確認するほうがバリデーションに凝るよりも健全ではないかなと思っています。「RFC に準拠しているけれど誰も使っていないメールアドレス」なんていくらでもあるわけですしね。