update patch 1
This commit is contained in:
Vendored
+11
@@ -1,6 +1,17 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
7.2
|
||||
---
|
||||
|
||||
* Deprecate `TransportFactoryTestCase`, extend `AbstractTransportFactoryTestCase` instead
|
||||
|
||||
The `testIncompleteDsnException()` test is no longer provided by default. If you make use of it by implementing the `incompleteDsnProvider()` data providers,
|
||||
you now need to use the `IncompleteDsnTestTrait`.
|
||||
|
||||
* Make `TransportFactoryTestCase` compatible with PHPUnit 10+
|
||||
* Support unicode email addresses such as "dømi@dømi.example"
|
||||
|
||||
7.1
|
||||
---
|
||||
|
||||
|
||||
+3
-4
@@ -25,11 +25,10 @@ final class DelayedEnvelope extends Envelope
|
||||
{
|
||||
private bool $senderSet = false;
|
||||
private bool $recipientsSet = false;
|
||||
private Message $message;
|
||||
|
||||
public function __construct(Message $message)
|
||||
{
|
||||
$this->message = $message;
|
||||
public function __construct(
|
||||
private Message $message,
|
||||
) {
|
||||
}
|
||||
|
||||
public function setSender(Address $sender): void
|
||||
|
||||
Vendored
+31
-2
@@ -46,7 +46,7 @@ class Envelope
|
||||
{
|
||||
// to ensure deliverability of bounce emails independent of UTF-8 capabilities of SMTP servers
|
||||
if (!preg_match('/^[^@\x80-\xFF]++@/', $sender->getAddress())) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress()));
|
||||
throw new InvalidArgumentException(\sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress()));
|
||||
}
|
||||
$this->sender = $sender;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ class Envelope
|
||||
$this->recipients = [];
|
||||
foreach ($recipients as $recipient) {
|
||||
if (!$recipient instanceof Address) {
|
||||
throw new InvalidArgumentException(sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, get_debug_type($recipient)));
|
||||
throw new InvalidArgumentException(\sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, get_debug_type($recipient)));
|
||||
}
|
||||
$this->recipients[] = new Address($recipient->getAddress());
|
||||
}
|
||||
@@ -85,4 +85,33 @@ class Envelope
|
||||
{
|
||||
return $this->recipients;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any address' localpart contains at least one
|
||||
* non-ASCII character, and false if all addresses have all-ASCII
|
||||
* localparts.
|
||||
*
|
||||
* This helps to decide whether to the SMTPUTF8 extensions (RFC
|
||||
* 6530 and following) for any given message.
|
||||
*
|
||||
* The SMTPUTF8 extension is strictly required if any address
|
||||
* contains a non-ASCII character in its localpart. If non-ASCII
|
||||
* is only used in domains (e.g. horst@freiherr-von-mühlhausen.de)
|
||||
* then it is possible to send the message using IDN encoding
|
||||
* instead of SMTPUTF8. The most common software will display the
|
||||
* message as intended.
|
||||
*/
|
||||
public function anyAddressHasUnicodeLocalpart(): bool
|
||||
{
|
||||
if ($this->getSender()->hasUnicodeLocalpart()) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->getRecipients() as $r) {
|
||||
if ($r->hasUnicodeLocalpart()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-12
@@ -24,21 +24,17 @@ use Symfony\Contracts\EventDispatcher\Event;
|
||||
*/
|
||||
final class MessageEvent extends Event
|
||||
{
|
||||
private RawMessage $message;
|
||||
private Envelope $envelope;
|
||||
private string $transport;
|
||||
private bool $queued;
|
||||
private bool $rejected = false;
|
||||
|
||||
/** @var StampInterface[] */
|
||||
private array $stamps = [];
|
||||
|
||||
public function __construct(RawMessage $message, Envelope $envelope, string $transport, bool $queued = false)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->envelope = $envelope;
|
||||
$this->transport = $transport;
|
||||
$this->queued = $queued;
|
||||
public function __construct(
|
||||
private RawMessage $message,
|
||||
private Envelope $envelope,
|
||||
private string $transport,
|
||||
private bool $queued = false,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getMessage(): RawMessage
|
||||
@@ -85,7 +81,7 @@ final class MessageEvent extends Event
|
||||
public function addStamp(StampInterface $stamp): void
|
||||
{
|
||||
if (!$this->queued) {
|
||||
throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__));
|
||||
throw new LogicException(\sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__));
|
||||
}
|
||||
|
||||
$this->stamps[] = $stamp;
|
||||
@@ -97,7 +93,7 @@ final class MessageEvent extends Event
|
||||
public function getStamps(): array
|
||||
{
|
||||
if (!$this->queued) {
|
||||
throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__));
|
||||
throw new LogicException(\sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__));
|
||||
}
|
||||
|
||||
return $this->stamps;
|
||||
|
||||
+7
-8
@@ -39,14 +39,13 @@ class MessageListener implements EventSubscriberInterface
|
||||
'bcc' => self::HEADER_ADD,
|
||||
];
|
||||
|
||||
private ?Headers $headers;
|
||||
private array $headerRules = [];
|
||||
private ?BodyRendererInterface $renderer;
|
||||
|
||||
public function __construct(?Headers $headers = null, ?BodyRendererInterface $renderer = null, array $headerRules = self::DEFAULT_RULES)
|
||||
{
|
||||
$this->headers = $headers;
|
||||
$this->renderer = $renderer;
|
||||
public function __construct(
|
||||
private ?Headers $headers = null,
|
||||
private ?BodyRendererInterface $renderer = null,
|
||||
array $headerRules = self::DEFAULT_RULES,
|
||||
) {
|
||||
foreach ($headerRules as $headerName => $rule) {
|
||||
$this->addHeaderRule($headerName, $rule);
|
||||
}
|
||||
@@ -55,7 +54,7 @@ class MessageListener implements EventSubscriberInterface
|
||||
public function addHeaderRule(string $headerName, int $rule): void
|
||||
{
|
||||
if ($rule < 1 || $rule > 3) {
|
||||
throw new InvalidArgumentException(sprintf('The "%d" rule is not supported.', $rule));
|
||||
throw new InvalidArgumentException(\sprintf('The "%d" rule is not supported.', $rule));
|
||||
}
|
||||
|
||||
$this->headerRules[strtolower($headerName)] = $rule;
|
||||
@@ -105,7 +104,7 @@ class MessageListener implements EventSubscriberInterface
|
||||
|
||||
$h = $headers->get($name);
|
||||
if (!$h instanceof MailboxListHeader) {
|
||||
throw new RuntimeException(sprintf('Unable to set header "%s".', $name));
|
||||
throw new RuntimeException(\sprintf('Unable to set header "%s".', $name));
|
||||
}
|
||||
|
||||
Headers::checkHeaderClass($header);
|
||||
|
||||
@@ -18,13 +18,13 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
*/
|
||||
class HttpTransportException extends TransportException
|
||||
{
|
||||
private ResponseInterface $response;
|
||||
|
||||
public function __construct(string $message, ResponseInterface $response, int $code = 0, ?\Throwable $previous = null)
|
||||
{
|
||||
public function __construct(
|
||||
string $message,
|
||||
private ResponseInterface $response,
|
||||
int $code = 0,
|
||||
?\Throwable $previous = null,
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
public function getResponse(): ResponseInterface
|
||||
|
||||
@@ -48,6 +48,10 @@ class UnsupportedSchemeException extends LogicException
|
||||
'class' => Bridge\Mailjet\Transport\MailjetTransportFactory::class,
|
||||
'package' => 'symfony/mailjet-mailer',
|
||||
],
|
||||
'mailomat' => [
|
||||
'class' => Bridge\Mailomat\Transport\MailomatTransportFactory::class,
|
||||
'package' => 'symfony/mailomat-mailer',
|
||||
],
|
||||
'mailpace' => [
|
||||
'class' => Bridge\MailPace\Transport\MailPaceTransportFactory::class,
|
||||
'package' => 'symfony/mail-pace-mailer',
|
||||
@@ -56,10 +60,18 @@ class UnsupportedSchemeException extends LogicException
|
||||
'class' => Bridge\Mailchimp\Transport\MandrillTransportFactory::class,
|
||||
'package' => 'symfony/mailchimp-mailer',
|
||||
],
|
||||
'postal' => [
|
||||
'class' => Bridge\Postal\Transport\PostalTransportFactory::class,
|
||||
'package' => 'symfony/postal-mailer',
|
||||
],
|
||||
'postmark' => [
|
||||
'class' => Bridge\Postmark\Transport\PostmarkTransportFactory::class,
|
||||
'package' => 'symfony/postmark-mailer',
|
||||
],
|
||||
'mailtrap' => [
|
||||
'class' => Bridge\Mailtrap\Transport\MailtrapTransportFactory::class,
|
||||
'package' => 'symfony/mailtrap-mailer',
|
||||
],
|
||||
'resend' => [
|
||||
'class' => Bridge\Resend\Transport\ResendTransportFactory::class,
|
||||
'package' => 'symfony/resend-mailer',
|
||||
@@ -76,6 +88,10 @@ class UnsupportedSchemeException extends LogicException
|
||||
'class' => Bridge\Amazon\Transport\SesTransportFactory::class,
|
||||
'package' => 'symfony/amazon-mailer',
|
||||
],
|
||||
'sweego' => [
|
||||
'class' => Bridge\Sweego\Transport\SweegoTransportFactory::class,
|
||||
'package' => 'symfony/sweego-mailer',
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct(Dsn $dsn, ?string $name = null, array $supported = [])
|
||||
@@ -86,14 +102,14 @@ class UnsupportedSchemeException extends LogicException
|
||||
}
|
||||
$package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null;
|
||||
if ($package && !class_exists($package['class'])) {
|
||||
parent::__construct(sprintf('Unable to send emails via "%s" as the bridge is not installed. Try running "composer require %s".', $provider, $package['package']));
|
||||
parent::__construct(\sprintf('Unable to send emails via "%s" as the bridge is not installed. Try running "composer require %s".', $provider, $package['package']));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf('The "%s" scheme is not supported', $dsn->getScheme());
|
||||
$message = \sprintf('The "%s" scheme is not supported', $dsn->getScheme());
|
||||
if ($name && $supported) {
|
||||
$message .= sprintf('; supported schemes for mailer "%s" are: "%s"', $name, implode('", "', $supported));
|
||||
$message .= \sprintf('; supported schemes for mailer "%s" are: "%s"', $name, implode('", "', $supported));
|
||||
}
|
||||
|
||||
parent::__construct($message.'.');
|
||||
|
||||
+4
-6
@@ -18,12 +18,10 @@ use Symfony\Component\Mime\Header\UnstructuredHeader;
|
||||
*/
|
||||
final class MetadataHeader extends UnstructuredHeader
|
||||
{
|
||||
private string $key;
|
||||
|
||||
public function __construct(string $key, string $value)
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
public function __construct(
|
||||
private string $key,
|
||||
string $value,
|
||||
) {
|
||||
parent::__construct('X-Metadata-'.$key, $value);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+5
-9
@@ -25,15 +25,11 @@ use Symfony\Component\Mime\RawMessage;
|
||||
*/
|
||||
final class Mailer implements MailerInterface
|
||||
{
|
||||
private TransportInterface $transport;
|
||||
private ?MessageBusInterface $bus;
|
||||
private ?EventDispatcherInterface $dispatcher;
|
||||
|
||||
public function __construct(TransportInterface $transport, ?MessageBusInterface $bus = null, ?EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
$this->transport = $transport;
|
||||
$this->bus = $bus;
|
||||
$this->dispatcher = $dispatcher;
|
||||
public function __construct(
|
||||
private TransportInterface $transport,
|
||||
private ?MessageBusInterface $bus = null,
|
||||
private ?EventDispatcherInterface $dispatcher = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function send(RawMessage $message, ?Envelope $envelope = null): void
|
||||
|
||||
+3
-5
@@ -19,11 +19,9 @@ use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||
*/
|
||||
class MessageHandler
|
||||
{
|
||||
private TransportInterface $transport;
|
||||
|
||||
public function __construct(TransportInterface $transport)
|
||||
{
|
||||
$this->transport = $transport;
|
||||
public function __construct(
|
||||
private TransportInterface $transport,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(SendEmailMessage $message): ?SentMessage
|
||||
|
||||
+4
-7
@@ -19,13 +19,10 @@ use Symfony\Component\Mime\RawMessage;
|
||||
*/
|
||||
class SendEmailMessage
|
||||
{
|
||||
private RawMessage $message;
|
||||
private ?Envelope $envelope;
|
||||
|
||||
public function __construct(RawMessage $message, ?Envelope $envelope = null)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->envelope = $envelope;
|
||||
public function __construct(
|
||||
private RawMessage $message,
|
||||
private ?Envelope $envelope = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getMessage(): RawMessage
|
||||
|
||||
Vendored
+13
@@ -64,6 +64,15 @@ $email = (new TemplatedEmail())
|
||||
$mailer->send($email);
|
||||
```
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
The Mailer component for Symfony 7.2 is [backed][1] by:
|
||||
|
||||
* [Sweego][2], a European email and SMS sending platform for developers and product builders. Easily create, deliver, and monitor your emails and notifications.
|
||||
|
||||
Help Symfony by [sponsoring][3] its development!
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
@@ -72,3 +81,7 @@ Resources
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
|
||||
[1]: https://symfony.com/backers
|
||||
[2]: https://www.sweego.io/
|
||||
[3]: https://symfony.com/sponsor
|
||||
|
||||
+4
-4
@@ -21,19 +21,19 @@ class SentMessage
|
||||
{
|
||||
private RawMessage $original;
|
||||
private RawMessage $raw;
|
||||
private Envelope $envelope;
|
||||
private string $messageId;
|
||||
private string $debug = '';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(RawMessage $message, Envelope $envelope)
|
||||
{
|
||||
public function __construct(
|
||||
RawMessage $message,
|
||||
private Envelope $envelope,
|
||||
) {
|
||||
$message->ensureValidity();
|
||||
|
||||
$this->original = $message;
|
||||
$this->envelope = $envelope;
|
||||
|
||||
if ($message instanceof Message) {
|
||||
$message = clone $message;
|
||||
|
||||
+7
-11
@@ -16,20 +16,16 @@ use Symfony\Component\Mailer\Event\MessageEvents;
|
||||
|
||||
final class EmailCount extends Constraint
|
||||
{
|
||||
private int $expectedValue;
|
||||
private ?string $transport;
|
||||
private bool $queued;
|
||||
|
||||
public function __construct(int $expectedValue, ?string $transport = null, bool $queued = false)
|
||||
{
|
||||
$this->expectedValue = $expectedValue;
|
||||
$this->transport = $transport;
|
||||
$this->queued = $queued;
|
||||
public function __construct(
|
||||
private int $expectedValue,
|
||||
private ?string $transport = null,
|
||||
private bool $queued = false,
|
||||
) {
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return sprintf('%shas %s "%d" emails', $this->transport ? $this->transport.' ' : '', $this->queued ? 'queued' : 'sent', $this->expectedValue);
|
||||
return \sprintf('%shas %s "%d" emails', $this->transport ? $this->transport.' ' : '', $this->queued ? 'queued' : 'sent', $this->expectedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +41,7 @@ final class EmailCount extends Constraint
|
||||
*/
|
||||
protected function failureDescription($events): string
|
||||
{
|
||||
return sprintf('the Transport %s (%d %s)', $this->toString(), $this->countEmails($events), $this->queued ? 'queued' : 'sent');
|
||||
return \sprintf('the Transport %s (%d %s)', $this->toString(), $this->countEmails($events), $this->queued ? 'queued' : 'sent');
|
||||
}
|
||||
|
||||
private function countEmails(MessageEvents $events): int
|
||||
|
||||
+10
-63
@@ -11,13 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\Mailer\Test;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Mailer\Exception\IncompleteDsnException;
|
||||
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||
use Symfony\Component\Mailer\Transport\Dsn;
|
||||
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
|
||||
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
@@ -25,81 +20,33 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
* A test case to ease testing Transport Factory.
|
||||
*
|
||||
* @author Konstantin Myakshin <molodchick@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 7.2, use AbstractTransportFactoryTestCase instead
|
||||
*/
|
||||
abstract class TransportFactoryTestCase extends TestCase
|
||||
abstract class TransportFactoryTestCase extends AbstractTransportFactoryTestCase
|
||||
{
|
||||
protected const USER = 'u$er';
|
||||
protected const PASSWORD = 'pa$s';
|
||||
use IncompleteDsnTestTrait;
|
||||
|
||||
protected EventDispatcherInterface $dispatcher;
|
||||
protected HttpClientInterface $client;
|
||||
protected LoggerInterface $logger;
|
||||
|
||||
abstract public function getFactory(): TransportFactoryInterface;
|
||||
|
||||
abstract public static function supportsProvider(): iterable;
|
||||
|
||||
abstract public static function createProvider(): iterable;
|
||||
|
||||
/**
|
||||
* @psalm-return iterable<array{0: Dsn, 1?: string|null}>
|
||||
*/
|
||||
public static function unsupportedSchemeProvider(): iterable
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return iterable<array{0: Dsn}>
|
||||
*/
|
||||
public static function incompleteDsnProvider(): iterable
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider supportsProvider
|
||||
*/
|
||||
public function testSupports(Dsn $dsn, bool $supports)
|
||||
{
|
||||
$factory = $this->getFactory();
|
||||
|
||||
$this->assertSame($supports, $factory->supports($dsn));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider createProvider
|
||||
*/
|
||||
public function testCreate(Dsn $dsn, TransportInterface $transport)
|
||||
{
|
||||
$factory = $this->getFactory();
|
||||
|
||||
$this->assertEquals($transport, $factory->create($dsn));
|
||||
if (str_contains('smtp', $dsn->getScheme())) {
|
||||
$this->assertStringMatchesFormat($dsn->getScheme().'://%S'.$dsn->getHost().'%S', (string) $transport);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider unsupportedSchemeProvider
|
||||
*/
|
||||
public function testUnsupportedSchemeException(Dsn $dsn, ?string $message = null)
|
||||
{
|
||||
$factory = $this->getFactory();
|
||||
|
||||
$this->expectException(UnsupportedSchemeException::class);
|
||||
if (null !== $message) {
|
||||
$this->expectExceptionMessage($message);
|
||||
}
|
||||
|
||||
$factory->create($dsn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider incompleteDsnProvider
|
||||
*/
|
||||
public function testIncompleteDsnException(Dsn $dsn)
|
||||
{
|
||||
$factory = $this->getFactory();
|
||||
|
||||
$this->expectException(IncompleteDsnException::class);
|
||||
$factory->create($dsn);
|
||||
}
|
||||
|
||||
protected function getDispatcher(): EventDispatcherInterface
|
||||
{
|
||||
return $this->dispatcher ??= $this->createMock(EventDispatcherInterface::class);
|
||||
|
||||
Vendored
+12
-6
@@ -22,11 +22,15 @@ use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory
|
||||
use Symfony\Component\Mailer\Bridge\MailerSend\Transport\MailerSendTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Mailjet\Transport\MailjetTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Mailomat\Transport\MailomatTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\MailPace\Transport\MailPaceTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Mailtrap\Transport\MailtrapTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Postal\Transport\PostalTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Resend\Transport\ResendTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Scaleway\Transport\ScalewayTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory;
|
||||
use Symfony\Component\Mailer\Bridge\Sweego\Transport\SweegoTransportFactory;
|
||||
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||
use Symfony\Component\Mailer\Transport\Dsn;
|
||||
@@ -55,17 +59,19 @@ final class Transport
|
||||
MailerSendTransportFactory::class,
|
||||
MailgunTransportFactory::class,
|
||||
MailjetTransportFactory::class,
|
||||
MailomatTransportFactory::class,
|
||||
MailPaceTransportFactory::class,
|
||||
MandrillTransportFactory::class,
|
||||
PostalTransportFactory::class,
|
||||
PostmarkTransportFactory::class,
|
||||
MailtrapTransportFactory::class,
|
||||
ResendTransportFactory::class,
|
||||
ScalewayTransportFactory::class,
|
||||
SendgridTransportFactory::class,
|
||||
SesTransportFactory::class,
|
||||
SweegoTransportFactory::class,
|
||||
];
|
||||
|
||||
private iterable $factories;
|
||||
|
||||
public static function fromDsn(#[\SensitiveParameter] string $dsn, ?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null): TransportInterface
|
||||
{
|
||||
$factory = new self(iterator_to_array(self::getDefaultFactories($dispatcher, $client, $logger)));
|
||||
@@ -83,9 +89,9 @@ final class Transport
|
||||
/**
|
||||
* @param TransportFactoryInterface[] $factories
|
||||
*/
|
||||
public function __construct(iterable $factories)
|
||||
{
|
||||
$this->factories = $factories;
|
||||
public function __construct(
|
||||
private iterable $factories,
|
||||
) {
|
||||
}
|
||||
|
||||
public function fromStrings(#[\SensitiveParameter] array $dsns): Transports
|
||||
@@ -144,7 +150,7 @@ final class Transport
|
||||
}
|
||||
|
||||
if (preg_match('{(\w+)\(}A', $dsn, $matches, 0, $offset)) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords))));
|
||||
throw new InvalidArgumentException(\sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords))));
|
||||
}
|
||||
|
||||
if ($pos = strcspn($dsn, ' )', $offset)) {
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class AbstractApiTransport extends AbstractHttpTransport
|
||||
try {
|
||||
$email = MessageConverter::toEmail($message->getOriginalMessage());
|
||||
} catch (\Exception $e) {
|
||||
throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e);
|
||||
throw new RuntimeException(\sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
return $this->doSendApi($message, $email, $message->getEnvelope());
|
||||
|
||||
@@ -26,14 +26,15 @@ abstract class AbstractHttpTransport extends AbstractTransport
|
||||
{
|
||||
protected ?string $host = null;
|
||||
protected ?int $port = null;
|
||||
protected ?HttpClientInterface $client;
|
||||
|
||||
public function __construct(?HttpClientInterface $client = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
public function __construct(
|
||||
protected ?HttpClientInterface $client = null,
|
||||
?EventDispatcherInterface $dispatcher = null,
|
||||
?LoggerInterface $logger = null,
|
||||
) {
|
||||
if (null === $client) {
|
||||
if (!class_exists(HttpClient::class)) {
|
||||
throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
|
||||
throw new \LogicException(\sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
|
||||
}
|
||||
|
||||
$this->client = HttpClient::create();
|
||||
|
||||
+6
-6
@@ -30,14 +30,14 @@ use Symfony\Component\Mime\RawMessage;
|
||||
*/
|
||||
abstract class AbstractTransport implements TransportInterface
|
||||
{
|
||||
private ?EventDispatcherInterface $dispatcher;
|
||||
private LoggerInterface $logger;
|
||||
private float $rate = 0;
|
||||
private float $lastSent = 0;
|
||||
|
||||
public function __construct(?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
public function __construct(
|
||||
private ?EventDispatcherInterface $dispatcher = null,
|
||||
?LoggerInterface $logger = null,
|
||||
) {
|
||||
$this->logger = $logger ?? new NullLogger();
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ abstract class AbstractTransport implements TransportInterface
|
||||
$message = $event->getMessage();
|
||||
|
||||
if ($message instanceof TemplatedEmail && !$message->isRendered()) {
|
||||
throw new LogicException(sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message)));
|
||||
throw new LogicException(\sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message)));
|
||||
}
|
||||
|
||||
$sentMessage = new SentMessage($message, $envelope);
|
||||
@@ -128,7 +128,7 @@ abstract class AbstractTransport implements TransportInterface
|
||||
|
||||
$sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent);
|
||||
if (0 < $sleep) {
|
||||
$this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep));
|
||||
$this->logger->debug(\sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep));
|
||||
usleep((int) ($sleep * 1000000));
|
||||
}
|
||||
$this->lastSent = microtime(true);
|
||||
|
||||
@@ -21,15 +21,11 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
*/
|
||||
abstract class AbstractTransportFactory implements TransportFactoryInterface
|
||||
{
|
||||
protected ?EventDispatcherInterface $dispatcher;
|
||||
protected ?HttpClientInterface $client;
|
||||
protected ?LoggerInterface $logger;
|
||||
|
||||
public function __construct(?EventDispatcherInterface $dispatcher = null, ?HttpClientInterface $client = null, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->client = $client;
|
||||
$this->logger = $logger;
|
||||
public function __construct(
|
||||
protected ?EventDispatcherInterface $dispatcher = null,
|
||||
protected ?HttpClientInterface $client = null,
|
||||
protected ?LoggerInterface $logger = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function supports(Dsn $dsn): bool
|
||||
|
||||
+8
-15
@@ -18,21 +18,14 @@ use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||||
*/
|
||||
final class Dsn
|
||||
{
|
||||
private string $scheme;
|
||||
private string $host;
|
||||
private ?string $user;
|
||||
private ?string $password;
|
||||
private ?int $port;
|
||||
private array $options;
|
||||
|
||||
public function __construct(string $scheme, string $host, ?string $user = null, #[\SensitiveParameter] ?string $password = null, ?int $port = null, array $options = [])
|
||||
{
|
||||
$this->scheme = $scheme;
|
||||
$this->host = $host;
|
||||
$this->user = $user;
|
||||
$this->password = $password;
|
||||
$this->port = $port;
|
||||
$this->options = $options;
|
||||
public function __construct(
|
||||
private string $scheme,
|
||||
private string $host,
|
||||
private ?string $user = null,
|
||||
#[\SensitiveParameter] private ?string $password = null,
|
||||
private ?int $port = null,
|
||||
private array $options = [],
|
||||
) {
|
||||
}
|
||||
|
||||
public static function fromString(#[\SensitiveParameter] string $dsn): self
|
||||
|
||||
+6
-8
@@ -28,22 +28,20 @@ class RoundRobinTransport implements TransportInterface
|
||||
* @var \SplObjectStorage<TransportInterface, float>
|
||||
*/
|
||||
private \SplObjectStorage $deadTransports;
|
||||
private array $transports = [];
|
||||
private int $retryPeriod;
|
||||
private int $cursor = -1;
|
||||
|
||||
/**
|
||||
* @param TransportInterface[] $transports
|
||||
*/
|
||||
public function __construct(array $transports, int $retryPeriod = 60)
|
||||
{
|
||||
public function __construct(
|
||||
private array $transports,
|
||||
private int $retryPeriod = 60,
|
||||
) {
|
||||
if (!$transports) {
|
||||
throw new TransportException(sprintf('"%s" must have at least one transport configured.', static::class));
|
||||
throw new TransportException(\sprintf('"%s" must have at least one transport configured.', static::class));
|
||||
}
|
||||
|
||||
$this->transports = $transports;
|
||||
$this->deadTransports = new \SplObjectStorage();
|
||||
$this->retryPeriod = $retryPeriod;
|
||||
}
|
||||
|
||||
public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMessage
|
||||
@@ -55,7 +53,7 @@ class RoundRobinTransport implements TransportInterface
|
||||
return $transport->send($message, $envelope);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$exception ??= new TransportException('All transports failed.');
|
||||
$exception->appendDebug(sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug()));
|
||||
$exception->appendDebug(\sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug()));
|
||||
$this->deadTransports[$transport] = microtime(true);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -55,7 +55,7 @@ class SendmailTransport extends AbstractTransport
|
||||
|
||||
if (null !== $command) {
|
||||
if (!str_contains($command, ' -bs') && !str_contains($command, ' -t')) {
|
||||
throw new \InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command));
|
||||
throw new \InvalidArgumentException(\sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command));
|
||||
}
|
||||
|
||||
$this->command = $command;
|
||||
@@ -89,7 +89,7 @@ class SendmailTransport extends AbstractTransport
|
||||
|
||||
protected function doSend(SentMessage $message): void
|
||||
{
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" starting', __CLASS__));
|
||||
|
||||
$command = $this->command;
|
||||
|
||||
@@ -119,6 +119,6 @@ class SendmailTransport extends AbstractTransport
|
||||
$this->stream->flush();
|
||||
$this->stream->terminate();
|
||||
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class CramMd5Authenticator implements AuthenticatorInterface
|
||||
$challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]);
|
||||
$challenge = base64_decode(substr($challenge, 4));
|
||||
$message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge));
|
||||
$client->executeCommand(sprintf("%s\r\n", $message), [235]);
|
||||
$client->executeCommand(\sprintf("%s\r\n", $message), [235]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,8 +58,7 @@ class CramMd5Authenticator implements AuthenticatorInterface
|
||||
$kopad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64);
|
||||
|
||||
$inner = pack('H32', md5($kipad.$challenge));
|
||||
$digest = md5($kopad.$inner);
|
||||
|
||||
return $digest;
|
||||
return md5($kopad.$inner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class LoginAuthenticator implements AuthenticatorInterface
|
||||
public function authenticate(EsmtpTransport $client): void
|
||||
{
|
||||
$client->executeCommand("AUTH LOGIN\r\n", [334]);
|
||||
$client->executeCommand(sprintf("%s\r\n", base64_encode($client->getUsername())), [334]);
|
||||
$client->executeCommand(sprintf("%s\r\n", base64_encode($client->getPassword())), [235]);
|
||||
$client->executeCommand(\sprintf("%s\r\n", base64_encode($client->getUsername())), [334]);
|
||||
$client->executeCommand(\sprintf("%s\r\n", base64_encode($client->getPassword())), [235]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,6 @@ class PlainAuthenticator implements AuthenticatorInterface
|
||||
*/
|
||||
public function authenticate(EsmtpTransport $client): void
|
||||
{
|
||||
$client->executeCommand(sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]);
|
||||
$client->executeCommand(\sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -142,10 +142,10 @@ class EsmtpTransport extends SmtpTransport
|
||||
private function doEhloCommand(): string
|
||||
{
|
||||
try {
|
||||
$response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
|
||||
$response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
try {
|
||||
return parent::executeCommand(sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]);
|
||||
return parent::executeCommand(\sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]);
|
||||
} catch (TransportExceptionInterface $ex) {
|
||||
if (!$ex->getCode()) {
|
||||
throw $e;
|
||||
@@ -169,7 +169,7 @@ class EsmtpTransport extends SmtpTransport
|
||||
throw new TransportException('Unable to connect with STARTTLS.');
|
||||
}
|
||||
|
||||
$response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
|
||||
$response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
|
||||
$this->capabilities = $this->parseCapabilities($response);
|
||||
}
|
||||
|
||||
@@ -195,6 +195,11 @@ class EsmtpTransport extends SmtpTransport
|
||||
return $capabilities;
|
||||
}
|
||||
|
||||
protected function serverSupportsSmtpUtf8(): bool
|
||||
{
|
||||
return \array_key_exists('SMTPUTF8', $this->capabilities);
|
||||
}
|
||||
|
||||
private function handleAuth(array $modes): void
|
||||
{
|
||||
if (!$this->username) {
|
||||
@@ -231,12 +236,12 @@ class EsmtpTransport extends SmtpTransport
|
||||
}
|
||||
|
||||
if (!$authNames) {
|
||||
throw new TransportException(sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504);
|
||||
throw new TransportException(\sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504);
|
||||
}
|
||||
|
||||
$message = sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames));
|
||||
$message = \sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames));
|
||||
foreach ($errors as $name => $error) {
|
||||
$message .= sprintf(' Authenticator "%s" returned "%s".', $name, $error);
|
||||
$message .= \sprintf(' Authenticator "%s" returned "%s".', $name, $error);
|
||||
}
|
||||
|
||||
throw new TransportException($message, $code ?: 535);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Mailer\Transport\Smtp;
|
||||
|
||||
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
|
||||
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
|
||||
use Symfony\Component\Mailer\Transport\Dsn;
|
||||
use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream;
|
||||
@@ -23,6 +24,10 @@ final class EsmtpTransportFactory extends AbstractTransportFactory
|
||||
{
|
||||
public function create(Dsn $dsn): TransportInterface
|
||||
{
|
||||
if (!\in_array($dsn->getScheme(), $this->getSupportedSchemes(), true)) {
|
||||
throw new UnsupportedSchemeException($dsn, 'smtp', $this->getSupportedSchemes());
|
||||
}
|
||||
|
||||
$autoTls = '' === $dsn->getOption('auto_tls') || filter_var($dsn->getOption('auto_tls', true), \FILTER_VALIDATE_BOOL);
|
||||
$tls = 'smtps' === $dsn->getScheme() ? true : ($autoTls ? null : false);
|
||||
$port = $dsn->getPort(0);
|
||||
|
||||
+25
-16
@@ -14,6 +14,7 @@ namespace Symfony\Component\Mailer\Transport\Smtp;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Mailer\Envelope;
|
||||
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Mailer\Exception\LogicException;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
@@ -171,7 +172,7 @@ class SmtpTransport extends AbstractTransport
|
||||
public function __toString(): string
|
||||
{
|
||||
if ($this->stream instanceof SocketStream) {
|
||||
$name = sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost());
|
||||
$name = \sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost());
|
||||
$port = $this->stream->getPort();
|
||||
if (!(25 === $port || ($tls && 465 === $port))) {
|
||||
$name .= ':'.$port;
|
||||
@@ -211,7 +212,7 @@ class SmtpTransport extends AbstractTransport
|
||||
|
||||
try {
|
||||
$envelope = $message->getEnvelope();
|
||||
$this->doMailFromCommand($envelope->getSender()->getEncodedAddress());
|
||||
$this->doMailFromCommand($envelope->getSender()->getEncodedAddress(), $envelope->anyAddressHasUnicodeLocalpart());
|
||||
foreach ($envelope->getRecipients() as $recipient) {
|
||||
$this->doRcptToCommand($recipient->getEncodedAddress());
|
||||
}
|
||||
@@ -227,7 +228,7 @@ class SmtpTransport extends AbstractTransport
|
||||
} catch (\Exception $e) {
|
||||
$this->stream->terminate();
|
||||
$this->started = false;
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__));
|
||||
throw $e;
|
||||
}
|
||||
$mtaResult = $this->executeCommand("\r\n.\r\n", [250]);
|
||||
@@ -244,19 +245,27 @@ class SmtpTransport extends AbstractTransport
|
||||
}
|
||||
}
|
||||
|
||||
private function doHeloCommand(): void
|
||||
protected function serverSupportsSmtpUtf8(): bool
|
||||
{
|
||||
$this->executeCommand(sprintf("HELO %s\r\n", $this->domain), [250]);
|
||||
return false;
|
||||
}
|
||||
|
||||
private function doMailFromCommand(string $address): void
|
||||
private function doHeloCommand(): void
|
||||
{
|
||||
$this->executeCommand(sprintf("MAIL FROM:<%s>\r\n", $address), [250]);
|
||||
$this->executeCommand(\sprintf("HELO %s\r\n", $this->domain), [250]);
|
||||
}
|
||||
|
||||
private function doMailFromCommand(string $address, bool $smtputf8): void
|
||||
{
|
||||
if ($smtputf8 && !$this->serverSupportsSmtpUtf8()) {
|
||||
throw new InvalidArgumentException('Invalid addresses: non-ASCII characters not supported in local-part of email.');
|
||||
}
|
||||
$this->executeCommand(\sprintf("MAIL FROM:<%s>%s\r\n", $address, $smtputf8 ? ' SMTPUTF8' : ''), [250]);
|
||||
}
|
||||
|
||||
private function doRcptToCommand(string $address): void
|
||||
{
|
||||
$this->executeCommand(sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]);
|
||||
$this->executeCommand(\sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]);
|
||||
}
|
||||
|
||||
public function start(): void
|
||||
@@ -265,7 +274,7 @@ class SmtpTransport extends AbstractTransport
|
||||
return;
|
||||
}
|
||||
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" starting', __CLASS__));
|
||||
|
||||
$this->stream->initialize();
|
||||
$this->assertResponseCode($this->getFullResponse(), [220]);
|
||||
@@ -273,7 +282,7 @@ class SmtpTransport extends AbstractTransport
|
||||
$this->started = true;
|
||||
$this->lastMessageTime = 0;
|
||||
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" started', __CLASS__));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,7 +298,7 @@ class SmtpTransport extends AbstractTransport
|
||||
return;
|
||||
}
|
||||
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" stopping', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" stopping', __CLASS__));
|
||||
|
||||
try {
|
||||
$this->executeCommand("QUIT\r\n", [221]);
|
||||
@@ -297,7 +306,7 @@ class SmtpTransport extends AbstractTransport
|
||||
} finally {
|
||||
$this->stream->terminate();
|
||||
$this->started = false;
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,10 +336,10 @@ class SmtpTransport extends AbstractTransport
|
||||
$valid = \in_array($code, $codes);
|
||||
|
||||
if (!$valid || !$response) {
|
||||
$codeStr = $code ? sprintf('code "%s"', $code) : 'empty code';
|
||||
$responseStr = $response ? sprintf(', with message "%s"', trim($response)) : '';
|
||||
$codeStr = $code ? \sprintf('code "%s"', $code) : 'empty code';
|
||||
$responseStr = $response ? \sprintf(', with message "%s"', trim($response)) : '';
|
||||
|
||||
throw new UnexpectedResponseException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0);
|
||||
throw new UnexpectedResponseException(\sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +368,7 @@ class SmtpTransport extends AbstractTransport
|
||||
|
||||
$this->stop();
|
||||
if (0 < $sleep = $this->restartThresholdSleep) {
|
||||
$this->getLogger()->debug(sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep));
|
||||
$this->getLogger()->debug(\sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep));
|
||||
|
||||
sleep($sleep);
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ abstract class AbstractStream
|
||||
public function write(string $bytes, bool $debug = true): void
|
||||
{
|
||||
if ($debug) {
|
||||
$timestamp = date('c');
|
||||
$timestamp = (new \DateTimeImmutable())->format('Y-m-d\TH:i:s.up');
|
||||
foreach (explode("\n", trim($bytes)) as $line) {
|
||||
$this->debug .= sprintf("[%s] > %s\n", $timestamp, $line);
|
||||
$this->debug .= \sprintf("[%s] > %s\n", $timestamp, $line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,17 +83,17 @@ abstract class AbstractStream
|
||||
if ('' === $line || false === $line) {
|
||||
$metas = stream_get_meta_data($this->out);
|
||||
if ($metas['timed_out']) {
|
||||
throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
|
||||
throw new TransportException(\sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
|
||||
}
|
||||
if ($metas['eof']) {
|
||||
throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
|
||||
throw new TransportException(\sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
|
||||
}
|
||||
if (false === $line) {
|
||||
throw new TransportException(sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']);
|
||||
throw new TransportException(\sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->debug .= sprintf('[%s] < %s', date('c'), $line);
|
||||
$this->debug .= \sprintf('[%s] < %s', (new \DateTimeImmutable())->format('Y-m-d\TH:i:s.up'), $line);
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ final class SocketStream extends AbstractStream
|
||||
|
||||
$timeout = $this->getTimeout();
|
||||
set_error_handler(function ($type, $msg) {
|
||||
throw new TransportException(sprintf('Connection could not be established with host "%s": ', $this->url).$msg);
|
||||
throw new TransportException(\sprintf('Connection could not be established with host "%s": ', $this->url).$msg);
|
||||
});
|
||||
try {
|
||||
$this->stream = stream_socket_client($this->url, $errno, $errstr, $timeout, \STREAM_CLIENT_CONNECT, $streamContext);
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ final class Transports implements TransportInterface
|
||||
}
|
||||
|
||||
if (!$this->transports) {
|
||||
throw new LogicException(sprintf('"%s" must have at least one transport configured.', __CLASS__));
|
||||
throw new LogicException(\sprintf('"%s" must have at least one transport configured.', __CLASS__));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ final class Transports implements TransportInterface
|
||||
$headers->remove('X-Transport');
|
||||
|
||||
if (!isset($this->transports[$transport])) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports))));
|
||||
throw new InvalidArgumentException(\sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports))));
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Vendored
+1
-1
@@ -21,7 +21,7 @@
|
||||
"psr/event-dispatcher": "^1",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/event-dispatcher": "^6.4|^7.0",
|
||||
"symfony/mime": "^6.4|^7.0",
|
||||
"symfony/mime": "^7.2",
|
||||
"symfony/service-contracts": "^2.5|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
Reference in New Issue
Block a user