August 24

How to increase SocketStream timeout in Symfony Mailer v4.4

0  comments

After I switched to office365 I started getting this error:

Failed to authenticate on SMTP server with username "***" using the following authenticators: "LOGIN", "XOAUTH2". Authenticator "LOGIN" returned "Symfony\Component\Mailer\Exception\TransportException: Connection to "smtp.office365.com:587" timed out.

After some research it turned out that this error happens because of short timeout defined in SocketStream, which is created in transports by EsmtpTransportFactory and is not possible to change using configuration.

namespace Symfony\Component\Mailer\Transport\Smtp\Stream;

final class SocketStream extends AbstractStream {

    private $timeout = 5;

In the version 5 of Symfony Mailer this problem is solved: it reads default_socket_timeout in the php.ini. But the problem still exists in v4.4

Here is my fix

This idea is to decorate EsmtpTransportFactory and set timeout in the decorated create method

<?php declare(strict_types=1);
# src/Email/EsmtpTransportWithTimeoutFactory.php

namespace App\Email;

use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
use Symfony\Component\Mailer\Transport\TransportInterface;

class EsmtpTransportWithTimeoutFactory implements TransportFactoryInterface
{
    private $decorated;

    public function __construct(TransportFactoryInterface $decorated)
    {
        $this->decorated = $decorated;
    }

    public function create(Dsn $dsn): TransportInterface
    {
        $transport = $this->decorated->create($dsn);
        if (null !== ($timeout = $dsn->getOption('timeout')) &&
            ($stream = $transport->getStream()) instanceof SocketStream
        ) {
            $stream->setTimeout((float)$timeout);
        }
        return $transport;
    }

    public function supports(Dsn $dsn): bool
    {
        return $this->decorated->supports($dsn);
    }
}

Then add service definition in services.yaml

# config/services.yaml
services:
    App\Email\EsmtpTransportWithTimeoutFactory:
        decorates: mailer.transport_factory.smtp
        arguments: ['@App\Email\EsmtpTransportWithTimeoutFactory.inner']

That’s done! now just specify timeout you want in the DSN string

MAILER_DSN=smtp://****:****@smtp.office365.com:587?timeout=60

Tags

symfony, symfony mailer


You may also like

Leave a Reply

Your email address will not be published. Required fields are marked *

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

Subscribe to our newsletter now!