diff --git a/Classes/Command/FlushQueueCommand.php b/Classes/Command/FlushQueueCommand.php
new file mode 100644
index 0000000..8441cbd
--- /dev/null
+++ b/Classes/Command/FlushQueueCommand.php
@@ -0,0 +1,192 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+namespace CPSIT\Typo3Mailqueue\Command;
+
+use CPSIT\Typo3Mailqueue\Mail;
+use Symfony\Component\Console;
+use TYPO3\CMS\Core;
+
+/**
+ * FlushQueueCommand
+ *
+ * @author Elias Häußler
+ * @license GPL-2.0-or-later
+ */
+final class FlushQueueCommand extends Console\Command\Command
+{
+ private ?Console\Output\OutputInterface $jsonOutput = null;
+ private Console\Style\SymfonyStyle $io;
+
+ public function __construct(
+ private readonly Core\Mail\Mailer $mailer,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this->addOption(
+ 'json',
+ 'j',
+ Console\Input\InputOption::VALUE_NONE,
+ 'Output results in JSON format',
+ );
+ $this->addOption(
+ 'limit',
+ 'l',
+ Console\Input\InputOption::VALUE_REQUIRED,
+ 'Maximum number of mails to send in one iteration',
+ );
+ }
+
+ protected function initialize(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): void
+ {
+ if ($input->getOption('json')) {
+ $this->jsonOutput = $output;
+
+ if ($output instanceof Console\Output\ConsoleOutputInterface) {
+ $output = $output->getErrorOutput();
+ } else {
+ $output = new Console\Output\NullOutput();
+ }
+ }
+
+ $this->io = new Console\Style\SymfonyStyle($input, $output);
+ }
+
+ protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
+ {
+ $limit = $input->getOption('limit');
+ $transport = $this->mailer->getTransport();
+
+ // Early return if unsupported mail transport is configured
+ if (!($transport instanceof Mail\Transport\QueueableTransport)) {
+ $message = sprintf(
+ 'The configured mail transport "%s" is not supported. Please configure a mail spooler as mail transport.',
+ $transport::class,
+ );
+
+ $this->io->error($message);
+ $this->writeJsonResult([
+ 'error' => $message,
+ ]);
+
+ return self::INVALID;
+ }
+
+ $mailQueue = $transport->getMailQueue();
+ $numberOfMailsInQueue = count($mailQueue);
+ $realTransport = $this->mailer->getRealTransport();
+
+ // Early return if mail queue is empty
+ if ($numberOfMailsInQueue === 0) {
+ $message = 'No mails are currently in queue.';
+
+ $this->io->success($message);
+ $this->writeJsonResult([
+ 'result' => $message,
+ ]);
+
+ return self::SUCCESS;
+ }
+
+ // Limit number of sent mails from command option or send all mails
+ if ($limit !== null) {
+ $limit = (int)$limit;
+ } else {
+ $limit = $numberOfMailsInQueue;
+ }
+
+ // Early return if invalid limit is provided
+ if ($limit < 1) {
+ $message = 'Limit must be a number greater than or equal to 1.';
+
+ $this->io->error($message);
+ $this->writeJsonResult([
+ 'error' => $message,
+ ]);
+
+ return self::INVALID;
+ }
+
+ $this->io->section('Flushing mail queue');
+
+ $progressBar = $this->io->createProgressBar($limit);
+
+ // Send mails from queue
+ foreach ($progressBar->iterate($mailQueue, $limit) as $i => $item) {
+ if ($i >= $limit) {
+ $progressBar->finish();
+ break;
+ }
+
+ $transport->dequeue($item, $realTransport);
+
+ --$numberOfMailsInQueue;
+ }
+
+ $this->io->newLine(2);
+
+ if ($numberOfMailsInQueue > 0) {
+ $this->io->success(
+ sprintf(
+ 'Successfully sent %d mail%s, %d mail%s still enqueued.',
+ $limit,
+ $limit === 1 ? '' : 's',
+ $numberOfMailsInQueue,
+ $numberOfMailsInQueue === 1 ? ' is' : 's are',
+ ),
+ );
+ } else {
+ $this->io->success(
+ sprintf(
+ 'Successfully flushed mail queue (sent %d mail%s).',
+ $limit,
+ $limit === 1 ? '' : 's',
+ ),
+ );
+ }
+
+ $this->writeJsonResult([
+ 'sent' => $limit,
+ 'remaining' => $numberOfMailsInQueue,
+ ]);
+
+ return self::SUCCESS;
+ }
+
+ /**
+ * @param array $json
+ */
+ private function writeJsonResult(array $json): void
+ {
+ if ($this->jsonOutput === null) {
+ return;
+ }
+
+ $this->jsonOutput->writeln(
+ json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR),
+ );
+ }
+}
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
index ea7cb99..ddfda2a 100644
--- a/Configuration/Services.yaml
+++ b/Configuration/Services.yaml
@@ -16,6 +16,13 @@ services:
# @todo Replace with #[AsController] attribute once support for TYPO3 v11 is dropped
tags: ['backend.controller']
+ CPSIT\Typo3Mailqueue\Command\FlushQueueCommand:
+ # @todo Replace with #[AsCommand] attribute once support for TYPO3 v11 is dropped
+ tags:
+ - name: console.command
+ command: 'mailqueue:flushqueue'
+ description: 'Flush mail queue by sending mails using the configured real transport'
+
CPSIT\Typo3Mailqueue\Command\ListQueueCommand:
# @todo Replace with #[AsCommand] attribute once support for TYPO3 v11 is dropped
tags:
diff --git a/Documentation/Images/ScreenshotFlushQueueCommand.png b/Documentation/Images/ScreenshotFlushQueueCommand.png
new file mode 100644
index 0000000..3db2535
Binary files /dev/null and b/Documentation/Images/ScreenshotFlushQueueCommand.png differ
diff --git a/Documentation/Images/ScreenshotConsoleCommand.png b/Documentation/Images/ScreenshotListQueueCommand.png
similarity index 100%
rename from Documentation/Images/ScreenshotConsoleCommand.png
rename to Documentation/Images/ScreenshotListQueueCommand.png
diff --git a/README.md b/README.md
index b073dad..23d7d14 100644
--- a/README.md
+++ b/README.md
@@ -27,14 +27,14 @@ An extension for TYPO3 CMS that extends TYPO3's mail spooling functionality
with an extended queueable mail transport interface. In addition, it provides
an improved version of TYPO3's `FileSpooler`. In order to make mails in the
mail queue visible, the extension provides an (admin-only) backend module and
-a console command.
+console commands to list and flush the mail queue.
## 🚀 Features
* Extended interface for queueable mail transports
* Improved queueable file transport with failure metadata
* Backend module to list mails in queue
-* Console command to list mails in queue
+* Console command to list queue and flush mails
* Compatible with TYPO3 11.5 LTS and 12.4 LTS
## 🔥 Installation
@@ -98,9 +98,27 @@ be used to get a quick overview about the health state of the mail queue.
It also allows to dequeue single mails from the mail queue by sending them
with the configured real transport.
-### Console command
+### Console commands
-![Screenshot console command](Documentation/Images/ScreenshotConsoleCommand.png)
+#### Flush queue
+
+![Screenshot "mailqueue:flushqueue" console command](Documentation/Images/ScreenshotFlushQueueCommand.png)
+
+The extension provides a console command to flush the mail queue:
+
+```bash
+typo3 mailqueue:flushqueue [-l|--limit] [-j|--json]
+```
+
+The number of mails to be sent can be limited with `--limit` (or `-l`). If
+no limit is passed, the whole mail queue is flushed.
+
+When using `--json` (or `-j`), user-oriented output is written to stderr and
+result messages are written in JSON format to stdout.
+
+#### List queue
+
+![Screenshot "mailqueue:listqueue" console command](Documentation/Images/ScreenshotListQueueCommand.png)
The extension provides a console command to list enqueued mails:
diff --git a/Tests/Build/console-application.php b/Tests/Build/console-application.php
index 63a325c..06b1cf7 100644
--- a/Tests/Build/console-application.php
+++ b/Tests/Build/console-application.php
@@ -28,14 +28,18 @@
require dirname(__DIR__, 2) . '/.Build/vendor/autoload.php';
-$command = new Command\ListQueueCommand(
- new Core\Mail\Mailer(
- new Mailer\Transport\NullTransport(),
- ),
+$mailer = new Core\Mail\Mailer(
+ new Mailer\Transport\NullTransport(),
);
-$command->setName('mailqueue:listqueue');
+
+$flushCommand = new Command\FlushQueueCommand($mailer);
+$flushCommand->setName('mailqueue:flushqueue');
+
+$listCommand = new Command\ListQueueCommand($mailer);
+$listCommand->setName('mailqueue:listqueue');
$application = new Console\Application();
-$application->add($command);
+$application->add($flushCommand);
+$application->add($listCommand);
return $application;