Swiftmailer不立即发送邮件

3
我已成功配置我的Symfony Web应用程序,以使用SMTP发送电子邮件。但是,所有我发送的电子邮件都被放置在spool目录中。
只有在发送时出现错误时才应该发生这种情况,对吗?
但是,如果我执行命令swiftmailer:spool:send --env=prod,那么所有的电子邮件都会正确发送。
为什么我的服务器不立即发送电子邮件?是因为我修复了一个错误吗?有没有办法解决这个问题?
Swiftmailer:
spool:
    type: file
    path: %kernel.root_dir%/spool
3个回答

6

如果有人通过消息队列(symfony/messenger)处理电子邮件,使用内存 spool 是首选。但是,内存 spool 只在 Kernel::terminate 事件上进行处理。这个事件不会发生在长时间运行的控制台工作进程中。

这个内核事件调用了 Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener::onTerminate() 方法。你可以通过分派自己的事件并订阅上述方法来手动调用此方法。

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

消息队列工人 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.


3
您可以强制刷新输出缓存。 例如:
$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);

请在 config.yml 文件中检查您的 spool 配置。

如果您有:

swiftmailer:
    ....
    spool:     { type: memory }

电子邮件会在内核终止事件(即页面结束时)发送。

是的,在某些情况下我会这样做。但是当FOSUserBundle发送电子邮件时,队列没有被刷新。我使用的是文件类型的 spool。因此,只有在我手动刷新时才会发送电子邮件。在我的旧机器上,这是自动完成的。 - Victor
你不想使用内存吗?(至少对于FOSUserBundle而言) - griotteau
为什么要使用“文件”和“内存”? - Victor
请参考http://symfony.com/doc/current/cookbook/email/spool.html了解文件 spool 的优势(但您必须刷新...)。 - griotteau
是的,现在我明白了。我正在从另一个人配置的机器上进行迁移,所以这是我第一次从零开始配置Symfony。并不清楚你应该将命令添加到cron表中以发送电子邮件。 - Victor

3
只需要在crontab中添加命令swiftmailer:spool:send即可。这一步在Symfony文档中并不清晰。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接