yiisoft / yii2-swiftmailer

Yii 2 swiftmailer extension.
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
116 stars 74 forks source link

When transport is gone, swiftmailer does not try to restart transport #67

Closed mikk150 closed 6 years ago

mikk150 commented 6 years ago

What steps will reproduce the problem?

Make a queue that sends emails, send email and after some time(about 5-15 minutes) send another email

What's expected?

it sends email, waits 15 minutes (because queue said so) it sends another

What do you get instead?

it sends email, waits 15 minutes (because queue said so) gets error that transport is gone, because it never tries to reconnect

Additional info

4 lines of code fixes this(will make PR myself)

Q A
Yii version 2.0.15.1
Yii SwiftMailer version 2.0.7
SwiftMailer version 5.4.12
PHP version 7.2
Operating system Docker
i-cooltea commented 6 years ago

I also encountered this problem

Exception 'Swift_TransportException' with message 'Expected response code 250 but got code "", with message ""'

in /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:456

Stack trace:
#0 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(343): Swift_Transport_AbstractSmtpTransport->assertResponseCode(''
#1 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php(305): Swift_Transport_AbstractSmtpTransport->executeCommand('MAIL FROM:<3
#2 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(392): Swift_Transport_EsmtpTransport->executeCommand('DATA\r\n', A
#3 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(503): Swift_Transport_AbstractSmtpTransport->doDataCommand(Array)
#4 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(522): Swift_Transport_AbstractSmtpTransport->doMailTransaction(Objy, Array)
#5 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php(205): Swift_Transport_AbstractSmtpTransport->sendTo(Object(Swift_M
#6 /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php(70): Swift_Transport_AbstractSmtpTransport->send(Object(Swift_Message), Array)
#7 /var/www/html/ykupgrader/vendor/yiisoft/yii2-swiftmailer/src/Mailer.php(151): Swift_Mailer->send(Object(Swift_Message))
#8 /var/www/html/ykupgrader/vendor/yiisoft/yii2/mail/BaseMailer.php(263): yii\swiftmailer\Mailer->sendMessage(Object(yii\swiftmailer\Message))
#9 /var/www/html/ykupgrader/vendor/yiisoft/yii2/mail/BaseMessage.php(49): yii\mail\BaseMailer->send(Object(yii\swiftmailer\Message))
#10 /var/www/html/ykupgrader/common/components/consumers/MailConsumer.php(43): yii\mail\BaseMessage->send()
#11 /var/www/html/ykupgrader/common/components/consumers/MailConsumer.php(76): common\components\consumers\MailConsumer->sendEmail(Array)
#12 /var/www/html/ykupgrader/vendor/mikemadisonweb/yii2-rabbitmq/components/Consumer.php(334): common\components\consumers\MailConsumer->execute(Object(PhpAmqpLib\Message\AMQPMess
#13 /var/www/html/ykupgrader/vendor/mikemadisonweb/yii2-rabbitmq/components/Consumer.php(281): mikemadisonweb\rabbitmq\components\Consumer->onReceive(Object(PhpAmqpLib\Message\AMQ
#14 [internal function]: mikemadisonweb\rabbitmq\components\Consumer->mikemadisonweb\rabbitmq\components\{closure}(Object(PhpAmqpLib\Message\AMQPMessage))
#15 /var/www/html/ykupgrader/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AMQPChannel.php(997): call_user_func(Object(Closure), Object(PhpAmqpLib\Message\AMQPMessage))
#16 [internal function]: PhpAmqpLib\Channel\AMQPChannel->basic_deliver(Object(PhpAmqpLib\Wire\AMQPReader), Object(PhpAmqpLib\Message\AMQPMessage))
#17 /var/www/html/ykupgrader/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php(210): call_user_func(Array, Object(PhpAmqpLib\Wire\AMQPReader), Object(PhpAmqpLi
#18 /var/www/html/ykupgrader/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php(348): PhpAmqpLib\Channel\AbstractChannel->dispatch('60,60', '&mail_queue-mai...'
#19 /var/www/html/ykupgrader/vendor/mikemadisonweb/yii2-rabbitmq/components/Consumer.php(202): PhpAmqpLib\Channel\AbstractChannel->wait(NULL, false, NULL)
#20 /var/www/html/ykupgrader/vendor/mikemadisonweb/yii2-rabbitmq/controllers/RabbitMQController.php(95): mikemadisonweb\rabbitmq\components\Consumer->consume(0)
#21 [internal function]: mikemadisonweb\rabbitmq\controllers\RabbitMQController->actionConsume('mail_consumer')
#22 /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#23 /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#24 /var/www/html/ykupgrader/vendor/yiisoft/yii2/console/Controller.php(148): yii\base\Controller->runAction('consume', Array)
#25 /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/Module.php(528): yii\console\Controller->runAction('consume', Array)
#26 /var/www/html/ykupgrader/vendor/yiisoft/yii2/console/Application.php(180): yii\base\Module->runAction('rabbitmq/consum...', Array)
#27 /var/www/html/ykupgrader/vendor/yiisoft/yii2/console/Application.php(147): yii\console\Application->runAction('rabbitmq/consum...', Array)
#28 /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/Application.php(386): yii\console\Application->handleRequest(Object(yii\console\Request))
#29 /var/www/html/ykupgrader/yii(23): yii\base\Application->run()
#30 {main}
PHP Warning:  fwrite(): SSL: Broken pipe in /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php on line 231
PHP Stack trace:
PHP   1. yii\console\ErrorHandler->handleException() /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/ErrorHandler.php:0
PHP   2. Swift_SmtpTransport->__destruct() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:0
PHP   3. Swift_SmtpTransport->stop() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:545
PHP   4. Swift_SmtpTransport->executeCommand() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:245
PHP   5. Swift_SmtpTransport->executeCommand() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php:305
PHP   6. Swift_Transport_StreamBuffer->write() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:330
PHP   7. Swift_Transport_StreamBuffer->doWrite() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php:91
PHP   8. Swift_Transport_StreamBuffer->doCommit() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php:168
PHP   9. fwrite() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php:231
mikk150 commented 6 years ago

screenshot from 2018-08-16 13-51-19

I even tried to fix it, but tests are now broken because swiftmailer has an issue where sendmail transport inherits ping method from smtp transport because of inheritance, but last time I checked executable file cannot does not have stream

i-cooltea commented 6 years ago

@mikk150 Then how do we solve this problem? Is there no other way?

i-cooltea commented 6 years ago

@mikk150
The problem comes from another library called swiftmailer/swiftmailer. Find this file swiftmailer\swiftmailer\lib\classes\Swift\Mailer.php And append the following code to function send Disconnect each time after sending

public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
    {
        $failedRecipients = (array) $failedRecipients;

        if (!$this->transport->isStarted()) {
            $this->transport->start();
        }

        $sent = 0;

        try {
            $sent = $this->transport->send($message, $failedRecipients);
        } catch (Swift_RfcComplianceException $e) {
            foreach ($message->getTo() as $address => $name) {
                $failedRecipients[] = $address;
            }
        }

+        if ($this->transport->isStarted()){
+           $this->transport->stop();
+        }
        return $sent;
    }

Then the problem is solved.

mikk150 commented 6 years ago

@ADirtyCat I do not think that getting rid of transport is a good idea because it will add more overhead to this problem(SYN, ACK, EHLO, AUTH)

Also it is not Swiftmailer's problem, because they have clearly told that this is developers problem

i-cooltea commented 6 years ago

I added the code, but there was still an exception. Am I another `question?

Exception 'Swift_TransportException' with message 'Expected response code 250 but got code "", with message ""'

in /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:456
1. yii\console\ErrorHandler->handleException() /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/ErrorHandler.php:0
PHP   2. Swift_SmtpTransport->__destruct() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:0
PHP   3. Swift_SmtpTransport->stop() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:545
PHP   4. Swift_SmtpTransport->executeCommand() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:245
PHP   5. Swift_SmtpTransport->executeCommand() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php:305
PHP   6. Swift_Transport_StreamBuffer->write() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:330
PHP   7. Swift_Transport_StreamBuffer->doWrite() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php:91
PHP   8. Swift_Transport_StreamBuffer->doCommit() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php:168
PHP   9. fwrite() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php:231
mikk150 commented 6 years ago

@ADirtyCat please try to relocate this code according to my new PR

i-cooltea commented 6 years ago

@mikk150 Thank you very much !! You are the Savior

i-cooltea commented 6 years ago

@mikk150 I don't know why I tried it again today. Another problem was discovered PHP Warning fwrite(): SSL: Broken pipe

PHP Warning:  fwrite(): SSL: Broken pipe in /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php on line 231
PHP Stack trace:
PHP   1. yii\console\ErrorHandler->handleException() /var/www/html/ykupgrader/vendor/yiisoft/yii2/base/ErrorHandler.php:0
PHP   2. Swift_SmtpTransport->__destruct() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:0
PHP   3. Swift_SmtpTransport->stop() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:545
PHP   4. Swift_SmtpTransport->executeCommand() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:245
PHP   5. Swift_SmtpTransport->executeCommand() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php:305
PHP   6. Swift_Transport_StreamBuffer->write() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php:330
PHP   7. Swift_Transport_StreamBuffer->doWrite() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php:91
PHP   8. Swift_Transport_StreamBuffer->doCommit() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php:168
PHP   9. fwrite() /var/www/html/ykupgrader/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php:231
mikk150 commented 6 years ago

@ADirtyCat that is issue to swiftmailer, they do not convert libSSL warnings into Swift_TransportException

if it affects me as well(because I might still have this issue), then I'll see what I can do

it seems to work for now at least

ivoglent commented 4 years ago

I have faced this issue again when send many mails from mailing queue. This is workaround:

class Mailer extends BaseMailer
{
    /**
     * Fix yii2 mailer when send multi email
     * issue "fwrite(): SSL: Broken pipe"
     * @see https://github.com/yiisoft/yii2-swiftmailer/issues/67
     *
     *
     * @param \yii\mail\MessageInterface $message
     * @return bool
     */
    public function sendMessage($message)
    {
        $result = parent::sendMessage($message);
        if ($this->getTransport()->isStarted()) {
            $this->getTransport()->stop();
        }
        return $result;
    }
}

then replace mailer class in config file.