Skip to content
This repository has been archived by the owner on Feb 6, 2022. It is now read-only.

Emails not sending from commands using memory spooling #127

Closed
mbates opened this issue Dec 29, 2015 · 12 comments
Closed

Emails not sending from commands using memory spooling #127

mbates opened this issue Dec 29, 2015 · 12 comments

Comments

@mbates
Copy link

mbates commented Dec 29, 2015

I'm using Symfony 2.7.3 and Swiftmailer 5.4.1 and according to the documentation (and from PR #64) these versions should automatically handle emails when memory spooling is used.

Emails are sending okay in controllers, so the config is setup correctly.

I've tried sending with the standard email code

$container = $this->getContainer();
$mailer = $container->get('mailer');

...

$email = \Swift_Message::newInstance()
    ->setSubject('New Email')
    ->setFrom('[email protected]')
    ->setTo($recipients)
    ->setBody($message);
$mailer->send($email);

I also tried with the manual flush code at the end of the command

$spool = $mailer->getTransport()->getSpool();
$transport = $container->get('swiftmailer.transport.real');
$spool->flushQueue($transport);

Neither of these worked. (I've also checked that $recipients and $message are valid)

@mbates
Copy link
Author

mbates commented Dec 29, 2015

I've done some more digging and have found that when using memory spooling, flushQueue() is called from vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php

It is calling this when the command ends, so I definitely do not need the code to manually flush the queue.

To see what was going on I edited the flushQueue() function and did a var_dump on the $transport variable. I see that it is using the null transport Swift_Transport_NullTransport to send the emails, which should only be used if disable_delivery is set on the config (or if the transport is set to null in the config)

The problem appears to be coming from this line

swiftmailer-bundle/EventListener/EmailSenderListener.php

$spool->flushQueue($this->container->get(sprintf('swiftmailer.mailer.%s.transport.real', $name)));

I checked $name and it is "default"

I only have one mailer setup in my config

swiftmailer:
    transport:      %mailer_transport%
    host:           %mailer_host%
    username:       %mailer_user%
    password:       %mailer_password%
    spool:          { type: memory }
    port:           %mailer_port%
    encryption:     %mailer_encryption%
    sender_address: %mailer_sender_address%

which is pulling the values from parameters.yml

mailer_transport: sendmail
mailer_host: smtp.sendgrid.net
mailer_user: [USERNAME]
mailer_password: [PASSWORD]
mailer_port: 465
mailer_encryption: ssl
mailer_sender_address: [email protected]

I also checked what I get from this line, in the same class

$mailer = $this->container->get(sprintf('swiftmailer.mailer.%s', $name));

I've attached the debug dumps for the mailer and the transport that I am getting, but I'm not sure they help much:
debug_mailer.txt
debug_transport.txt

@jsor
Copy link

jsor commented Jan 22, 2016

Im experiencing the same bug. The bug was introduced in v2.3.10, v2.3.9 works. So my guessing is, that it has something to do with #121.

@xabbuh
Copy link
Member

xabbuh commented Jan 22, 2016

2.3.11 doesn't work either?

@jsor
Copy link

jsor commented Jan 22, 2016

After digging deeper i think i found the problem. In my case i had the following yml configs:

parameters.yml

parameters:
    mailer_delivery_address: ~

config.yml

imports:
    - { resource: parameters.yml }
swiftmailer:
    delivery_address: "%mailer_delivery_address%"

So, delivery_address ends as an empty string here, not as null: https://github.com/symfony/swiftmailer-bundle/blob/master/DependencyInjection/Configuration.php#L95

Maybe that check should something like:

return array_key_exists('delivery_address', $v) && '' === (string) $v['delivery_address'];

That would include empty strings, null and false.

@danieldumbrava
Copy link

We also have this issue with 2.3 and Symfony 2.7.4. Our temporary solution is not that great for now, but at least it works:

Basically in a command this does not work:

$mailer = $this->getContainer()->get('mailer');
...
$mailer->send($message);

This does:

$transport = $this->getContainer()->get('swiftmailer.transport.real');
...
$mailer = \Swift_Mailer::newInstance($transport);
$mailer->send($message);

@stof
Copy link
Member

stof commented Jan 4, 2017

So, delivery_address ends as an empty string here, not as null

That's really weird. ~ is null in YAML

@Yopai
Copy link

Yopai commented May 31, 2017

Hi,
Got the same issue on Symfony 3.2.9, swiftMailer 5.4.8 and symfony/swiftmailer-bundle 2.6.2, with default parameters (spool set to memory).

The workaround given by @danieldumbrava is working :

$transport = $this->container()->get('swiftmailer.transport.real');
$mailer = \Swift_Mailer::newInstance($transport);

instead of

$mailer = $this->container()->get('mailer');

@kasparsj
Copy link

kasparsj commented Jul 7, 2017

Hi,

We are haveing the same issue in our ExceptionController. Messages are not being set, while they are from normal controllers and even commands.

When debugging I found our that the message is being queued via MemorySpool::queueMessage, but when MemorySpool::flushQueue is called, the queued message is not there (count($this->messages) == 0).

@danieldumbrava workaround works.

Symfony v2.7.29, swiftMailer 5.4.8 and symfony/swiftmailer-bundle 2.6.2, with spool set to memory

@julienfastre
Copy link

I experienced the same issue, the workaround works.

symfony/symfony v3.3.12

@weaverryan
Copy link
Member

For people that have issues, do you have $kernel->terminate() in your front controller? I believe that’s where the message queues are fired.

@ureimers
Copy link

ureimers commented Apr 24, 2018

@weaverryan That's correct. \Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener attaches itself to KernelEvents::TERMINATE or (when run from the console) ConsoleEvents::TERMINATE. Its onTerminate method actually uses the mailer's transport.real transport. So as long as your Web/CLI-Application's Kernel shuts down gracefully the emails are sent.

If you're sending from a custom Plain-old-PHP-Script (play.php @weaverryan / KnpUniversity ;-) where you manually boot Symfony on your own, you can easily call the Listener's onTerminate method yourself by calling something like

    use Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener;
    // ... boot Symfony and send your message
    (new EmailSenderListener($container, $container->get('logger')))->onTerminate();

@niccolomineo
Copy link

niccolomineo commented Oct 9, 2018

I am working on an old 2.0 installation and can't get email sending to work via a command. This is what I am doing:

        $mailer = $container->get('mailer');
        $message = \Swift_Message::newInstance() (setting a bunch of things, too) 
        $mailer->send($message)

I tried also the following but to no avail:

        $transport = $container->get('swiftmailer.transport.real');
        $mailer = \Swift_Mailer::newInstance($transport);
        $message = \Swift_Message::newInstance() (setting a bunch of things, too) 
        $mailer->send($message)

In the latter case, I get:
You have requested a non-existent service "swiftmailer.transport.real"

Debugging the container shows I only have swiftmailer.transport, which has a value of Swift_Transport_NullTransport, but I do have transport set up in my config.yml / parameters.ini as smtp.

EDIT:

The solution was to add the service: https://stackoverflow.com/a/21303631/1025495

@fabpot fabpot closed this as completed Sep 27, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests