Skip to content

Commit fa19a00

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 fa19a00

File tree

5 files changed

+234
-0
lines changed

5 files changed

+234
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkTransportFactory;
8888
use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridTransportFactory;
8989
use Symfony\Component\Mailer\Bridge\Sendinblue\Transport\SendinblueTransportFactory;
90+
use Symfony\Component\Mailer\Command\MailerDebugCommand;
9091
use Symfony\Component\Mailer\Mailer;
9192
use Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsTransportFactory;
9293
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransportFactory;

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

Lines changed: 10 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,14 @@
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
;
301+
302+
if (class_exists(MailerDebugCommand::class)) {
303+
$container->services()
304+
->set('console.command.mailer_debug', MailerDebugCommand::class)
305+
->tag('console.command', ['command' => 'debug:mailer:email:send']);
306+
}
297307
};

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: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
use Symfony\Component\Console\Style\SymfonyStyle;
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+
*
26+
* @author Guillaume MOREL <me@gmorel.io>
27+
*
28+
* @final
29+
*/
30+
class MailerDebugCommand extends Command
31+
{
32+
/** {@inheritdoc} */
33+
protected static $defaultName = 'debug:mailer:email:send';
34+
35+
/** @var MailerInterface */
36+
private $mailer;
37+
38+
/** @var SymfonyStyle */
39+
private $io;
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function __construct(MailerInterface $mailer)
45+
{
46+
parent::__construct();
47+
48+
$this->mailer = $mailer;
49+
}
50+
51+
/**
52+
* {@inheritdoc}
53+
*/
54+
protected function configure()
55+
{
56+
$this->setDescription('Send simple email message')
57+
->setDefinition([
58+
new InputOption('from', null, InputOption::VALUE_REQUIRED, 'The from email of the message'),
59+
new InputOption('to', null, InputOption::VALUE_REQUIRED, 'The to email of the message'),
60+
new InputOption('subject', null, InputOption::VALUE_REQUIRED, 'The subject of the message'),
61+
new InputOption('body', null, InputOption::VALUE_REQUIRED, 'The body of the message'),
62+
])
63+
->setHelp(
64+
<<<EOF
65+
The <info>%command.name%</info> command creates and sends a simple email message.
66+
Usage:
67+
- <info>php %command.full_name%</info> will trigger the interactive mode
68+
- <info>php %command.full_name% --from=a@symfony.com --to=b@symfony.com --subject=Test --body=body</info>
69+
EOF
70+
);
71+
}
72+
73+
/**
74+
* {@inheritdoc}
75+
*/
76+
protected function initialize(InputInterface $input, OutputInterface $output)
77+
{
78+
$this->io = new SymfonyStyle($input, $output);
79+
}
80+
81+
/**
82+
* {@inheritdoc}
83+
*
84+
* @throws TransportExceptionInterface
85+
*/
86+
protected function execute(InputInterface $input, OutputInterface $output): int
87+
{
88+
$email = $this->createEmail($input);
89+
90+
try {
91+
$this->mailer->send($email);
92+
} catch (TransportExceptionInterface $e) {
93+
$this->io->error('Fail to send email.');
94+
throw $e;
95+
}
96+
97+
$this->io->success(
98+
sprintf(
99+
'Email was successfully sent to "%s".',
100+
(string) $input->getOption('to')
101+
)
102+
);
103+
104+
return Command::SUCCESS;
105+
}
106+
107+
/**
108+
* {@inheritdoc}
109+
*/
110+
protected function interact(InputInterface $input, OutputInterface $output)
111+
{
112+
foreach ($input->getOptions() as $option => $value) {
113+
if (null === $value) {
114+
$input->setOption($option, $this->io->ask(sprintf('%s', ucfirst($option))));
115+
}
116+
}
117+
}
118+
119+
private function createEmail(InputInterface $input): Email
120+
{
121+
return (new Email())
122+
->from($input->getOption('from'))
123+
->to($input->getOption('to'))
124+
->priority(Email::PRIORITY_HIGH)
125+
->subject($input->getOption('subject'))
126+
->text($input->getOption('body'))
127+
->html($input->getOption('body'));
128+
}
129+
}
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)