Search code examples
phpsymfonyswiftmailersymfony3

Swift_Mailer Symfony 3 add event listener to send event


How to add eventListener to swiftmailer send event? Every time i send email i create a file and attach it to email, and after sending i want to unlink that file. How to do that? Thanks.

 file_put_contents($path, implode(";\r\n", $result));
$message = (new \Swift_Message('VAT checking result !'))
            ->setFrom('[email protected]')
            ->setTo($vat->getEmail())
             ->setBody(
                    'Hello, ...' ,'text/')
             ->attach(\Swift_Attachment::fromPath($path));
// START send result email
    $mailer = $this->container->get('mailer');

    $listener = $this->container->get('app.service.send_email_listener');
    $listener->setPathToFile($path);
    $mailer->registerPlugin($listener);

    $mailer->send( $message );
    // END send email to admin

//unlink($path);  email will not be sent

I tried to register listener like that

app.service.send_email_listener:
    class: AppBundle\Listener\SendEmailListener
    public: true
    tags:
         - { name: swiftmailer.plugin }

this is listener class :

namespace AppBundle\Listener;

use \Swift_Events_SendListener as base;

class SendEmailListener implements base
{
    private $pathToFile;

    public function setPathToFile($path)
    {
        $this->pathToFile = $path;
    }
    public function getPathToFile($path)
    {
        return $this->pathToFile;
    }


    /**
     * Invoked immediately before the Message is sent.
     *
     * @param \Swift_Events_SendEvent $evt
     */
    public function beforeSendPerformed(\Swift_Events_SendEvent $evt)
    {

    }

    /**
     * Invoked immediately after the Message is sent.
     *
     * @param \Swift_Events_SendEvent $evt
     */
    public function sendPerformed(\Swift_Events_SendEvent $evt)
    {
        if($this->pathToFile){
            unlink($this->pathToFile);
        }
    }
}

EDIT It executes the method, but swift is not able to stream the file , beacuse the the file is unlinked before the sending is end... This is from dev_logs:

[2018-05-24 20:40:18] php.CRITICAL: Uncaught Exception: Unable to open file for reading [C:\Users\\projects\vat\web\vatfiles\122.txt] {"exception":"[object] (Swift_IoException(code: 0): Unable to open file for reading [C:\\Users\\\projects\\vat\\web\\vatfiles\\122.txt] at C:\\Users\\projects\\vat\\vendor\\swiftmailer\\swiftmailer\\lib\\classes\\Swift\\ByteStream\\FileByteStream.php:144)"} []

Solution

  • As an alternative to using a Swiftmailer Plugin, I recommend using the __destruct magic method in your service/controller that utilizes the file(s). __destruct will be called when the object is released and will unlink any of the declared paths.

    namespace AppBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    
    class YourController extends Controller
    {
        private $paths = [];
    
        public function someAction()
        {
             $this->paths[] = $path;
             file_put_contents($path, implode(";\r\n", $result));
             $message = (new \Swift_Message('VAT checking result !'))
                ->setFrom('[email protected]')
                ->setTo($vat->getEmail())
                ->setBody('Hello, ...' ,'text/')
                ->attach(\Swift_Attachment::fromPath($path));
             $mailer = $this->container->get('mailer');
             $mailer->send( $message );
    
             return $this->redirectToRoute('some_route');
        }
    
        public function __destruct()
        {
            if ($this->paths) {
                array_map('unlink', $this->paths);
            }
        }
    
    }
    

    NOTE: This approach may not work if you use a spool to send emails, as the email will not be sent until the thresholds have been met for the spool.


    Symfony 2.3+ will automatically register the Swiftmailer plugin when you tag a service with swiftmailer.plugin. So there is no need to call $mailer->registerPlugin($listener);, where swiftmailer will simply ignore duplicate plugin registrations.