Skip to content

Instantly share code, notes, and snippets.

@greabock
Last active October 6, 2015 17:45
Show Gist options
  • Save greabock/a6d55e8218dcbdb7d699 to your computer and use it in GitHub Desktop.
Save greabock/a6d55e8218dcbdb7d699 to your computer and use it in GitHub Desktop.
SwiftMailer - Работаем с самоподписанными сертификатами

актуально для версий до коммита от третьего сентября. В версиях новее, это делается приблизительно так:

$mailer->getTransport()->setStreamOptions([#...]);

спасибо @lynicidn

Я уже давно ничего не писал... но наш бессменный лидер - Алексей aka @Butochnikov угрозами и шантажом убедил меня написать хоть небольшую заметку... Держите, други ))

Сегодня передо мной встала задача, рассылать e-mail по smtp через серевер с самоподписанным сертификатом SSL.

SwiftMailer категорически отказывался работать с таким сервером, выдавая что-то в духе

SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

и еще какую-то ересь...

Недолгое гуление проказало, что проблема известная, и легко решается добавлением пары строк в... исходный код!
Дело в том, что массив с опциями объявляется непосредственно в коде StreamBuffer; И никакого апи для влияния на эти опции в SwiftMailer'е просто не предусмотрено. Вот там-то и нужно внедрить пару этих волшебных сток:

$options = array(
    'ssl' => array(
        'verify_peer' => false,
        'verify_peer_name' => false,
    ),
);

Окей, дупустим мы внедрили этот код прямо куда надо, и все работает. Однако, сразу ясно, что первый же composer update снесет всё к чертвовой бабушке... Разумеется нужно расширять класс. Вот только как его подсунуть назад в SM?

Прогулка по деревьям классов привела меня в святая святых SwiftMailer'а - Swift_DependencyContainer;

По методу getInstance() сразу становится ясно, что это классический случай singleton - а значит бегать по провайдерам в поисках инициализации не придется.

// выполнять, само собой, после загрузки провайдеров.
dd(Swift_DependencyContainer::getInstance());

показало, что наш замечательный StreamBuffer скрывается в этом самом контейнере за ключом transport.buffer; и имеет в зависимостях transport.replacementfactory, после десяти минут изучения механики контейнера, я пришел к выводу, что заменить буффер в контeйнере не сложно:

Swift_DependencyContainer::getInstance()
            ->register('transport.buffer')
            ->asNewInstanceOf(InsecureStreamBuffer::class)
            ->addConstructorLookup('transport.replacementfactory');
// Где InSecureStreamBuffer - это расширенный StreamBuffer

С самим же InsecureStreamBuffer пришлось повозится чуть дольше. Сначала я пытался не перекрывать все методы наледуемого класса, а отделаться мимнимумом. Но ввиду того, что они почти все приватные, пришлось таки их переопределить, а к ним в довесок еще и все приватные свойства. В итоге, получился точно такой же класс, но с той самой парой строк, которые отключают проверку сертификата.

$options = array(
    'ssl' => array(
        'verify_peer' => env('MAIL_VERIFY_PEER', true),
        'verify_peer_name' =>  env('MAIL_VERIFY_PEER_NAME', true),
    ),
);

Здесь я добавил подключение этих параметров из .env файла, чтобы можно было удобно настроить "в случае чего".

Покончив с кодом я зашел на свой сайт, спокойно зарегистрировался, потом перешел на сайт своей почты, и уже через минуту, довльный - наблюдал заветное письмо в папке "Спам" XD

Вот такая история ))

@lynicidn
Copy link

lynicidn commented Oct 6, 2015

@greabock
Copy link
Author

greabock commented Oct 6, 2015

Пожалуй, ты прав
swiftmailer/swiftmailer@51c81bb

Проблема была исправлена в сентябре...
А у меня composer lock на том проекте с середины августа

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment