symfony / swiftmailer-bundle

Symfony Swiftmailer Bundle
https://symfony.com/swiftmailer-bundle
MIT License
1.56k stars 151 forks source link

Send emails async with symfony messenger #258

Closed Fisher-mast closed 5 years ago

Fisher-mast commented 6 years ago

Hello, i'm trying to send emails async with symfony messenger:

// src/Controller/MessengerController.php
public function index(MessageBusInterface $bus, UserRepository $userRepository)
    {
        $user = $userRepository->find(1);

        $event = new UserMessage($user->getId());
        $bus->dispatch($event);

        return $this->render('messenger/index.html.twig', [
            'controller_name' => 'MessengerController',
        ]);
    }

// src/Message/Handler/UserRegisteredHandler.php
class UserRegisteredHandler
{
    private $mailer;
    private $templating;
    private $userRepository;

    public function __construct(\Swift_Mailer $mailer, \Twig_Environment $templating, UserRepository $userRepository)
    {
        $this->mailer = $mailer;
        $this->templating = $templating;
        $this->userRepository = $userRepository;
    }

    public function __invoke(UserMessage $event)
    {
        $user = $this->userRepository->find($event->getUserId());
        $message = new \Swift_Message();
        $message
            ->setSubject('Site: подтверждение регистрации.')
            ->setFrom('no-reply@site.com')
            ->setTo($user->getEmail())
            ->setBody(
                $this->templating->render('emails/registration.html.twig', ['user' => $user]),
                'text/html'
            );

        $this->mailer->send($message);
    }
}

It is not working when i'm using sf messenger async. But when i disable async - it is work. By default symfony swiftmailer bandle settings:

// config/packages/swiftmailer.yaml
swiftmailer:
    url: '%env(MAILER_URL)%'
    spool: { type: 'memory' }

I'm check other types of spool. There are only two: memory and spool. And as i understand type: 'memory' is not work. By command: php bin/console config:dump-reference swiftmailer i understand that without property "type" in swiftmailer.yaml config wiil be:

spool:
                type:                 file
                path:                 '%kernel.cache_dir%/swiftmailer/spool'

so, i comment "type":

// config/packages/swiftmailer.yaml
swiftmailer:
    url: '%env(MAILER_URL)%'
#    spool: { type: 'memory' }

and now must be file type. But when i dispatch message email was sended async. I can't understand why! When using type file, emails must send only after console command php bin/console swiftmailer:spool:send I checked php bin/console debug:config swiftmailer - Current configuration for extension with alias "swiftmailer" and here no spool type:

swiftmailer:
    default_mailer: default
    mailers:
        default:
            url: '%env(MAILER_URL)%'
            delivery_addresses:
                - '%env(MAILER_DEV_ADDRESS)%'
            transport: smtp
            command: '/usr/sbin/sendmail -bs'
            username: null
            password: null
            host: localhost
            port: null
            timeout: 30
            source_ip: null
            local_domain: null
            encryption: null
            auth_mode: null
            logging: true
            delivery_whitelist: {  }

How it's works? It's error? p.s. it's good that last config send emails like i want, but i scared that it is stop working after some time, because i do not understand how it works... p.s.s sry for my English)

symfony 4.1.6 php 7.2.10

// UPDATE When i try set type file manualy:

// config/packages/swiftmailer.yaml
swiftmailer:
    url: '%env(MAILER_URL)%'
    spool:
        type:                 file
        path:                 '%kernel.cache_dir%/swiftmailer/spool'

it sends emails only after console command php bin/console swiftmailer:spool:send

kojidev commented 5 years ago

I didn't actually understand what you want.

Do you want to handle a Symfony Messenger's Message asynchronously through AMQP protocol (RabbitMQ)?

If first is the case you have to set up AMQP transport: https://symfony.com/doc/current/messenger.html#transports and use no spool at all

Default SwiftMailer spools are: memory and file neither of them understand the concept of AMQP queues. Tho you could implement one using Swift_Spool interface.

Memory spool just lets user go and after that sends a mail before terminating, so that user doesn't have to wait for SMTP. File spool writes mails to files than sends them on a command.

atakchidi commented 5 years ago

I didn't understand your first sentence about the async stuff, but talking about default configuration of swiftmailer according to symfony docs if spool is not specified email are send immediately. It is the very first sentence in the link I provided: "The default behavior of the Symfony mailer is to send the email messages immediately." This is exactly what happened when you commented out the spool config line. So it's working exactly as described in the docs.

fr4ngus commented 5 years ago

Close #258

jkobus commented 5 years ago

I have similar problem on dev environment in symfony - when I use memory spool and try to send an email from the command line it does not work. When I use spool using files (and then issue the command to flush it) mail is delivered.

Update:

After some digging it turns out that:

Hope this will help someone :)

chalasr commented 5 years ago

If you have an async transport configured for symfony/messenger, you don't have to use the spool. What you need is to have a bin/console messenger:consume-messages process that will actually handle the messages dispatched by your application.

Also as of 4.3 a better alternative is to use https://symfony.com/doc/current/components/mailer.html.