fuel/email

A timeout issue and an uncatchable Exception

Closed this issue · 0 comments

Today I just found there was an error on my server (PHP 5.3.3).

I tried send an E-mail by smtp, but it simply timeout and throw an SmtpCommandFailureException (not SmtpTimeoutException). And if I tried to catch Exception by EmailSendingFailedException but it failed.

I've analyzed this issue and I found what happened exactly.

In /classes/email/driver/smtp.php, Line 289:

while($str = fgets($this->smtp_connection, 512))
{
    // If it counters a timeout, $str will simply get nothing and it won't run this code here.
    $info = stream_get_meta_data($this->smtp_connection);
    if($info['timed_out'])
    {
        throw new \SmtpTimeoutException('SMTP connection timed out.');
    }
...

As you can see, it never throw a SmtpTimeoutException correctly.

If I try to fix it by my own, I will encounter another SmtpCommandFailureException issue.

Although if it throws SmtpTimeoutException correctly, it will throw another SmtpCommandFailureException by "__destruct" function.

In /classes/email/driver/smtp.php, Line 30:

function __destruct()
{
    // If there is another Exception before this, it will be likely to throw SmtpCommandFailureException here.  When it happens, there no way I can catch this Exception by a "try" block except nested "try" blocks.
    if ( ! empty($this->smtp_connection))
    {
        $this->smtp_disconnect();
    }
}

So, I have to code like this to resolve the problem.

try
{
    $email->send();

    ...
}
catch(\EmailValidationFailedException $e)
{
    ...
}
catch(\EmailSendingFailedException $e)
{
    ...

    try
    {
        // I have to force it to tigger "__destruct" in order to prevent any unexpecting Exception.
        unset($email);
    }
    // catch EmailSendingFailedException **again**
    catch (\EmailSendingFailedException $e)
    {
        // Do nothing
    }

    ...
}