Skip to content

Commit e34cca3

Browse files
committed
[Mailer] introduce debug command
Aim is to allow to test if your mailer configuration or supplier is operational in production Usage - console debug:mailer:email:send --from=a@symfony.com --to=b@symfony.com --subject=Test --body=body - console debug:mailer:email:send
1 parent 49eafee commit e34cca3

File tree

5 files changed

+230
-0
lines changed

5 files changed

+230
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
use Symfony\Contracts\Service\ResetInterface;
165165
use Symfony\Contracts\Service\ServiceSubscriberInterface;
166166
use Symfony\Contracts\Translation\LocaleAwareInterface;
167+
use Symfony\Component\Mailer\Command\MailerDebugCommand;
167168

168169
/**
169170
* FrameworkExtension.
@@ -215,6 +216,10 @@ public function load(array $configs, ContainerBuilder $container)
215216
if (!class_exists(BaseYamlLintCommand::class)) {
216217
$container->removeDefinition('console.command.yaml_lint');
217218
}
219+
220+
if (!class_exists(MailerDebugCommand::class)) {
221+
$container->removeDefinition('console.command.mailer_debug');
222+
}
218223
}
219224

220225
// Load Cache configuration first as it is used by other components

src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand;
4040
use Symfony\Bundle\FrameworkBundle\EventListener\SuggestMissingPackageSubscriber;
4141
use Symfony\Component\Console\EventListener\ErrorListener;
42+
use Symfony\Component\Mailer\Command\MailerDebugCommand;
4243
use Symfony\Component\Messenger\Command\ConsumeMessagesCommand;
4344
use Symfony\Component\Messenger\Command\DebugCommand;
4445
use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand;
@@ -293,5 +294,8 @@
293294
service('secrets.local_vault'),
294295
])
295296
->tag('console.command', ['command' => 'secrets:encrypt-from-local'])
297+
298+
->set('console.command.mailer_debug', MailerDebugCommand::class)
299+
->tag('console.command', ['command' => 'debug:mailer:email:send'])
296300
;
297301
};

src/Symfony/Component/Mailer/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.3.0
5+
-----
6+
7+
* added `console debug:mailer:email:send` command to check if your mailer configuration or supplier is (still) operational in production
8+
49
5.2.0
510
-----
611

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Command;
13+
14+
use Symfony\Component\Console\Style\SymfonyStyle;
15+
use Symfony\Component\Console\Command\Command;
16+
use Symfony\Component\Console\Input\InputInterface;
17+
use Symfony\Component\Console\Input\InputOption;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
20+
use Symfony\Component\Mailer\MailerInterface;
21+
use Symfony\Component\Mime\Email;
22+
23+
/**
24+
* Helps making sure your mailer provider is operational
25+
* @author Guillaume MOREL <me@gmorel.io>
26+
*
27+
* @final
28+
*/
29+
class MailerDebugCommand extends Command
30+
{
31+
/** {@inheritdoc} */
32+
protected static $defaultName = 'debug:mailer:email:send';
33+
34+
/** @var MailerInterface */
35+
private $mailer;
36+
37+
/** @var SymfonyStyle */
38+
private $io;
39+
40+
/**
41+
* {@inheritdoc}
42+
*/
43+
public function __construct(MailerInterface $mailer)
44+
{
45+
parent::__construct();
46+
47+
$this->mailer = $mailer;
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
protected function configure()
54+
{
55+
$this->setDescription('Send simple email message')
56+
->setDefinition([
57+
new InputOption('from', null, InputOption::VALUE_REQUIRED, 'The from email of the message'),
58+
new InputOption('to', null, InputOption::VALUE_REQUIRED, 'The to email of the message'),
59+
new InputOption('subject', null, InputOption::VALUE_REQUIRED, 'The subject of the message'),
60+
new InputOption('body', null, InputOption::VALUE_REQUIRED, 'The body of the message'),
61+
])
62+
->setHelp(
63+
<<<EOF
64+
The <info>%command.name%</info> command creates and sends a simple email message.
65+
Usage:
66+
- <info>php %command.full_name%</info> will trigger the interactive mode
67+
- <info>php %command.full_name% --from=a@symfony.com --to=b@symfony.com --subject=Test --body=body</info>
68+
EOF
69+
);
70+
}
71+
72+
/**
73+
* {@inheritdoc}
74+
*/
75+
protected function initialize(InputInterface $input, OutputInterface $output)
76+
{
77+
$this->io = new SymfonyStyle($input, $output);
78+
}
79+
80+
/**
81+
* {@inheritdoc}
82+
* @throws TransportExceptionInterface
83+
*/
84+
protected function execute(InputInterface $input, OutputInterface $output): int
85+
{
86+
$email = $this->createEmail($input);
87+
88+
try {
89+
$this->mailer->send($email);
90+
} catch (TransportExceptionInterface $e) {
91+
$this->io->error('Fail to send email.');
92+
throw $e;
93+
}
94+
95+
$this->io->success(
96+
sprintf(
97+
'Email was successfully sent to "%s".',
98+
(string) $input->getOption('to')
99+
)
100+
);
101+
102+
return Command::SUCCESS;
103+
}
104+
105+
/**
106+
* {@inheritdoc}
107+
*/
108+
protected function interact(InputInterface $input, OutputInterface $output)
109+
{
110+
foreach ($input->getOptions() as $option => $value) {
111+
if (null === $value) {
112+
$input->setOption($option, $this->io->ask(sprintf('%s', ucfirst($option))));
113+
}
114+
}
115+
}
116+
117+
private function createEmail(InputInterface $input): Email
118+
{
119+
return (new Email())
120+
->from($input->getOption('from'))
121+
->to($input->getOption('to'))
122+
->priority(Email::PRIORITY_HIGH)
123+
->subject($input->getOption('subject'))
124+
->text($input->getOption('body'))
125+
->html($input->getOption('body'));
126+
}
127+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Tests\Command;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Console\Application;
16+
use Symfony\Component\Console\Tester\CommandTester;
17+
use Symfony\Component\Mailer\Command\MailerDebugCommand;
18+
use Symfony\Component\Mailer\MailerInterface;
19+
use Symfony\Component\Mime\Email;
20+
21+
class MailerDebugCommandTest extends TestCase
22+
{
23+
public function testSendMail()
24+
{
25+
$expectedMail = $this->createExpectedMail();
26+
27+
$mailer = $this->createMock(MailerInterface::class);
28+
$mailer->expects($this->once())->method('send')->with($expectedMail);
29+
30+
$command = new MailerDebugCommand($mailer);
31+
32+
$application = new Application();
33+
$application->add($command);
34+
$tester = new CommandTester($application->get('debug:mailer:email:send'));
35+
$tester->execute([
36+
'--from' => 'a@symfony.com',
37+
'--to' => 'b@symfony.com',
38+
'--subject' => 'Test',
39+
'--body' => 'body'
40+
]);
41+
42+
$this->assertSame(0, $tester->getStatusCode());
43+
$this->assertStringContainsString('[OK] Email was successfully sent to "b@symfony.com"', $tester->getDisplay());
44+
}
45+
46+
public function testSendMailInteractive()
47+
{
48+
$expectedMail = $this->createExpectedMail();
49+
50+
$mailer = $this->createMock(MailerInterface::class);
51+
$mailer->expects($this->once())->method('send')->with($expectedMail);
52+
53+
$command = new MailerDebugCommand($mailer);
54+
55+
$application = new Application();
56+
$application->add($command);
57+
$tester = new CommandTester($application->get('debug:mailer:email:send'));
58+
$tester->setInputs([
59+
'a@symfony.com',
60+
'b@symfony.com',
61+
'Test',
62+
'body'
63+
]);
64+
65+
$tester->execute(
66+
[],
67+
['interactive' => true]
68+
);
69+
70+
$this->assertSame(0, $tester->getStatusCode());
71+
$this->assertStringContainsString('[OK] Email was successfully sent to "b@symfony.com"', $tester->getDisplay());
72+
73+
$this->assertStringContainsString("From:\n", $tester->getDisplay());
74+
$this->assertStringContainsString("To:\n", $tester->getDisplay());
75+
$this->assertStringContainsString("Subject:\n", $tester->getDisplay());
76+
$this->assertStringContainsString("Body:\n", $tester->getDisplay());
77+
}
78+
79+
private function createExpectedMail(): Email
80+
{
81+
return (new Email())
82+
->from('a@symfony.com')
83+
->to('b@symfony.com')
84+
->priority(Email::PRIORITY_HIGH)
85+
->subject('Test')
86+
->text('body')
87+
->html('body');
88+
}
89+
}

0 commit comments

Comments
 (0)