Help us understand the problem. What is going on with this article?

Laravel RFC違反のメールアドレスにメール送信できるようにする

ストーリー

Laravel RFC違反しているメールアドレスをサクッと探すtipsより。

RFC違反しているメールアドレスを見つけたところで、送信できるようにして欲しいという無茶苦茶な要望があります。

そんな無茶振りに対応する方法をご紹介します。

環境

  • PHP 7.2
  • Laravel 5.7

RFC違反のメールアドレスの例

  • example.-.@example.com
    • @の前に.を置いてはならない
  • .example@example.com
    • .から開始してはならない
  • ex..ample@example.com
    • .が連続してはいけない

エラー

$ php artisan tinker

このRFC違反メールアドレスにLaravelからメールを送信しようとするとSwift_RfcComplianceExceptionという例外が発生します。

Mail::raw('test mail',function($message){$message->to('example.-.@example.com')->subject('test');});

Swift_RfcComplianceException with message 'Address in mailbox given [test.@example.com] does not comply with RFC 2822, 3.6.2.'

RFC 2822

電子メールに関するきまりが書かれたRFCRFC 822を破棄し、新標準となった。

対応策

Swiftmailerのコンテナに独自のバリデータを読み込ませる事で対応します。

app/Validation/AllowNonRfcComplaintEmailValidator.php

<?php

namespace App\Validation;

use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\EmailValidation;

class AllowNonRfcComplaintEmailValidator extends EmailValidator
{
    /**
     * 最低限、@が含まれていて、ドメインとアカウント名が含まれているメールアドレスは許可します
     * @param string          $email
     * @param EmailValidation $emailValidation
     * @return bool
     */
    public function isValid($email, EmailValidation $emailValidation): bool
    {
        // warningsとerrorのプロパティを埋める
        parent::isValid($email, $emailValidation);

        if (substr_count($email, '@') !== 1) {
            return false;
        }

        list($account, $domain) = explode('@', $email);

        if (strlen($account) > 0 && strlen($domain) > 0) {
            return true;
        }

        return false;
    }
}

parent::isValid($email, $emailValidation) 戻り値は使用してないですが、
親関数ので実行している warnings, errors プロパティを埋める処理を呼び出してます。

app/Providers/AllowNonRfcComplaintEmailPatchServiceProvider.php

<?php

namespace App\Providers;

use App\Validation\AllowNonRfcComplaintEmailValidator;
use Illuminate\Support\ServiceProvider;
use Swift;
use Swift_DependencyContainer;

class AllowNonRfcComplaintEmailPatchServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot(): void
    {
        Swift::init(
            function () {
                Swift_DependencyContainer::getInstance()
                    ->register('email.validator')
                    ->asSharedInstanceOf(AllowNonRfcComplaintEmailValidator::class);
            }
        );
    }
}

config/app.php

return [
    'providers' => [
        // ...
        App\Providers\AllowNonRfcComplaintEmailPatchServiceProvider::class,
    ],
];

動作確認

$ php artisan tinker
Mail::raw('test mail',function($message){$message->to('example.-.@example.com')->subject('test');});

null

成功したらnullが返ってきます。

参考

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away