9

I have written a custom console command to query my database, produce a report and e-mail it to an address; however I can not seem to successfully send the e-mail. I can send e-mail fine from within normal controllers elsewhere within my application, and I can also send it from within my console command if I manually create and configure a Swift_Mailer instance and not get it via the container.

Here is a stripped down version of my console command:

<?php

namespace Foo\ReportBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ExpiryCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this->setName('report:expiry')
            ->setDescription('Compile and send e-mail listing imminent expiries');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        /* ... */
        $message = \Swift_Message::newInstance()
            ->setSubject('Expiry report')
            ->setFrom('DoNotReply@domain.com')
            ->setTo('recipient@domain.com')
            ->setBody($body);

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

/*      This works...
        $transport = \Swift_SmtpTransport::newInstance('smtp.domain.com', 25)
            ->setUsername('username')
            ->setPassword('password');
        $mailer = \Swift_Mailer::newInstance($transport);
*/
        $result = $mailer->send($message);
        $output->writeln($result);
    }
}

Swiftmailer is configured to send via SMTP within my app/config/config.yml file (delivery_address: dev@domain.com is also set in app/config/config_dev.yml):

swiftmailer:
    transport: smtp
    host: smtp.domain.com
    username: username
    password: password
    spool:
        type: memory

When running the command, it prints 1 to the command line, which I assume it means it was successful. However I'm monitoring my mail server's logs at the same time, and it's not even connecting.

To confirm that my configuration was being loaded into the mailer, I changed the spool from memory to file and messages are being spooled to the file system when running the command and I can successfully flush the spool on the command line with php app/console swiftmailer:spool:send.

Does anyone have any ideas as to what's happening here, or any suggestions as to how I can debug it further? Nothing is appearing in my app/logs/dev.log file. I'm using Symfony 2.1.3-DEV.

Kris
  • 1,094
  • 3
  • 13
  • 23

3 Answers3

27

From digging some Symfony and SwiftMailer code, I can see that the memory spool is flushed on the kernel.terminate event that occurs after a response was sent. I'm not sure it works for the commands, but I may be wrong.

Try adding this code at the end of your command and see if it helps:

$transport = $this->container->get('mailer')->getTransport();
if (!$transport instanceof \Swift_Transport_SpoolTransport) {
    return;
}

$spool = $transport->getSpool();
if (!$spool instanceof \Swift_MemorySpool) {
    return;
}

$spool->flushQueue($this->container->get('swiftmailer.transport.real'));
Elnur Abdurrakhimov
  • 44,533
  • 10
  • 148
  • 133
  • Manually flushing the spool like this appears to work, I guess the `kernel.terminate` event isn't fired within console commands, then. Thanks! – Kris Oct 29 '12 at 16:23
  • 1
    Another option is disabling the spool from the config file, you can do this only for the command line. I did this as a temporary solution (yeah right) and it worked for me. – Jens Feb 22 '13 at 23:44
  • As always, great answer Elnur! :) – DonCallisto Jan 13 '14 at 09:16
2

Instead of memory spool use file spool. Modify your app/config/config.yml:

swiftmailer:
    transport: "%mailer_transport%"
    host:      "%mailer_host%"
    username:  "%mailer_user%"
    password:  "%mailer_password%"
    spool:     { type: file, path: %kernel.root_dir%/spool }
and_rest
  • 314
  • 2
  • 7
-1

Just add this to the end of your execute action:

$container = $this->getContainer();
$mailer = $container->get('mailer'); 
$spool = $mailer->getTransport()->getSpool();    
$transport = $container->get('swiftmailer.transport.real');
$spool->flushQueue($transport);
Matthias
  • 19
  • 3