问题
I have successfully configure my symfony webapp to sending email using SMTP. But all my sending email are being put into the spool
directory.
This should only occurs whem there is an error in the sending. Is that correct?
But if I execute the command swiftmailer:spool:send --env=prod
, all my emails are sending correctly.
Why my server are not sending the email immediately? Is that because I fixed an error? Is there any way to fix this?
swiftmailer:
spool:
type: file
path: %kernel.root_dir%/spool
回答1:
In case somebody is processing emails via message-queue (symfony/messenger), using memory spool is preferred option. However, memory spool is processed only on Kernel::terminate
event. This event will never occur on long running console worker.
This kernel event is invoking Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener::onTerminate()
method. You can invoke this method manually by dispatching your own event & subscribing above mentioned method to it.
src/App/Email/Events.php
<?php
namespace App\Email;
class Events
{
public const UNSPOOL = 'unspool';
}
config/services.yml
services:
App\Email\AmqpHandler:
tags: [messenger.message_handler]
Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener:
tags:
- name: kernel.event_listener
event: !php/const App\Email\Events::UNSPOOL
method: onTerminate
your message-queue worker
src/App/Email/AmqpHandler.php
<?php
namespace App\Email;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class AmqpHandler
{
/** @var EventDispatcherInterface */
private $eventDispatcher;
/** @var Swift_Mailer */
private $mailer;
public function __construct(EventDispatcherInterface $eventDispatcher, Swift_Mailer $mailer)
{
$this->eventDispatcher = $eventDispatcher;
$this->mailer = $mailer;
}
public function __invoke($emailMessage): void
{
//...
$message = (new Swift_Message($subject))
->setFrom($emailMessage->from)
->setTo($emailMessage->to)
->setBody($emailMessage->body, 'text/html');
$successfulRecipientsCount = $this->mailer->send($message, $failedRecipients);
if ($successfulRecipientsCount < 1 || count($failedRecipients) > 0) {
throw new DeliveryFailureException($message);
}
$this->eventDispatcher->dispatch(Events::UNSPOOL);
}
}
You can read about symfony/messenger here.
回答2:
You can force to flush the spool. For example :
$mailer = $this->container->get('mailer');
$mailer->send($message);
$spool = $mailer->getTransport()->getSpool();
$transport = $this->container->get('swiftmailer.transport.real');
if ($spool and $transport) $spool->flushQueue($transport);
Check also your spool configuration in config.yml.
If you have :
swiftmailer:
....
spool: { type: memory }
mails get sent on the kernel terminate event (so at the end of the page)
回答3:
A just add the command swiftmailer:spool:send
into crontab
. This step wasn't clear on Symfony documentation.
来源:https://stackoverflow.com/questions/29802225/swiftmailer-not-sending-immediately