diff --git a/README.md b/README.md index ba20d26..670d16b 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,14 @@ return [ 'dot_mail' => [ 'default' => [ //... - 'transport' => Symfony\Component\Mailer\Transport\Smtp\SmtpTransport::class, + 'transport' => 'sendmail', //... ] ] ] ``` -### Mail - SMTP +### Mail - ESMTP If you want your application to send mails on e.g. registration, contact, then edit the file `config/autoload/mail.local.php`. Set the `transport`, `message_options` and `smtp_options` keys like below. @@ -55,7 +55,8 @@ Under `smtp_options` key: - `host` - the mail server's hostname or IP address - `port` - the mail server's port -- `connection_config` - fill in the `username`, `password` and `ssl` keys with the login details of the email used in `from` above +- `connection_config` - fill in the `username` and `password` keys with the login details of the email used in `from` above +- if you want to disable auto_tls set `tls` key to false Note: all other keys can be left as is. @@ -65,7 +66,7 @@ return [ 'dot_mail' => [ 'default' => [ //... - 'transport' => Symfony\Component\Mailer\Transport\Smtp\SmtpTransport::class, + 'transport' => 'esmtp' 'message_options' => [ 'from' => '', //... @@ -76,7 +77,7 @@ return [ 'connection_config' => [ 'username' => '', 'password' => '', - 'ssl' => '', + 'tls' => null, ] ] //... diff --git a/config/mail.global.php.dist b/config/mail.global.php.dist index dcc1a61..9ef3b30 100644 --- a/config/mail.global.php.dist +++ b/config/mail.global.php.dist @@ -3,65 +3,37 @@ declare(strict_types=1); return [ - /** * Dotkernel mail module configuration - * Note that many of these options can be set programmatically too, when sending mail messages - * actually that is what you'll usually do, these config provide just default and options that remain the same for all mails + * Note that many of these options can be set programmatically too, when sending mail messages actually that is + * what you'll usually do, these configs provide just defaults and options that remain the same for all mails */ - 'dot_mail' => [ - //the key is the mail service name, this is the default one, which does not extends any configuration + //the key is the mail service name, this is the default one, which does not extend any configuration 'default' => [ - //tells which other mail service configuration to extend - 'extends' => null, - - /** - * the mail transport to use - * can be any class implementing Symfony\Component\Mailer\Transport\TransportInterface - * - * for standard mail transports, you can use these aliases - * - sendmail => Symfony\Component\Mailer\Transport\SendmailTransport - * - smtp => Symfony\Component\Mailer\Transport\Smtp\SmtpTransport - * - * defaults to sendmail - **/ - - 'transport' => Symfony\Component\Mailer\Transport\SendmailTransport::class, - //message configuration 'message_options' => [ - //from email address of the email 'from' => '', - //from name to be displayed instead of from address 'from_name' => '', - //reply-to email address of the email 'reply_to' => '', - //replyTo name to be displayed instead of the address 'reply_to_name' => '', - //destination email address as string or a list of email addresses 'to' => [], - //copy destination addresses 'cc' => [], - //hidden copy destination addresses 'bcc' => [], - //email subject 'subject' => '', - //body options - content can be plain text, HTML 'body' => [ 'content' => '', 'charset' => 'utf-8', ], - //attachments config 'attachments' => [ 'files' => [], @@ -69,45 +41,40 @@ return [ 'iterate' => false, 'path' => 'data/mail/attachments', 'recursive' => false, - ] + ], ], ], - - //options that will be used only if Symfony\Component\Mailer\Transport\Smtp\SmtpTransport adapter is used + /** + * the mail transport to use can be any class implementing + * Symfony\Component\Mailer\Transport\TransportInterface + * + * for standard mail transports, you can use these aliases: + * - sendmail => Symfony\Component\Mailer\Transport\SendmailTransport + * - esmtp => Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport + * + * defaults to sendmail + **/ + 'transport' => 'sendmail', + //options that will be used only if esmtp adapter is used 'smtp_options' => [ - //hostname or IP address of the mail server 'host' => '', - //port of the mail server - 587 or 465 for secure connections - 'port' => 587, - - //connection class used for authentication - //the value can be one of smtp, plain, login or crammd5 - 'connection_class' => 'login', - + 'port' => 587, 'connection_config' => [ - //the smtp authentication identity 'username' => '', - //the smtp authentication credential 'password' => '', - - //the encryption type to be used, ssl or tls - //null should be used to disable SSL - 'ssl' => 'tls', - ] + //to disable auto_tls set tls key to false + //it's not recommended to disable TLS while connecting to an SMTP server + 'tls' => null, + ], ], ], // option to log the SENT emails 'log' => [ - 'sent' => getcwd() . '/log/mail/sent.log' + 'sent' => getcwd() . '/log/mail/sent.log', ], - - /** - * You can define other mail services here, with the same structure as the default block - * you can even extend from the default block, and overwrite only the differences - */ ], ]; diff --git a/docs/book/v5/configuration.md b/docs/book/v5/configuration.md index 7316366..4c84742 100644 --- a/docs/book/v5/configuration.md +++ b/docs/book/v5/configuration.md @@ -21,9 +21,9 @@ $this->mailService->getMessage()->addTo("receiver@email.com"); ## Transport configuration `dot-mail` uses the `transport` key under the main `dot_mail` configuration key to select the email transport. -It has four email transport classes available by default (`SmtpTransport`), one of which is to be added under the `dot_mail.transport` key for use. +It has two email transport classes available (by default `sendmail`), one of which is to be added under the `dot_mail.transport` key for use. -Sending email with the `Smtp` transport requires valid data for the values under `dot-mail.default.smtp_options`, which is only used in this case. +Sending email with the `esmtp` transport requires valid data for the values under `dot-mail.default.smtp_options`, which is only used in this case. > The configured path must be a writable directory diff --git a/docs/book/v5/transports.md b/docs/book/v5/transports.md index e6301eb..976586f 100644 --- a/docs/book/v5/transports.md +++ b/docs/book/v5/transports.md @@ -2,13 +2,13 @@ `dot-mail` can use any transport class that implements `Symfony\Component\Mailer\Transport\TransportInterface`, with the standard transport available being: -- `Symfony\Component\Mailer\Transport\Smtp\SmtpTransport,` -- `Symfony\Component\Mailer\Transport\SendmailTransport,` +- `esmtp,` +- `sendmail,` > Feel free to use any custom transport you desire, provided it implements the mentioned `TransportInterface`. -PHP's `mail()` function is a wrapper over `Sendmail`, and as such has a different behaviour on Windows than on *nix systems. Using sendmail on Windows **will not work in combination with** `addBcc()`. +PHP's `mail()` function is a wrapper over `sendmail`, and as such has a different behaviour on Windows than on *nix systems. Using sendmail on Windows **will not work in combination with** `addBcc()`. - Note: emails sent using the sendmail transport will be more often delivered to SPAM. -`Smtp` connects to the configured SMTP host in order to handle sending emails. +`esmtp` connects to the configured SMTP host in order to handle sending emails. diff --git a/src/Factory/MailOptionsAbstractFactory.php b/src/Factory/MailOptionsAbstractFactory.php index 856ddbf..0d1fb56 100644 --- a/src/Factory/MailOptionsAbstractFactory.php +++ b/src/Factory/MailOptionsAbstractFactory.php @@ -5,16 +5,12 @@ namespace Dot\Mail\Factory; use Dot\Mail\Options\MailOptions; -use Laminas\Stdlib\ArrayUtils; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; -use function array_key_exists; use function explode; use function is_array; -use function is_string; -use function trim; class MailOptionsAbstractFactory extends AbstractMailFactory { @@ -35,25 +31,6 @@ public function __invoke(ContainerInterface $container, $requestedName, ?array $ $specificConfig = []; } - /** - * Merge any extended mail service config into this one - */ - do { - $extendsConfigKey = isset($specificConfig['extends']) && is_string($specificConfig['extends']) - ? trim($specificConfig['extends']) - : null; - - unset($specificConfig['extends']); - - if ( - $extendsConfigKey !== null - && array_key_exists($extendsConfigKey, $config) - && is_array($config[$extendsConfigKey]) - ) { - $specificConfig = ArrayUtils::merge($config[$extendsConfigKey], $specificConfig); - } - } while ($extendsConfigKey !== null); - return new MailOptions($specificConfig); } } diff --git a/src/Factory/MailServiceAbstractFactory.php b/src/Factory/MailServiceAbstractFactory.php index b3507fd..b03a8d5 100644 --- a/src/Factory/MailServiceAbstractFactory.php +++ b/src/Factory/MailServiceAbstractFactory.php @@ -21,7 +21,7 @@ use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use Symfony\Component\Mailer\Transport; -use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; use Symfony\Component\Mailer\Transport\TransportInterface; use function explode; @@ -177,13 +177,14 @@ protected function createTransport(ContainerInterface $container): TransportInte protected function setupTransportConfig(TransportInterface $transport): TransportInterface { - if ($transport instanceof SmtpTransport) { - $user = $this->mailOptions->getSmtpOptions()->getConnectionConfig()['username']; - $pass = $this->mailOptions->getSmtpOptions()->getConnectionConfig()['password']; - $port = $this->mailOptions->getSmtpOptions()->getPort(); - $host = $this->mailOptions->getSmtpOptions()->getHost(); - - $transport = Transport::fromDsn('smtp://' . $user . ':' . $pass . '@' . $host . ':' . $port); + if ($transport instanceof EsmtpTransport) { + $user = $this->mailOptions->getSmtpOptions()->getConnectionConfig()['username']; + $pass = $this->mailOptions->getSmtpOptions()->getConnectionConfig()['password']; + $tls = $this->mailOptions->getSmtpOptions()->getConnectionConfig()['tls'] === false ? 'false' : null; + $port = $this->mailOptions->getSmtpOptions()->getPort(); + $host = $this->mailOptions->getSmtpOptions()->getHost(); + $transport = Transport::fromDsn('smtp://' . $user . ':' . $pass . '@' . $host . ':' . $port + . '?auto_tls=' . $tls); } return $transport; diff --git a/src/Options/MailOptions.php b/src/Options/MailOptions.php index 4e309a1..10153ce 100644 --- a/src/Options/MailOptions.php +++ b/src/Options/MailOptions.php @@ -6,7 +6,7 @@ use Laminas\Stdlib\AbstractOptions; use Symfony\Component\Mailer\Transport\SendmailTransport; -use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; use Symfony\Component\Mailer\Transport\TransportInterface; use function array_key_exists; @@ -21,10 +21,9 @@ class MailOptions extends AbstractOptions { protected array $eventListeners = []; - protected array $saveSentMessageFolder = []; - protected TransportInterface|string $transport = SmtpTransport::class; + protected TransportInterface|string $transport = EsmtpTransport::class; protected array $transportMap = [ - 'smtp' => [SmtpTransport::class], + 'esmtp' => [EsmtpTransport::class], 'sendmail' => [SendmailTransport::class], ]; protected MessageOptions $messageOptions; @@ -89,14 +88,4 @@ public function setEventListeners(array $eventListeners): void { $this->eventListeners = $eventListeners; } - - public function getSaveSentMessageFolder(): array - { - return $this->saveSentMessageFolder; - } - - public function setSaveSentMessageFolder(array $saveSentMessageFolder): void - { - $this->saveSentMessageFolder = $saveSentMessageFolder; - } } diff --git a/src/Options/SmtpOptions.php b/src/Options/SmtpOptions.php index db491a7..43f430c 100644 --- a/src/Options/SmtpOptions.php +++ b/src/Options/SmtpOptions.php @@ -15,7 +15,6 @@ class SmtpOptions extends AbstractOptions { protected string $name = 'localhost'; - protected string $connectionClass = 'smtp'; protected array $connectionConfig = []; protected string $host = '127.0.0.1'; protected int $port = 25; @@ -36,23 +35,6 @@ public function setName(string $name): static return $this; } - /** - * Get connection class - */ - public function getConnectionClass(): string - { - return $this->connectionClass; - } - - /** - * Set connection class - */ - public function setConnectionClass(string $connectionClass): static - { - $this->connectionClass = $connectionClass; - return $this; - } - /** * Get connection configuration array */ diff --git a/test/CommonTrait.php b/test/CommonTrait.php index 4a21f3b..e42f8f7 100644 --- a/test/CommonTrait.php +++ b/test/CommonTrait.php @@ -6,7 +6,6 @@ use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStreamDirectory; -use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; trait CommonTrait { @@ -46,23 +45,7 @@ private function generateConfig(): array return [ 'dot_mail' => [ 'default' => [ - 'extends' => null, - - /** - * the mail transport to use - * can be any class implementing Symfony\Component\Mailer\Transport\TransportInterface - * - * for standard mail transports, you can use these aliases - * - sendmail => Symfony\Component\Mailer\Transport\SendmailTransport - * - smtp => Symfony\Component\Mailer\Transport\Smtp\SmtpTransport - * - * defaults to sendmail - **/ - 'transport' => SmtpTransport::class, - - // Valid only if the Transport is SMTP - 'save_sent_message_folder' => ['INBOX.Sent'], - 'message_options' => [ + 'message_options' => [ 'from' => '', 'from_name' => '', 'reply_to' => '', @@ -84,35 +67,36 @@ private function generateConfig(): array ], ], ], - - //options that will be used only if Symfony\Component\Mailer\Transport\Smtp\SmtpTransport + /** + * the mail transport to use + * can be any class implementing Symfony\Component\Mailer\Transport\TransportInterface + * + * for standard mail transports, you can use these aliases + * - sendmail => Symfony\Component\Mailer\Transport\SendmailTransport + * - esmtp => Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport + * + * defaults to sendmail + **/ + 'transport' => 'esmtp', + //options that will be used only if Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport // adapter is used 'smtp_options' => [ 'host' => 'testHost', 'port' => 587, - 'connection_class' => 'login', 'connection_config' => [ - //the smtp authentication identity 'username' => 'test', - //the smtp authentication credential 'password' => 'testPassword', - 'ssl' => 'tls', + 'tls' => null, ], ], ], 'test' => 'string test', - // option to log the SENT emails 'log' => [ 'sent' => $this->fileSystem->url() . '/log/mail/sent.log', ], - - /** - * You can define other mail services here, with the same structure as the default block - * you can even extend from the default block, and overwrite only the differences - */ ], ]; } diff --git a/test/Factory/MailServiceAbstractFactoryTest.php b/test/Factory/MailServiceAbstractFactoryTest.php index 13565e8..a926bba 100644 --- a/test/Factory/MailServiceAbstractFactoryTest.php +++ b/test/Factory/MailServiceAbstractFactoryTest.php @@ -23,7 +23,7 @@ use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; -use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; class MailServiceAbstractFactoryTest extends TestCase { @@ -91,7 +91,7 @@ public function testGenerateServiceWithProvidedAdapter(): void ->willReturn($this->messageOptions); $this->mailOptions->expects($this->any()) ->method('getTransport') - ->willReturn($this->createMock(SmtpTransport::class)); + ->willReturn($this->createMock(EsmtpTransport::class)); $this->mailOptions->expects($this->any()) ->method('getEventListeners') ->willReturn([AbstractMailEventListener::class]); @@ -116,7 +116,7 @@ public function testGenerateServiceWithProvidedAdapter(): void ->willReturn([ 'username' => 'test', 'password' => 'testPassword', - 'port' => 587, + 'tls' => null, ]); $this->smtpOptions->expects($this->once()) @@ -129,7 +129,7 @@ public function testGenerateServiceWithProvidedAdapter(): void $mailService = (new Subject())($this->container, $requestedName); $this->assertInstanceOf(MailService::class, $mailService); - $this->assertInstanceOf(SmtpTransport::class, $mailService->getTransport()); + $this->assertInstanceOf(EsmtpTransport::class, $mailService->getTransport()); } /** @@ -159,7 +159,7 @@ public function testGenerateServiceWithoutProvidedAdapter(): void ->willReturn($this->messageOptions); $this->mailOptions->expects($this->any()) ->method('getTransport') - ->willReturn(SmtpTransport::class); + ->willReturn(EsmtpTransport::class); $this->mailOptions->expects($this->any()) ->method('getEventListeners') ->willReturn(['Invalid Listener Test']); @@ -169,13 +169,13 @@ public function testGenerateServiceWithoutProvidedAdapter(): void ->willReturnMap([ ['dot-mail.options.default', $this->mailOptions], [LogServiceInterface::class, $this->createMock(LogService::class)], - [SmtpTransport::class, new SmtpTransport()], + [EsmtpTransport::class, new EsmtpTransport()], ['Invalid Listener Test', 'Invalid Listener provided'], ]); $this->container->expects($this->any()) ->method('has') ->willReturnMap([ - [SmtpTransport::class, true], + [EsmtpTransport::class, true], ['Invalid Listener Test', true], ]); @@ -184,7 +184,7 @@ public function testGenerateServiceWithoutProvidedAdapter(): void ->willReturn([ 'username' => 'test', 'password' => 'testPassword', - 'port' => 587, + 'tls' => false, ]); $this->smtpOptions->expects($this->once()) @@ -200,7 +200,7 @@ public function testGenerateServiceWithoutProvidedAdapter(): void $mailService = (new Subject())($this->container, $requestedName); $this->assertInstanceOf(MailService::class, $mailService); - $this->assertInstanceOf(SmtpTransport::class, $mailService->getTransport()); + $this->assertInstanceOf(EsmtpTransport::class, $mailService->getTransport()); $this->assertCount(2, $mailService->getAttachments()); } @@ -247,7 +247,7 @@ public function testGenerateServiceThrowException(): void ->willReturnMap([ ['dot-mail.options.default', $this->mailOptions], [LogServiceInterface::class, $this->createMock(LogService::class)], - [SmtpTransport::class, new SmtpTransport()], + [EsmtpTransport::class, new EsmtpTransport()], ['Invalid Listener Test', 'Invalid Listener provided'], ]); $this->container->expects($this->any()) diff --git a/test/Options/MailOptionsTest.php b/test/Options/MailOptionsTest.php index d20dd3b..5e78703 100644 --- a/test/Options/MailOptionsTest.php +++ b/test/Options/MailOptionsTest.php @@ -9,7 +9,7 @@ use Dot\Mail\Options\MessageOptions; use Dot\Mail\Options\SmtpOptions; use PHPUnit\Framework\TestCase; -use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; class MailOptionsTest extends TestCase { @@ -17,25 +17,22 @@ public function testGettersAndSetters(): void { $subject = new MailOptions(); - $transport = 'smtp'; - $transportMap = ['test' => 'array']; - $messageOptions = ['from' => '', 'to' => []]; - $smtpOptions = ['host' => '', 'port' => 587]; - $eventListeners = [AbstractMailEventListener::class]; - $saveSentMessageFolder = ['INBOX.Sent']; + $transport = 'esmtp'; + $transportMap = ['test' => 'array']; + $messageOptions = ['from' => '', 'to' => []]; + $smtpOptions = ['host' => '', 'port' => 587]; + $eventListeners = [AbstractMailEventListener::class]; $subject->setTransport($transport); $subject->setTransportMap($transportMap); $subject->setMessageOptions($messageOptions); $subject->setSmtpOptions($smtpOptions); $subject->setEventListeners($eventListeners); - $subject->setSaveSentMessageFolder($saveSentMessageFolder); - $this->assertSame(SmtpTransport::class, $subject->getTransport()); + $this->assertSame(EsmtpTransport::class, $subject->getTransport()); $this->assertSame($transportMap, $subject->getTransportMap()); $this->assertInstanceOf(MessageOptions::class, $subject->getMessageOptions()); $this->assertInstanceOf(SmtpOptions::class, $subject->getSmtpOptions()); $this->assertSame($eventListeners, $subject->getEventListeners()); - $this->assertSame($saveSentMessageFolder, $subject->getSaveSentMessageFolder()); } } diff --git a/test/Options/SmtpOptionsTest.php b/test/Options/SmtpOptionsTest.php index 3b5bd54..22f7619 100644 --- a/test/Options/SmtpOptionsTest.php +++ b/test/Options/SmtpOptionsTest.php @@ -23,7 +23,6 @@ public function testSmtpGettersAndSetters(): void $this->assertIsString($subject->getName()); $this->assertIsArray($subject->getConnectionConfig()); $this->assertIsString($subject->getHost()); - $this->assertIsString($subject->getConnectionClass()); $this->assertIsInt($subject->getPort()); $this->assertIsInt($subject->getConnectionTimeLimit()); diff --git a/test/Service/MailServiceTest.php b/test/Service/MailServiceTest.php index 02bae60..b87c78a 100644 --- a/test/Service/MailServiceTest.php +++ b/test/Service/MailServiceTest.php @@ -17,7 +17,7 @@ use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; use Symfony\Component\Mailer\Transport\TransportInterface; use Symfony\Component\Mime\Part\TextPart; @@ -68,7 +68,7 @@ public function setUp(): void public function testGettersAndSetters(): void { $attachments = ['/testAttachment.pdf', '/testDirectory/testAttachment2.xls']; - $transport = $this->createMock(SmtpTransport::class); + $transport = $this->createMock(EsmtpTransport::class); $this->mailService->setAttachments($attachments); $this->mailService->setTransport($transport);