Add transport factories (closes #31385, closes #32523)

This commit is contained in:
Konstantin Myakshin 2019-06-06 02:11:36 +03:00
parent af309b0acf
commit 5b9cded276
32 changed files with 1672 additions and 479 deletions

View File

@ -77,6 +77,12 @@ use Symfony\Component\Lock\PersistStoreInterface;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\StoreFactory;
use Symfony\Component\Lock\StoreInterface;
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Symfony\Component\Messenger\MessageBus;
@ -1955,8 +1961,24 @@ class FrameworkExtension extends Extension
}
$loader->load('mailer.xml');
$loader->load('mailer_transports.xml');
$container->getDefinition('mailer.default_transport')->setArgument(0, $config['dsn']);
$classToServices = [
SesTransportFactory::class => 'mailer.transport_factory.amazon',
GmailTransportFactory::class => 'mailer.transport_factory.gmail',
MandrillTransportFactory::class => 'mailer.transport_factory.mailchimp',
MailgunTransportFactory::class => 'mailer.transport_factory.mailgun',
PostmarkTransportFactory::class => 'mailer.transport_factory.postmark',
SendgridTransportFactory::class => 'mailer.transport_factory.sendgrid',
];
foreach ($classToServices as $class => $service) {
if (!class_exists($class)) {
$container->removeDefinition($service);
}
}
$recipients = $config['envelope']['recipients'] ?? null;
$sender = $config['envelope']['sender'] ?? null;

View File

@ -12,12 +12,13 @@
<service id="mailer" alias="mailer.mailer" />
<service id="Symfony\Component\Mailer\MailerInterface" alias="mailer.mailer" />
<service id="mailer.transport_factory" class="Symfony\Component\Mailer\Transport">
<argument type="tagged_iterator" tag="mailer.transport_factory" />
</service>
<service id="mailer.default_transport" class="Symfony\Component\Mailer\Transport\TransportInterface">
<factory class="Symfony\Component\Mailer\Transport" method="fromDsn" />
<factory service="mailer.transport_factory" method="fromString" />
<argument /> <!-- env(MAILER_DSN) -->
<argument type="service" id="event_dispatcher" />
<argument type="service" id="http_client" on-invalid="ignore" />
<argument type="service" id="logger" on-invalid="ignore" />
</service>
<service id="Symfony\Component\Mailer\Transport\TransportInterface" alias="mailer.default_transport" />

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="mailer.transport_factory.abstract" class="Symfony\Component\Mailer\Transport\AbstractTransportFactory" abstract="true">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="http_client" on-invalid="ignore" />
<argument type="service" id="logger" on-invalid="ignore" />
</service>
<service id="mailer.transport_factory.amazon" class="Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.gmail" class="Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.mailchimp" class="Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.mailgun" class="Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.postmark" class="Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.sendgrid" class="Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.null" class="Symfony\Component\Mailer\Transport\NullTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.sendmail" class="Symfony\Component\Mailer\Transport\SendmailTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" />
</service>
<service id="mailer.transport_factory.smtp" class="Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory" parent="mailer.transport_factory.abstract">
<tag name="mailer.transport_factory" priority="-100" />
</service>
</services>
</container>

View File

@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Amazon\Factory;
use Symfony\Component\Mailer\Bridge\Amazon;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class SesTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$scheme = $dsn->getScheme();
$user = $this->getUser($dsn);
$password = $this->getPassword($dsn);
$region = $dsn->getOption('region');
if ('api' === $scheme) {
return new Amazon\Http\Api\SesTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
}
if ('http' === $scheme) {
return new Amazon\Http\SesTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
}
if ('smtp' === $scheme) {
return new Amazon\Smtp\SesTransport($user, $password, $region, $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'ses' === $dsn->getHost();
}
}

View File

@ -0,0 +1,98 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Factory;
use Symfony\Component\Mailer\Bridge\Amazon;
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class SesTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new SesTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('api', 'ses'),
true,
];
yield [
new Dsn('http', 'ses'),
true,
];
yield [
new Dsn('smtp', 'ses'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
$client = $this->getClient();
$dispatcher = $this->getDispatcher();
$logger = $this->getLogger();
yield [
new Dsn('api', 'ses', self::USER, self::PASSWORD),
new Amazon\Http\Api\SesTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
];
yield [
new Dsn('api', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
new Amazon\Http\Api\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
];
yield [
new Dsn('http', 'ses', self::USER, self::PASSWORD),
new Amazon\Http\SesTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
];
yield [
new Dsn('http', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
new Amazon\Http\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
];
yield [
new Dsn('smtp', 'ses', self::USER, self::PASSWORD),
new Amazon\Smtp\SesTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger),
];
yield [
new Dsn('smtp', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
new Amazon\Smtp\SesTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('foo', 'ses', self::USER, self::PASSWORD)];
}
public function incompleteDsnProvider(): iterable
{
yield [new Dsn('smtp', 'ses', self::USER)];
yield [new Dsn('smtp', 'ses', null, self::PASSWORD)];
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Google\Factory;
use Symfony\Component\Mailer\Bridge\Google\Smtp\GmailTransport;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class GmailTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
if ('smtp' === $dsn->getScheme()) {
return new GmailTransport($this->getUser($dsn), $this->getPassword($dsn), $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'gmail' === $dsn->getHost();
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Symfony\Component\Mailer\Bridge\Google\Tests\Factory;
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
use Symfony\Component\Mailer\Bridge\Google\Smtp\GmailTransport;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class GmailTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new GmailTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('smtp', 'gmail'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
yield [
new Dsn('smtp', 'gmail', self::USER, self::PASSWORD),
new GmailTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('http', 'gmail', self::USER, self::PASSWORD)];
}
public function incompleteDsnProvider(): iterable
{
yield [new Dsn('smtp', 'gmail', self::USER)];
yield [new Dsn('smtp', 'gmail', null, self::PASSWORD)];
}
}

View File

@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Factory;
use Symfony\Component\Mailer\Bridge\Mailchimp;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class MandrillTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$scheme = $dsn->getScheme();
$user = $this->getUser($dsn);
if ('api' === $scheme) {
return new Mailchimp\Http\Api\MandrillTransport($user, $this->client, $this->dispatcher, $this->logger);
}
if ('http' === $scheme) {
return new Mailchimp\Http\MandrillTransport($user, $this->client, $this->dispatcher, $this->logger);
}
if ('smtp' === $scheme) {
$password = $this->getPassword($dsn);
return new Mailchimp\Smtp\MandrillTransport($user, $password, $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'mandrill' === $dsn->getHost();
}
}

View File

@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Tests\Factory;
use Symfony\Component\Mailer\Bridge\Mailchimp;
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class MandrillTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new MandrillTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('api', 'mandrill'),
true,
];
yield [
new Dsn('http', 'mandrill'),
true,
];
yield [
new Dsn('smtp', 'mandrill'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
$client = $this->getClient();
$dispatcher = $this->getDispatcher();
$logger = $this->getLogger();
yield [
new Dsn('api', 'mandrill', self::USER),
new Mailchimp\Http\Api\MandrillTransport(self::USER, $client, $dispatcher, $logger),
];
yield [
new Dsn('http', 'mandrill', self::USER),
new Mailchimp\Http\MandrillTransport(self::USER, $client, $dispatcher, $logger),
];
yield [
new Dsn('smtp', 'mandrill', self::USER, self::PASSWORD),
new Mailchimp\Smtp\MandrillTransport(self::USER, self::PASSWORD, $dispatcher, $logger),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('foo', 'mandrill', self::USER)];
}
public function incompleteDsnProvider(): iterable
{
yield [new Dsn('api', 'mandrill')];
yield [new Dsn('smtp', 'mandrill', self::USER)];
}
}

View File

@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Mailgun\Factory;
use Symfony\Component\Mailer\Bridge\Mailgun;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class MailgunTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$scheme = $dsn->getScheme();
$user = $this->getUser($dsn);
$password = $this->getPassword($dsn);
$region = $dsn->getOption('region');
if ('api' === $scheme) {
return new Mailgun\Http\Api\MailgunTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
}
if ('http' === $scheme) {
return new Mailgun\Http\MailgunTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
}
if ('smtp' === $scheme) {
return new Mailgun\Smtp\MailgunTransport($user, $password, $region, $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'mailgun' === $dsn->getHost();
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace Symfony\Component\Mailer\Bridge\Mailgun\Tests\Factory;
use Symfony\Component\Mailer\Bridge\Mailgun;
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class MailgunTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new MailgunTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('api', 'mailgun'),
true,
];
yield [
new Dsn('http', 'mailgun'),
true,
];
yield [
new Dsn('smtp', 'mailgun'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
$client = $this->getClient();
$dispatcher = $this->getDispatcher();
$logger = $this->getLogger();
yield [
new Dsn('api', 'mailgun', self::USER, self::PASSWORD),
new Mailgun\Http\Api\MailgunTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
];
yield [
new Dsn('api', 'mailgun', self::USER, self::PASSWORD, null, ['region' => 'eu']),
new Mailgun\Http\Api\MailgunTransport(self::USER, self::PASSWORD, 'eu', $client, $dispatcher, $logger),
];
yield [
new Dsn('http', 'mailgun', self::USER, self::PASSWORD),
new Mailgun\Http\MailgunTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
];
yield [
new Dsn('smtp', 'mailgun', self::USER, self::PASSWORD),
new Mailgun\Smtp\MailgunTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('foo', 'mailgun', self::USER, self::PASSWORD)];
}
public function incompleteDsnProvider(): iterable
{
yield [new Dsn('api', 'mailgun', self::USER)];
yield [new Dsn('api', 'mailgun', null, self::PASSWORD)];
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Postmark\Factory;
use Symfony\Component\Mailer\Bridge\Postmark;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class PostmarkTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$scheme = $dsn->getScheme();
$user = $this->getUser($dsn);
if ('api' === $scheme) {
return new Postmark\Http\Api\PostmarkTransport($user, $this->client, $this->dispatcher, $this->logger);
}
if ('smtp' === $scheme) {
return new Postmark\Smtp\PostmarkTransport($user, $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'postmark' === $dsn->getHost();
}
}

View File

@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Postmark\Tests\Factory;
use Symfony\Component\Mailer\Bridge\Postmark;
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class PostmarkTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new PostmarkTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('api', 'postmark'),
true,
];
yield [
new Dsn('smtp', 'postmark'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
$dispatcher = $this->getDispatcher();
$logger = $this->getLogger();
yield [
new Dsn('api', 'postmark', self::USER),
new Postmark\Http\Api\PostmarkTransport(self::USER, $this->getClient(), $dispatcher, $logger),
];
yield [
new Dsn('smtp', 'postmark', self::USER),
new Postmark\Smtp\PostmarkTransport(self::USER, $dispatcher, $logger),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('foo', 'postmark', self::USER)];
}
public function incompleteDsnProvider(): iterable
{
yield [new Dsn('api', 'postmark')];
}
}

View File

@ -0,0 +1,44 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Sendgrid\Factory;
use Symfony\Component\Mailer\Bridge\Sendgrid;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class SendgridTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$key = $this->getUser($dsn);
if ('api' === $dsn->getScheme()) {
return new Sendgrid\Http\Api\SendgridTransport($key, $this->client, $this->dispatcher, $this->logger);
}
if ('smtp' === $dsn->getScheme()) {
return new Sendgrid\Smtp\SendgridTransport($key, $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'sendgrid' === $dsn->getHost();
}
}

View File

@ -0,0 +1,65 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Sendgrid\Tests\Factory;
use Symfony\Component\Mailer\Bridge\Sendgrid;
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class SendgridTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new SendgridTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('api', 'sendgrid'),
true,
];
yield [
new Dsn('smtp', 'sendgrid'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
$dispatcher = $this->getDispatcher();
$logger = $this->getLogger();
yield [
new Dsn('api', 'sendgrid', self::USER),
new Sendgrid\Http\Api\SendgridTransport(self::USER, $this->getClient(), $dispatcher, $logger),
];
yield [
new Dsn('smtp', 'sendgrid', self::USER),
new Sendgrid\Smtp\SendgridTransport(self::USER, $dispatcher, $logger),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('foo', 'sendgrid', self::USER)];
}
}

View File

@ -6,6 +6,8 @@ CHANGELOG
* [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface`
instead of `Symfony\Component\EventDispatcher\EventDispatcherInterface`.
* Added possibility to register custom transport for dsn by implementing
`Symfony\Component\Mailer\Transport\TransportFactoryInterface` and tagging with `mailer.transport_factory` tag in DI.
4.3.0
-----

View File

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Exception;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
class IncompleteDsnException extends InvalidArgumentException
{
}

View File

@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Exception;
use Symfony\Component\Mailer\Bridge;
use Symfony\Component\Mailer\Transport\Dsn;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
class UnsupportedHostException extends LogicException
{
private const HOST_TO_PACKAGE_MAP = [
'gmail' => [
'class' => Bridge\Google\Factory\GmailTransportFactory::class,
'package' => 'symfony/google-mailer',
],
'mailgun' => [
'class' => Bridge\Mailgun\Factory\MailgunTransportFactory::class,
'package' => 'symfony/mailgun-mailer',
],
'postmark' => [
'class' => Bridge\Postmark\Factory\PostmarkTransportFactory::class,
'package' => 'symfony/postmark-mailer',
],
'sendgrid' => [
'class' => Bridge\Sendgrid\Factory\SendgridTransportFactory::class,
'package' => 'symfony/sendgrid-mailer',
],
'ses' => [
'class' => Bridge\Amazon\Factory\SesTransportFactory::class,
'package' => 'symfony/amazon-mailer',
],
'mandrill' => [
'class' => Bridge\Mailchimp\Factory\MandrillTransportFactory::class,
'package' => 'symfony/mailchimp-mailer',
],
];
public function __construct(Dsn $dsn)
{
$host = $dsn->getHost();
$package = self::HOST_TO_PACKAGE_MAP[$host] ?? 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".', $host, $package['package']));
return;
}
parent::__construct(sprintf('The "%s" mailer is not supported.', $host));
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Exception;
use Symfony\Component\Mailer\Transport\Dsn;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
class UnsupportedSchemeException extends LogicException
{
public function __construct(Dsn $dsn)
{
parent::__construct(sprintf('The "%s" scheme is not supported for mailer "%s".', $dsn->getScheme(), $dsn->getHost()));
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Tests\Transport;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
use Symfony\Component\Mailer\Transport\Dsn;
class DsnTest extends TestCase
{
/**
* @dataProvider fromStringProvider
*/
public function testFromString(string $string, Dsn $dsn): void
{
$this->assertEquals($dsn, Dsn::fromString($string));
}
public function testGetOption(): void
{
$options = ['with_value' => 'some value', 'nullable' => null];
$dsn = new Dsn('smtp', 'example.com', null, null, null, $options);
$this->assertSame('some value', $dsn->getOption('with_value'));
$this->assertSame('default', $dsn->getOption('nullable', 'default'));
$this->assertSame('default', $dsn->getOption('not_existent_property', 'default'));
}
/**
* @dataProvider invalidDsnProvider
*/
public function testInvalidDsn(string $dsn, string $exceptionMessage): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage($exceptionMessage);
Dsn::fromString($dsn);
}
public function fromStringProvider(): iterable
{
yield 'simple smtp without user and pass' => [
'smtp://example.com',
new Dsn('smtp', 'example.com'),
];
yield 'simple smtp with custom port' => [
'smtp://user1:pass2@example.com:99',
new Dsn('smtp', 'example.com', 'user1', 'pass2', 99),
];
yield 'gmail smtp with urlencoded user and pass' => [
'smtp://u%24er:pa%24s@gmail',
new Dsn('smtp', 'gmail', 'u$er', 'pa$s'),
];
yield 'mailgun api with custom options' => [
'api://u%24er:pa%24s@mailgun?region=eu',
new Dsn('api', 'mailgun', 'u$er', 'pa$s', null, ['region' => 'eu']),
];
}
public function invalidDsnProvider(): iterable
{
yield [
'some://',
'The "some://" mailer DSN is invalid.',
];
yield [
'//sendmail',
'The "//sendmail" mailer DSN must contain a transport scheme.',
];
yield [
'file:///some/path',
'The "file:///some/path" mailer DSN must contain a mailer name.',
];
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Tests\Transport;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\NullTransport;
use Symfony\Component\Mailer\Transport\NullTransportFactory;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class NullTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new NullTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('smtp', 'null'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
yield [
new Dsn('smtp', 'null'),
new NullTransport($this->getDispatcher(), $this->getLogger()),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('foo', 'null')];
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Tests\Transport;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\SendmailTransport;
use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class SendmailTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new SendmailTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('smtp', 'sendmail'),
true,
];
yield [
new Dsn('smtp', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
yield [
new Dsn('smtp', 'sendmail'),
new SendmailTransport(null, $this->getDispatcher(), $this->getLogger()),
];
}
public function unsupportedSchemeProvider(): iterable
{
yield [new Dsn('http', 'sendmail')];
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace Symfony\Component\Mailer\Tests\Transport\Smtp;
use Symfony\Component\Mailer\Tests\TransportFactoryTestCase;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
class EsmtpTransportFactoryTest extends TransportFactoryTestCase
{
public function getFactory(): TransportFactoryInterface
{
return new EsmtpTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger());
}
public function supportsProvider(): iterable
{
yield [
new Dsn('smtp', 'example.com'),
true,
];
yield [
new Dsn('api', 'example.com'),
false,
];
}
public function createProvider(): iterable
{
$eventDispatcher = $this->getDispatcher();
$logger = $this->getLogger();
$transport = new EsmtpTransport('example.com', 25, null, null, $eventDispatcher, $logger);
yield [
new Dsn('smtp', 'example.com'),
$transport,
];
$transport = new EsmtpTransport('example.com', 99, 'ssl', 'login', $eventDispatcher, $logger);
$transport->setUsername(self::USER);
$transport->setPassword(self::PASSWORD);
yield [
new Dsn('smtp', 'example.com', self::USER, self::PASSWORD, 99, ['encryption' => 'ssl', 'auth_mode' => 'login']),
$transport,
];
}
}

View File

@ -0,0 +1,105 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Tests;
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;
abstract class TransportFactoryTestCase extends TestCase
{
protected const USER = 'u$er';
protected const PASSWORD = 'pa$s';
protected $dispatcher;
protected $client;
protected $logger;
abstract public function getFactory(): TransportFactoryInterface;
abstract public function supportsProvider(): iterable;
abstract public function createProvider(): iterable;
public function unsupportedSchemeProvider(): iterable
{
return [];
}
public function incompleteDsnProvider(): iterable
{
return [];
}
/**
* @dataProvider supportsProvider
*/
public function testSupports(Dsn $dsn, bool $supports): void
{
$factory = $this->getFactory();
$this->assertSame($supports, $factory->supports($dsn));
}
/**
* @dataProvider createProvider
*/
public function testCreate(Dsn $dsn, TransportInterface $transport): void
{
$factory = $this->getFactory();
$this->assertEquals($transport, $factory->create($dsn));
}
/**
* @dataProvider unsupportedSchemeProvider
*/
public function testUnsupportedSchemeException(Dsn $dsn): void
{
$factory = $this->getFactory();
$this->expectException(UnsupportedSchemeException::class);
$factory->create($dsn);
}
/**
* @dataProvider incompleteDsnProvider
*/
public function testIncompleteDsnException(Dsn $dsn): void
{
$factory = $this->getFactory();
$this->expectException(IncompleteDsnException::class);
$factory->create($dsn);
}
protected function getDispatcher(): EventDispatcherInterface
{
return $this->dispatcher ?? $this->dispatcher = $this->createMock(EventDispatcherInterface::class);
}
protected function getClient(): HttpClientInterface
{
return $this->client ?? $this->client = $this->createMock(HttpClientInterface::class);
}
protected function getLogger(): LoggerInterface
{
return $this->logger ?? $this->logger = $this->createMock(LoggerInterface::class);
}
}

View File

@ -12,345 +12,71 @@
namespace Symfony\Component\Mailer\Tests;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Bridge\Amazon;
use Symfony\Component\Mailer\Bridge\Google;
use Symfony\Component\Mailer\Bridge\Mailchimp;
use Symfony\Component\Mailer\Bridge\Mailgun;
use Symfony\Component\Mailer\Bridge\Postmark;
use Symfony\Component\Mailer\Bridge\Sendgrid;
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
use Symfony\Component\Mailer\Exception\LogicException;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\SmtpEnvelope;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Email;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
use Symfony\Component\Mime\RawMessage;
class TransportTest extends TestCase
{
public function testFromDsnNull()
/**
* @dataProvider fromStringProvider
*/
public function testFromString(string $dsn, TransportInterface $transport): void
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://null', $dispatcher, null, $logger);
$this->assertInstanceOf(Transport\NullTransport::class, $transport);
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher');
$p->setAccessible(true);
$this->assertSame($dispatcher, $p->getValue($transport));
$transportFactory = new Transport([new DummyTransportFactory()]);
$this->assertEquals($transport, $transportFactory->fromString($dsn));
}
public function testFromDsnSendmail()
public function fromStringProvider(): iterable
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://sendmail', $dispatcher, null, $logger);
$this->assertInstanceOf(Transport\SendmailTransport::class, $transport);
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher');
$p->setAccessible(true);
$this->assertSame($dispatcher, $p->getValue($transport));
}
$transportA = new DummyTransport('a');
$transportB = new DummyTransport('b');
public function testFromDsnSmtp()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://localhost:44?auth_mode=plain&encryption=tls', $dispatcher, null, $logger);
$this->assertInstanceOf(Transport\Smtp\SmtpTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger);
$this->assertEquals('localhost', $transport->getStream()->getHost());
$this->assertEquals('plain', $transport->getAuthMode());
$this->assertTrue($transport->getStream()->isTLS());
$this->assertEquals(44, $transport->getStream()->getPort());
}
yield 'simple transport' => [
'dummy://a',
$transportA,
];
public function testFromInvalidDsn()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The "some://" mailer DSN is invalid.');
Transport::fromDsn('some://');
}
yield 'failover transport' => [
'dummy://a || dummy://b',
new Transport\FailoverTransport([$transportA, $transportB]),
];
public function testNoScheme()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The "//sendmail" mailer DSN must contain a transport scheme.');
Transport::fromDsn('//sendmail');
}
public function testFromInvalidDsnNoHost()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The "file:///some/path" mailer DSN must contain a mailer name.');
Transport::fromDsn('file:///some/path');
}
public function testFromInvalidTransportName()
{
$this->expectException(LogicException::class);
Transport::fromDsn('api://foobar');
}
public function testFromDsnGmail()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@gmail', $dispatcher, null, $logger);
$this->assertInstanceOf(Google\Smtp\GmailTransport::class, $transport);
$this->assertEquals('u$er', $transport->getUsername());
$this->assertEquals('pa$s', $transport->getPassword());
$this->assertProperties($transport, $dispatcher, $logger);
$this->expectException(LogicException::class);
Transport::fromDsn('http://gmail');
}
public function testFromDsnMailgun()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, null, $logger);
$this->assertInstanceOf(Mailgun\Smtp\MailgunTransport::class, $transport);
$this->assertEquals('u$er', $transport->getUsername());
$this->assertEquals('pa$s', $transport->getPassword());
$this->assertProperties($transport, $dispatcher, $logger);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, null, $logger);
$this->assertEquals('smtp.mailgun.org', $transport->getStream()->getHost());
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=eu', $dispatcher, null, $logger);
$this->assertEquals('smtp.eu.mailgun.org', $transport->getStream()->getHost());
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, null, $logger);
$this->assertEquals('smtp.mailgun.org', $transport->getStream()->getHost());
$client = $this->createMock(HttpClientInterface::class);
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
$this->assertInstanceOf(Mailgun\Http\MailgunTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'key' => 'u$er',
'domain' => 'pa$s',
'client' => $client,
]);
$response = $this->createMock(ResponseInterface::class);
$response->expects($this->any())->method('getStatusCode')->willReturn(200);
$message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->text('Hello you');
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages.mime')->willReturn($response);
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
$transport->send($message);
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.eu.mailgun.net/v3/pa%24s/messages.mime')->willReturn($response);
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=eu', $dispatcher, $client, $logger);
$transport->send($message);
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages.mime')->willReturn($response);
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
$transport->send($message);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
$this->assertInstanceOf(Mailgun\Http\Api\MailgunTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'key' => 'u$er',
'domain' => 'pa$s',
'client' => $client,
]);
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger);
$transport->send($message);
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.eu.mailgun.net/v3/pa%24s/messages')->willReturn($response);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=eu', $dispatcher, $client, $logger);
$transport->send($message);
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
$transport->send($message);
$message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->html('test');
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
$transport->send($message);
$stream = fopen('data://text/plain,'.$message->getTextBody(), 'r');
$message = (new Email())->from('me@me.com')->to('you@you.com')->subject('hello')->html($stream);
$client = $this->createMock(HttpClientInterface::class);
$client->expects($this->once())->method('request')->with('POST', 'https://api.mailgun.net/v3/pa%24s/messages')->willReturn($response);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun?region=us', $dispatcher, $client, $logger);
$transport->send($message);
$this->expectException(LogicException::class);
Transport::fromDsn('foo://mailgun');
}
public function testFromDsnPostmark()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').'@postmark', $dispatcher, null, $logger);
$this->assertInstanceOf(Postmark\Smtp\PostmarkTransport::class, $transport);
$this->assertEquals('u$er', $transport->getUsername());
$this->assertEquals('u$er', $transport->getPassword());
$this->assertProperties($transport, $dispatcher, $logger);
$client = $this->createMock(HttpClientInterface::class);
$transport = Transport::fromDsn('api://'.urlencode('u$er').'@postmark', $dispatcher, $client, $logger);
$this->assertInstanceOf(Postmark\Http\Api\PostmarkTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'key' => 'u$er',
'client' => $client,
]);
$this->expectException(LogicException::class);
Transport::fromDsn('http://postmark');
}
public function testFromDsnSendgrid()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').'@sendgrid', $dispatcher, null, $logger);
$this->assertInstanceOf(Sendgrid\Smtp\SendgridTransport::class, $transport);
$this->assertEquals('apikey', $transport->getUsername());
$this->assertEquals('u$er', $transport->getPassword());
$this->assertProperties($transport, $dispatcher, $logger);
$client = $this->createMock(HttpClientInterface::class);
$transport = Transport::fromDsn('api://'.urlencode('u$er').'@sendgrid', $dispatcher, $client, $logger);
$this->assertInstanceOf(Sendgrid\Http\Api\SendgridTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'key' => 'u$er',
'client' => $client,
]);
$this->expectException(LogicException::class);
Transport::fromDsn('http://sendgrid');
}
public function testFromDsnAmazonSes()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, null, $logger);
$this->assertInstanceOf(Amazon\Smtp\SesTransport::class, $transport);
$this->assertEquals('u$er', $transport->getUsername());
$this->assertEquals('pa$s', $transport->getPassword());
$this->assertContains('.sun.', $transport->getStream()->getHost());
$this->assertProperties($transport, $dispatcher, $logger);
$client = $this->createMock(HttpClientInterface::class);
$transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, $client, $logger);
$this->assertInstanceOf(Amazon\Http\SesTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'accessKey' => 'u$er',
'secretKey' => 'pa$s',
'region' => 'sun',
'client' => $client,
]);
$transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, $client, $logger);
$this->assertInstanceOf(Amazon\Http\Api\SesTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'accessKey' => 'u$er',
'secretKey' => 'pa$s',
'region' => 'sun',
'client' => $client,
]);
$this->expectException(LogicException::class);
Transport::fromDsn('foo://ses');
}
public function testFromDsnMailchimp()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mandrill', $dispatcher, null, $logger);
$this->assertInstanceOf(Mailchimp\Smtp\MandrillTransport::class, $transport);
$this->assertEquals('u$er', $transport->getUsername());
$this->assertEquals('pa$s', $transport->getPassword());
$this->assertProperties($transport, $dispatcher, $logger);
$client = $this->createMock(HttpClientInterface::class);
$transport = Transport::fromDsn('http://'.urlencode('u$er').'@mandrill', $dispatcher, $client, $logger);
$this->assertInstanceOf(Mailchimp\Http\MandrillTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'key' => 'u$er',
'client' => $client,
]);
$transport = Transport::fromDsn('api://'.urlencode('u$er').'@mandrill', $dispatcher, $client, $logger);
$this->assertInstanceOf(Mailchimp\Http\Api\MandrillTransport::class, $transport);
$this->assertProperties($transport, $dispatcher, $logger, [
'key' => 'u$er',
'client' => $client,
]);
$this->expectException(LogicException::class);
Transport::fromDsn('foo://mandrill');
}
public function testFromDsnFailover()
{
$user = 'user';
$pass = 'pass';
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://example.com || smtp://'.urlencode($user).'@example.com || smtp://'.urlencode($user).':'.urlencode($pass).'@example.com', $dispatcher, null, $logger);
$this->assertInstanceOf(Transport\FailoverTransport::class, $transport);
$p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports');
$p->setAccessible(true);
$transports = $p->getValue($transport);
$this->assertCount(3, $transports);
foreach ($transports as $transport) {
$this->assertProperties($transport, $dispatcher, $logger);
}
$this->assertSame('', $transports[0]->getUsername());
$this->assertSame('', $transports[0]->getPassword());
$this->assertSame($user, $transports[1]->getUsername());
$this->assertSame('', $transports[1]->getPassword());
$this->assertSame($user, $transports[2]->getUsername());
$this->assertSame($pass, $transports[2]->getPassword());
}
public function testFromDsnRoundRobin()
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$logger = $this->createMock(LoggerInterface::class);
$transport = Transport::fromDsn('smtp://null && smtp://null && smtp://null', $dispatcher, null, $logger);
$this->assertInstanceOf(Transport\RoundRobinTransport::class, $transport);
$p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports');
$p->setAccessible(true);
$transports = $p->getValue($transport);
$this->assertCount(3, $transports);
foreach ($transports as $transport) {
$this->assertProperties($transport, $dispatcher, $logger);
}
}
private function assertProperties(Transport\TransportInterface $transport, EventDispatcherInterface $dispatcher, LoggerInterface $logger, array $props = [])
{
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher');
$p->setAccessible(true);
$this->assertSame($dispatcher, $p->getValue($transport));
$p = new \ReflectionProperty(Transport\AbstractTransport::class, 'logger');
$p->setAccessible(true);
$this->assertSame($logger, $p->getValue($transport));
foreach ($props as $prop => $value) {
$p = new \ReflectionProperty($transport, $prop);
$p->setAccessible(true);
$this->assertEquals($value, $p->getValue($transport));
}
yield 'round robin transport' => [
'dummy://a && dummy://b',
new Transport\RoundRobinTransport([$transportA, $transportB]),
];
}
}
class DummyTransport implements Transport\TransportInterface
{
private $host;
public function __construct(string $host)
{
$this->host = $host;
}
public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage
{
throw new \BadMethodCallException('This method newer should be called.');
}
}
class DummyTransportFactory implements Transport\TransportFactoryInterface
{
public function create(Dsn $dsn): TransportInterface
{
return new DummyTransport($dsn->getHost());
}
public function supports(Dsn $dsn): bool
{
return 'dummy' === $dsn->getScheme();
}
}

View File

@ -12,181 +12,107 @@
namespace Symfony\Component\Mailer;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Bridge\Amazon;
use Symfony\Component\Mailer\Bridge\Google;
use Symfony\Component\Mailer\Bridge\Mailchimp;
use Symfony\Component\Mailer\Bridge\Mailgun;
use Symfony\Component\Mailer\Bridge\Postmark;
use Symfony\Component\Mailer\Bridge\Sendgrid;
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
use Symfony\Component\Mailer\Exception\LogicException;
use Symfony\Component\Mailer\Bridge\Amazon\Factory\SesTransportFactory;
use Symfony\Component\Mailer\Bridge\Google\Factory\GmailTransportFactory;
use Symfony\Component\Mailer\Bridge\Mailchimp\Factory\MandrillTransportFactory;
use Symfony\Component\Mailer\Bridge\Mailgun\Factory\MailgunTransportFactory;
use Symfony\Component\Mailer\Bridge\Postmark\Factory\PostmarkTransportFactory;
use Symfony\Component\Mailer\Bridge\Sendgrid\Factory\SendgridTransportFactory;
use Symfony\Component\Mailer\Exception\UnsupportedHostException;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\NullTransportFactory;
use Symfony\Component\Mailer\Transport\SendmailTransportFactory;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransportFactory;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
use Symfony\Component\Mailer\Transport\TransportInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
class Transport
{
private const FACTORY_CLASSES = [
SesTransportFactory::class,
GmailTransportFactory::class,
MandrillTransportFactory::class,
MailgunTransportFactory::class,
PostmarkTransportFactory::class,
SendgridTransportFactory::class,
];
private $factories;
public static function fromDsn(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
{
// failover?
$factory = new self(self::getDefaultFactories($dispatcher, $client, $logger));
return $factory->fromString($dsn);
}
/**
* @param TransportFactoryInterface[] $factories
*/
public function __construct(iterable $factories)
{
$this->factories = $factories;
}
public function fromString(string $dsn): TransportInterface
{
$dsns = preg_split('/\s++\|\|\s++/', $dsn);
if (\count($dsns) > 1) {
$transports = [];
foreach ($dsns as $dsn) {
$transports[] = self::createTransport($dsn, $dispatcher, $client, $logger);
}
return new Transport\FailoverTransport($transports);
return new Transport\FailoverTransport($this->createFromDsns($dsns));
}
// round robin?
$dsns = preg_split('/\s++&&\s++/', $dsn);
if (\count($dsns) > 1) {
$transports = [];
foreach ($dsns as $dsn) {
$transports[] = self::createTransport($dsn, $dispatcher, $client, $logger);
}
return new Transport\RoundRobinTransport($transports);
return new Transport\RoundRobinTransport($this->createFromDsns($dsns));
}
return self::createTransport($dsn, $dispatcher, $client, $logger);
return $this->fromDsnObject(Dsn::fromString($dsn));
}
private static function createTransport(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface
public function fromDsnObject(Dsn $dsn): TransportInterface
{
if (false === $parsedDsn = parse_url($dsn)) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn));
foreach ($this->factories as $factory) {
if ($factory->supports($dsn)) {
return $factory->create($dsn);
}
}
if (!isset($parsedDsn['scheme'])) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a transport scheme.', $dsn));
throw new UnsupportedHostException($dsn);
}
/**
* @param string[] $dsns
*
* @return TransportInterface[]
*/
private function createFromDsns(array $dsns): array
{
$transports = [];
foreach ($dsns as $dsn) {
$transports[] = $this->fromDsnObject(Dsn::fromString($dsn));
}
if (!isset($parsedDsn['host'])) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a mailer name.', $dsn));
return $transports;
}
private static function getDefaultFactories(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): iterable
{
foreach (self::FACTORY_CLASSES as $factoryClass) {
if (class_exists($factoryClass)) {
yield new $factoryClass($dispatcher, $client, $logger);
}
}
$user = urldecode($parsedDsn['user'] ?? '');
$pass = urldecode($parsedDsn['pass'] ?? '');
parse_str($parsedDsn['query'] ?? '', $query);
yield new NullTransportFactory($dispatcher, $client, $logger);
switch ($parsedDsn['host']) {
case 'null':
if ('smtp' === $parsedDsn['scheme']) {
return new Transport\NullTransport($dispatcher, $logger);
}
yield new SendmailTransportFactory($dispatcher, $client, $logger);
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'sendmail':
if ('smtp' === $parsedDsn['scheme']) {
return new Transport\SendmailTransport(null, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'gmail':
if (!class_exists(Google\Smtp\GmailTransport::class)) {
throw new \LogicException('Unable to send emails via Gmail as the Google bridge is not installed. Try running "composer require symfony/google-mailer".');
}
if ('smtp' === $parsedDsn['scheme']) {
return new Google\Smtp\GmailTransport($user, $pass, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'mailgun':
if (!class_exists(Mailgun\Smtp\MailgunTransport::class)) {
throw new \LogicException('Unable to send emails via Mailgun as the bridge is not installed. Try running "composer require symfony/mailgun-mailer".');
}
if ('smtp' === $parsedDsn['scheme']) {
return new Mailgun\Smtp\MailgunTransport($user, $pass, $query['region'] ?? null, $dispatcher, $logger);
}
if ('http' === $parsedDsn['scheme']) {
return new Mailgun\Http\MailgunTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
}
if ('api' === $parsedDsn['scheme']) {
return new Mailgun\Http\Api\MailgunTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'postmark':
if (!class_exists(Postmark\Smtp\PostmarkTransport::class)) {
throw new \LogicException('Unable to send emails via Postmark as the bridge is not installed. Try running "composer require symfony/postmark-mailer".');
}
if ('smtp' === $parsedDsn['scheme']) {
return new Postmark\Smtp\PostmarkTransport($user, $dispatcher, $logger);
}
if ('api' === $parsedDsn['scheme']) {
return new Postmark\Http\Api\PostmarkTransport($user, $client, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'sendgrid':
if (!class_exists(Sendgrid\Smtp\SendgridTransport::class)) {
throw new \LogicException('Unable to send emails via Sendgrid as the bridge is not installed. Try running "composer require symfony/sendgrid-mailer".');
}
if ('smtp' === $parsedDsn['scheme']) {
return new Sendgrid\Smtp\SendgridTransport($user, $dispatcher, $logger);
}
if ('api' === $parsedDsn['scheme']) {
return new Sendgrid\Http\Api\SendgridTransport($user, $client, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'ses':
if (!class_exists(Amazon\Smtp\SesTransport::class)) {
throw new \LogicException('Unable to send emails via Amazon SES as the bridge is not installed. Try running "composer require symfony/amazon-mailer".');
}
if ('smtp' === $parsedDsn['scheme']) {
return new Amazon\Smtp\SesTransport($user, $pass, $query['region'] ?? null, $dispatcher, $logger);
}
if ('api' === $parsedDsn['scheme']) {
return new Amazon\Http\Api\SesTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
}
if ('http' === $parsedDsn['scheme']) {
return new Amazon\Http\SesTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
case 'mandrill':
if (!class_exists(Mailchimp\Smtp\MandrillTransport::class)) {
throw new \LogicException('Unable to send emails via Mandrill as the bridge is not installed. Try running "composer require symfony/mailchimp-mailer".');
}
if ('smtp' === $parsedDsn['scheme']) {
return new Mailchimp\Smtp\MandrillTransport($user, $pass, $dispatcher, $logger);
}
if ('api' === $parsedDsn['scheme']) {
return new Mailchimp\Http\Api\MandrillTransport($user, $client, $dispatcher, $logger);
}
if ('http' === $parsedDsn['scheme']) {
return new Mailchimp\Http\MandrillTransport($user, $client, $dispatcher, $logger);
}
throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host']));
default:
if ('smtp' === $parsedDsn['scheme']) {
$transport = new Transport\Smtp\EsmtpTransport($parsedDsn['host'], $parsedDsn['port'] ?? 25, $query['encryption'] ?? null, $query['auth_mode'] ?? null, $dispatcher, $logger);
if ($user) {
$transport->setUsername($user);
}
if ($pass) {
$transport->setPassword($pass);
}
return $transport;
}
throw new LogicException(sprintf('The "%s" mailer is not supported.', $parsedDsn['host']));
}
yield new EsmtpTransportFactory($dispatcher, $client, $logger);
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Transport;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Exception\IncompleteDsnException;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
abstract class AbstractTransportFactory implements TransportFactoryInterface
{
protected $dispatcher;
protected $client;
protected $logger;
public function __construct(EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null)
{
$this->dispatcher = $dispatcher;
$this->client = $client;
$this->logger = $logger;
}
protected function getUser(Dsn $dsn): string
{
$user = $dsn->getUser();
if (null === $user) {
throw new IncompleteDsnException('User is not set.');
}
return $user;
}
protected function getPassword(Dsn $dsn): string
{
$password = $dsn->getPassword();
if (null === $password) {
throw new IncompleteDsnException('Password is not set.');
}
return $password;
}
}

View File

@ -0,0 +1,89 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class Dsn
{
private $scheme;
private $host;
private $user;
private $password;
private $port;
private $options;
public function __construct(string $scheme, string $host, ?string $user = null, ?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 static function fromString(string $dsn): self
{
if (false === $parsedDsn = parse_url($dsn)) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn));
}
if (!isset($parsedDsn['scheme'])) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a transport scheme.', $dsn));
}
if (!isset($parsedDsn['host'])) {
throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a mailer name.', $dsn));
}
$user = urldecode($parsedDsn['user'] ?? null);
$password = urldecode($parsedDsn['pass'] ?? null);
$port = $parsedDsn['port'] ?? null;
parse_str($parsedDsn['query'] ?? '', $query);
return new self($parsedDsn['scheme'], $parsedDsn['host'], $user, $password, $port, $query);
}
public function getScheme(): string
{
return $this->scheme;
}
public function getHost(): string
{
return $this->host;
}
public function getUser(): ?string
{
return $this->user;
}
public function getPassword(): ?string
{
return $this->password;
}
public function getPort(int $default = null): ?int
{
return $this->port ?? $default;
}
public function getOption(string $key, $default = null)
{
return $this->options[$key] ?? $default;
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class NullTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
if ('smtp' === $dsn->getScheme()) {
return new NullTransport($this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'null' === $dsn->getHost();
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class SendmailTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
if ('smtp' === $dsn->getScheme()) {
return new SendmailTransport(null, $this->dispatcher, $this->logger);
}
throw new UnsupportedSchemeException($dsn);
}
public function supports(Dsn $dsn): bool
{
return 'sendmail' === $dsn->getHost();
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Transport\Smtp;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
final class EsmtpTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$encryption = $dsn->getOption('encryption');
$authMode = $dsn->getOption('auth_mode');
$port = $dsn->getPort(25);
$host = $dsn->getHost();
$transport = new EsmtpTransport($host, $port, $encryption, $authMode, $this->dispatcher, $this->logger);
if ($user = $dsn->getUser()) {
$transport->setUsername($user);
}
if ($password = $dsn->getPassword()) {
$transport->setPassword($password);
}
return $transport;
}
public function supports(Dsn $dsn): bool
{
return 'smtp' === $dsn->getScheme();
}
}

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Exception\IncompleteDsnException;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
*/
interface TransportFactoryInterface
{
/**
* @throws UnsupportedSchemeException
* @throws IncompleteDsnException
*/
public function create(Dsn $dsn): TransportInterface;
public function supports(Dsn $dsn): bool;
}