diff --git a/app/AppKernel.php b/app/AppKernel.php index a7b4f9b80..812f778fa 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -13,7 +13,6 @@ class AppKernel extends Kernel new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), new Symfony\Bundle\MonologBundle\MonologBundle(), - new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new FOS\RestBundle\FOSRestBundle(), diff --git a/app/config/config.yml b/app/config/config.yml index 68dc00e29..f2bbb9b47 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -34,6 +34,8 @@ framework: fragments: ~ http_method_override: true assets: ~ + mailer: + dsn: "%mailer_dsn%" # Twig Configuration twig: @@ -78,18 +80,6 @@ doctrine_migrations: table_name: migration_versions name: Application Migrations -# Swiftmailer Configuration -swiftmailer: - transport: "%mailer_transport%" - username: "%mailer_user%" - password: "%mailer_password%" - host: "%mailer_host%" - port: "%mailer_port%" - encryption: "%mailer_encryption%" - auth_mode: "%mailer_auth_mode%" - spool: - type: memory - fos_rest: param_fetcher_listener: true body_listener: true @@ -183,7 +173,7 @@ fos_user: address: "%from_email%" sender_name: wallabag service: - mailer: fos_user.mailer.twig_swift + mailer: Wallabag\UserBundle\Mailer\UserMailer fos_oauth_server: db_driver: orm diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml index fa6e14e73..2e41c7606 100644 --- a/app/config/config_dev.yml +++ b/app/config/config_dev.yml @@ -8,6 +8,10 @@ framework: profiler: only_exceptions: false + mailer: + # see https://mailcatcher.me/ + dsn: smtp://127.0.0.1:1025 + web_profiler: toolbar: true intercept_redirects: false @@ -35,12 +39,6 @@ monolog: VERBOSITY_DEBUG: DEBUG channels: [doctrine] -swiftmailer: - # see https://mailcatcher.me/ - transport: smtp - host: 'localhost' - port: 1025 - # If you want to use cache for queries used in WallabagExtension # Uncomment the following lines #doctrine: diff --git a/app/config/config_test.yml b/app/config/config_test.yml index 216f84316..d738a49d6 100644 --- a/app/config/config_test.yml +++ b/app/config/config_test.yml @@ -11,16 +11,13 @@ framework: collect: false translator: enabled: false + mailer: + dsn: 'null://null' web_profiler: toolbar: false intercept_redirects: false -swiftmailer: - # to be able to read emails sent - spool: - type: file - doctrine: dbal: driver: "%test_database_driver%" diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index dcaf4dffb..a3019308e 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -26,13 +26,7 @@ parameters: domain_name: https://your-wallabag-url-instance.com server_name: "Your wallabag instance" - mailer_transport: smtp - mailer_user: ~ - mailer_password: ~ - mailer_host: 127.0.0.1 - mailer_port: false - mailer_encryption: ~ - mailer_auth_mode: ~ + mailer_dsn: smtp://127.0.0.1 locale: en diff --git a/app/config/services.yml b/app/config/services.yml index a3f5bd7eb..b7a3b658a 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -200,6 +200,16 @@ services: wallabag_core.entry.download_images.client: alias: 'httplug.client.wallabag_core.entry.download_images' + Wallabag\UserBundle\Mailer\UserMailer: + arguments: + $parameters: + template: + confirmation: '%fos_user.registration.confirmation.template%' + resetting: '%fos_user.resetting.email.template%' + from_email: + confirmation: '%fos_user.registration.confirmation.from_email%' + resetting: '%fos_user.resetting.email.from_email%' + Wallabag\UserBundle\EventListener\CreateConfigListener: arguments: $itemsOnPage: "%wallabag_core.items_on_page%" diff --git a/composer.json b/composer.json index b1976a802..f9fdb0146 100644 --- a/composer.json +++ b/composer.json @@ -65,6 +65,7 @@ "doctrine/migrations": "^1.8", "doctrine/orm": "^2.6", "doctrine/persistence": "^1.3", + "egulias/email-validator": "^3.2", "enshrined/svg-sanitize": "^0.15.4", "friendsofsymfony/jsrouting-bundle": "^2.2", "friendsofsymfony/oauth-server-bundle": "^1.5", @@ -112,10 +113,9 @@ "sensio/framework-extra-bundle": "^6.2", "sentry/sentry-symfony": "3.5.3", "stof/doctrine-extensions-bundle": "^1.2", - "swiftmailer/swiftmailer": "^6.3", "symfony/dom-crawler": "^4.0", + "symfony/mailer": "^4.0", "symfony/monolog-bundle": "^3.1", - "symfony/swiftmailer-bundle": "^3.2", "symfony/symfony": "^4.0", "tecnickcom/tcpdf": "^6.3.0", "twig/extra-bundle": "^3.4", diff --git a/composer.lock b/composer.lock index 1c48d1533..fc0744004 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7cd556e18e7d5c08e61d78d21acddb09", + "content-hash": "1bdf0355a12843194f046a6ac0b87338", "packages": [ { "name": "babdev/pagerfanta-bundle", @@ -7788,16 +7788,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.15.0", + "version": "1.15.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6ff970a7101acfe99b3048e4bbfbc094e55c5b04" + "reference": "5941477f100993652218928039d530b75a13a9ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ff970a7101acfe99b3048e4bbfbc094e55c5b04", - "reference": "6ff970a7101acfe99b3048e4bbfbc094e55c5b04", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/5941477f100993652218928039d530b75a13a9ca", + "reference": "5941477f100993652218928039d530b75a13a9ca", "shasum": "" }, "require": { @@ -7827,9 +7827,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.15.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.15.2" }, - "time": "2022-12-07T16:12:39+00:00" + "time": "2022-12-16T06:42:48+00:00" }, { "name": "phpzip/phpzip", @@ -9552,82 +9552,6 @@ }, "time": "2022-09-30T11:52:24+00:00" }, - { - "name": "swiftmailer/swiftmailer", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", - "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", - "shasum": "" - }, - "require": { - "egulias/email-validator": "^2.0|^3.1", - "php": ">=7.0.0", - "symfony/polyfill-iconv": "^1.0", - "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^1.0", - "symfony/phpunit-bridge": "^4.4|^5.4" - }, - "suggest": { - "ext-intl": "Needed to support internationalized email addresses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.2-dev" - } - }, - "autoload": { - "files": [ - "lib/swift_required.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Chris Corbyn" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "https://swiftmailer.symfony.com", - "keywords": [ - "email", - "mail", - "mailer" - ], - "support": { - "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", - "type": "tidelift" - } - ], - "abandoned": "symfony/mailer", - "time": "2021-10-18T15:26:12+00:00" - }, { "name": "symfony/contracts", "version": "v1.1.13", @@ -9952,89 +9876,6 @@ ], "time": "2022-11-03T14:55:06+00:00" }, - { - "name": "symfony/polyfill-iconv", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "927013f3aac555983a5059aada98e1907d842695" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/927013f3aac555983a5059aada98e1907d842695", - "reference": "927013f3aac555983a5059aada98e1907d842695", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-iconv": "*" - }, - "suggest": { - "ext-iconv": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Iconv extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "iconv", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.27.0", @@ -10942,87 +10783,6 @@ ], "time": "2022-10-05T15:16:54+00:00" }, - { - "name": "symfony/swiftmailer-bundle", - "version": "v3.5.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/swiftmailer-bundle.git", - "reference": "9daab339f226ac958192bf89836cb3378cc0e652" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/swiftmailer-bundle/zipball/9daab339f226ac958192bf89836cb3378cc0e652", - "reference": "9daab339f226ac958192bf89836cb3378cc0e652", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "swiftmailer/swiftmailer": "^6.1.3", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/http-kernel": "^4.4|^5.0" - }, - "conflict": { - "twig/twig": "<1.41|>=2.0,<2.10" - }, - "require-dev": { - "symfony/console": "^4.4|^5.0", - "symfony/framework-bundle": "^4.4|^5.0", - "symfony/phpunit-bridge": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Bundle\\SwiftmailerBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony SwiftmailerBundle", - "homepage": "http://symfony.com", - "support": { - "issues": "https://github.com/symfony/swiftmailer-bundle/issues", - "source": "https://github.com/symfony/swiftmailer-bundle/tree/v3.5.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "abandoned": "symfony/mailer", - "time": "2022-02-06T08:03:40+00:00" - }, { "name": "symfony/symfony", "version": "v4.4.49", diff --git a/src/Wallabag/CoreBundle/Resources/views/Static/about.html.twig b/src/Wallabag/CoreBundle/Resources/views/Static/about.html.twig index 4b07d7cbf..59bcc7f06 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Static/about.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Static/about.html.twig @@ -140,7 +140,6 @@ smalot/pdfparserGPL-3.0 sonata-project/google-authenticatorMIT stof/doctrine-extensions-bundleMIT - swiftmailer/swiftmailerMIT symfony/assetic-bundleMIT symfony/monolog-bundleMIT All of SymfonyMIT-licenced diff --git a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php index d86302379..7e355effe 100644 --- a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php +++ b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php @@ -4,6 +4,9 @@ namespace Wallabag\UserBundle\Mailer; use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface; use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; use Twig\Environment; /** @@ -13,9 +16,9 @@ use Twig\Environment; class AuthCodeMailer implements AuthCodeMailerInterface { /** - * SwiftMailer. + * Mailer. * - * @var \Swift_Mailer + * @var MailerInterface */ private $mailer; @@ -55,14 +58,12 @@ class AuthCodeMailer implements AuthCodeMailerInterface private $wallabagUrl; /** - * Initialize the auth code mailer with the SwiftMailer object. - * * @param string $senderEmail * @param string $senderName * @param string $supportUrl wallabag support url * @param string $wallabagUrl wallabag instance url */ - public function __construct(\Swift_Mailer $mailer, Environment $twig, $senderEmail, $senderName, $supportUrl, $wallabagUrl) + public function __construct(MailerInterface $mailer, Environment $twig, $senderEmail, $senderName, $supportUrl, $wallabagUrl) { $this->mailer = $mailer; $this->twig = $twig; @@ -92,15 +93,13 @@ class AuthCodeMailer implements AuthCodeMailerInterface 'support_url' => $this->supportUrl, ]); - $message = new \Swift_Message(); - $message - ->setTo($user->getEmailAuthRecipient()) - ->setFrom($this->senderEmail, $this->senderName) - ->setSubject($subject) - ->setBody($bodyText, 'text/plain') - ->addPart($bodyHtml, 'text/html') - ; + $email = (new Email()) + ->from(new Address($this->senderEmail, $this->senderName ?? $this->senderEmail)) + ->to($user->getEmailAuthRecipient()) + ->subject($subject) + ->text($bodyText) + ->html($bodyHtml); - $this->mailer->send($message); + $this->mailer->send($email); } } diff --git a/src/Wallabag/UserBundle/Mailer/UserMailer.php b/src/Wallabag/UserBundle/Mailer/UserMailer.php new file mode 100644 index 000000000..34f13e0c4 --- /dev/null +++ b/src/Wallabag/UserBundle/Mailer/UserMailer.php @@ -0,0 +1,78 @@ +mailer = $mailer; + $this->router = $router; + $this->twig = $twig; + $this->parameters = $parameters; + } + + /** + * @param string $templateName + * @param array $context + * @param array $fromEmail + * @param string $toEmail + */ + protected function sendMessage($templateName, $context, $fromEmail, $toEmail) + { + $template = $this->twig->load($templateName); + $subject = $template->renderBlock('subject', $context); + $textBody = $template->renderBlock('body_text', $context); + + $htmlBody = ''; + + if ($template->hasBlock('body_html', $context)) { + $htmlBody = $template->renderBlock('body_html', $context); + } + + $email = (new Email()) + ->from(new Address(key($fromEmail), current($fromEmail))) + ->to($toEmail) + ->subject($subject); + + if (!empty($htmlBody)) { + $email + ->text($textBody) + ->html($htmlBody); + } else { + $email->text($textBody); + } + + $this->mailer->send($email); + } +} diff --git a/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php b/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php index e1a30749b..983d39a34 100644 --- a/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php +++ b/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php @@ -3,6 +3,8 @@ namespace Tests\Wallabag\UserBundle\Mailer; use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; use Twig\Environment; use Twig\Loader\ArrayLoader; use Wallabag\UserBundle\Entity\User; @@ -10,19 +12,10 @@ use Wallabag\UserBundle\Mailer\AuthCodeMailer; class AuthCodeMailerTest extends TestCase { - protected $mailer; - protected $spool; protected $twig; protected function setUp(): void { - $this->spool = new CountableMemorySpool(); - $transport = new \Swift_Transport_SpoolTransport( - new \Swift_Events_SimpleEventDispatcher(), - $this->spool - ); - $this->mailer = new \Swift_Mailer($transport); - $twigTemplate = <<<'TWIG' {% block subject %}subject{% endblock %} {% block body_html %}html body {{ code }}{% endblock %} @@ -34,6 +27,31 @@ TWIG; public function testSendEmail() { + $mailer = $this->createMock(MailerInterface::class); + $mailer->expects($this->once()) + ->method('send') + ->with($this->callback(function ($email) { + $this->assertSame('subject', $email->getSubject()); + $this->assertSame('text body http://0.0.0.0/support', $email->getTextBody()); + $this->assertSame('html body 666666', $email->getHtmlBody()); + + $this->assertCount(1, $email->getTo()); + /** @var Address[] $addresses */ + $addresses = $email->getTo(); + $this->assertInstanceOf(Address::class, $addresses[0]); + $this->assertSame('', $addresses[0]->getName()); + $this->assertSame('test@wallabag.io', $addresses[0]->getAddress()); + + $this->assertCount(1, $email->getFrom()); + /** @var Address[] $addresses */ + $addresses = $email->getFrom(); + $this->assertInstanceOf(Address::class, $addresses[0]); + $this->assertSame('wallabag test', $addresses[0]->getName()); + $this->assertSame('nobody@test.io', $addresses[0]->getAddress()); + + return true; + })); + $user = new User(); $user->setEmailTwoFactor(true); $user->setEmailAuthCode(666666); @@ -41,7 +59,7 @@ TWIG; $user->setName('Bob'); $authCodeMailer = new AuthCodeMailer( - $this->mailer, + $mailer, $this->twig, 'nobody@test.io', 'wallabag test', @@ -50,14 +68,5 @@ TWIG; ); $authCodeMailer->sendAuthCode($user); - - $this->assertCount(1, $this->spool); - - $msg = $this->spool->getMessages()[0]; - $this->assertArrayHasKey('test@wallabag.io', $msg->getTo()); - $this->assertSame(['nobody@test.io' => 'wallabag test'], $msg->getFrom()); - $this->assertSame('subject', $msg->getSubject()); - $this->assertStringContainsString('text body http://0.0.0.0/support', $msg->toString()); - $this->assertStringContainsString('html body 666666', $msg->toString()); } } diff --git a/tests/Wallabag/UserBundle/Mailer/CountableMemorySpool.php b/tests/Wallabag/UserBundle/Mailer/CountableMemorySpool.php deleted file mode 100644 index 53f240a1d..000000000 --- a/tests/Wallabag/UserBundle/Mailer/CountableMemorySpool.php +++ /dev/null @@ -1,19 +0,0 @@ -messages); - } - - public function getMessages() - { - return $this->messages; - } -}