Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

olivermbs's avatar

Generate PDF using job and then attach to queueable email

I need to send a PDF which is generated by a job (it’s quite a complicated document) and then send it via a queued mailable as an attachment.

Question: how can this best be achieved? I would need the mailable only to send once the PDF job has completed. Ideally the PDF creation job would pass its file path to the mailable directly, is this possible? I’m not sure if I should be looking into batched jobs or pipelines for this, I can’t seem to join the two pieces together.

I’m not keen on sending the mail in the PDF creation job, as I might want to create the PDF without sending it in the future.

Thanks!

0 likes
2 replies
LaryAI's avatar
Level 58

To achieve this, you can use Laravel's queue system along with a combination of jobs and mailables.

First, create a job that generates the PDF. This job should implement the ShouldQueue interface to ensure it is queued for processing. Within the handle method of the job, you can generate the PDF and save it to a specific location. You can then pass the file path to the mailable.

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class GeneratePdfJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $user;
    protected $pdfFilePath;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        // Generate the PDF and save it to a specific location
        $pdf = generatePdf(); // Replace with your PDF generation logic
        $this->pdfFilePath = storage_path('app/pdf/' . $this->user->id . '.pdf');
        file_put_contents($this->pdfFilePath, $pdf);
    }

    public function getPdfFilePath()
    {
        return $this->pdfFilePath;
    }
}

Next, create a mailable that will send the email with the PDF attachment. In the build method of the mailable, you can attach the PDF file using the file path passed from the job.

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class SendPdfEmail extends Mailable
{
    use Queueable, SerializesModels;

    protected $pdfFilePath;

    public function __construct($pdfFilePath)
    {
        $this->pdfFilePath = $pdfFilePath;
    }

    public function build()
    {
        return $this->view('emails.pdf')
            ->attach($this->pdfFilePath, [
                'as' => 'document.pdf',
                'mime' => 'application/pdf',
            ]);
    }
}

Finally, in your controller or wherever you trigger the process, dispatch the GeneratePdfJob and pass the user to it. Once the job is completed, you can dispatch the SendPdfEmail mailable with the PDF file path.

use App\Jobs\GeneratePdfJob;
use App\Mail\SendPdfEmail;

public function sendPdfEmail(User $user)
{
    $generatePdfJob = new GeneratePdfJob($user);
    dispatch($generatePdfJob);

    $pdfFilePath = $generatePdfJob->getPdfFilePath();
    $sendPdfEmail = new SendPdfEmail($pdfFilePath);
    dispatch($sendPdfEmail);
}

This way, the PDF generation job will be queued and processed asynchronously. Once the job is completed, the mailable will be dispatched with the PDF file attached.

Note: Make sure to replace the placeholders (User, generatePdf(), emails.pdf, etc.) with your actual code and logic.

Snapey's avatar

I would move the pdf creation to a service so that you can use it in different contexts

Then create a job that creates the pdf using the service and then sends it.

1 like

Please or to participate in this conversation.