How to unlink files after they have been attached and sent? (When using Mail::queue)
Asked Answered
Q

3

6

I switched from sending my mails immediately to adding them to the queue, here is my code, the $attachments is an array of temporary paths, I've commented out what I've tried, which throws errors about files not existing.

Mail::queue($view, $data, function(\Illuminate\Mail\Message $message) use($mail,$attachments){
    foreach($mail->getRecipients() as $recipient){
        $message->to($recipient);
    }
    $message->subject($mail->getSubject());
    foreach($attachments as $attachment){
        $message->attach($attachment);
        //this deletes the attachment before being sent
        //unlink($attachment);
    }
});
/* This code only works when using Mail::send() instead of Mail:queue()
foreach($attachments as $attachment){
    unlink($attachment);
}
*/

Basically I want to clean up and remove my temporary attachments after the mail was sent. I am guessing this would not work with the out of the box laravel mail solutions. How can I trigger code post-queue-mail-sent?

Quadrant answered 13/5, 2014 at 17:4 Comment(0)
G
2

You have to wait until the queue is processed before removing the file.

Without knowing the implementation details of the queue it is hard to answer your question, but if your queue is processed before the script ends, you can use register_shutdown_function http://www.php.net/manual/en/function.register-shutdown-function.php to run a cleanup function that removes the file

register_shutdown_function(function() use (filename){
    if (file_exists($filename)) {
        unlink($filename);
    }
})
Guidotti answered 13/5, 2014 at 17:43 Comment(0)
I
9

Expanding on Deric Lima's answer a bit, you don't necessarily need a new Job class for this. You can do it with a Mailable object as well. Just override the send method.

/**
 * @param MailerContract $mailer
 */
public function send(MailerContract $mailer)
{
    parent::send($mailer);

    //$this->clearAttachments is something you can defined in your constructor,
    //making it the responsibility of whatever is applying the attachment
    //to know whether it needs to remain in tact after the email is transmitted.
    if ($this->clearAttachments) {
        foreach ($this->attachments as $attachment) {
            if (\File::exists($attachment['file'])) {
                \File::delete($attachment['file']);
            }
        }
    }
}

Personally, I'd make a BaseMailable class that all other Mailable classes extend, as opposed to the Illuminate\Mail\Mailable directly. Then you don't even have to worry about it from then on.

Istanbul answered 26/4, 2018 at 22:17 Comment(0)
G
2

You have to wait until the queue is processed before removing the file.

Without knowing the implementation details of the queue it is hard to answer your question, but if your queue is processed before the script ends, you can use register_shutdown_function http://www.php.net/manual/en/function.register-shutdown-function.php to run a cleanup function that removes the file

register_shutdown_function(function() use (filename){
    if (file_exists($filename)) {
        unlink($filename);
    }
})
Guidotti answered 13/5, 2014 at 17:43 Comment(0)
B
1

I had similar problem and I solved using Laravel Jobs. Basically, you can create a Job class to send the email:

class MailJob extends Job implements SelfHandling, ShouldQueue
{
  use InteractsWithQueue, SerializesModels;

  public function handle()
  {
    Mail::send($view, $data, function (\Illuminate\Mail\Message $message) use ($mail, $attachments) {
        foreach ($mail->getRecipients() as $recipient) {
            $message->to($recipient);
        }
        $message->subject($mail->getSubject());
        foreach ($attachments as $attachment) {
            $message->attach($attachment);
            unlink($attachment);
        }
    });
    foreach ($attachments as $attachment) {
        unlink($attachment);
    }
}

}

And then you just dispatch the Job inside the controller that you want to send the email:

$this->dispatch(new MailJob());

P.S: The job is running asynchronous on the background, so I used Mail::send instead of Mail::queue.

Bluefish answered 17/1, 2017 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.