16

How does one go about attaching multiple files to laravel 5.3 mailable?

I can attach a single file easily enough using ->attach($form->filePath) on my mailable build method. However, soon as I change the form field to array I get the following error:

basename() expects parameter 1 to be string, array given

I've searched the docs and also various search terms here on stack to no avail. Any help would be greatly appreciated.

Build Method:

public function build()
{
    return $this->subject('Employment Application')
                ->attach($this->employment['portfolio_samples'])
                ->view('emails.employment_mailview');
}

Mail Call From Controller:

Mail::to(config('mail.from.address'))->send(new Employment($employment));
kash101
  • 269
  • 2
  • 4
  • 13

3 Answers3

42

You should store your generated email as a variable, then you can just add multiple attachments like this:

public function build()
{
    $email = $this->view('emails.employment_mailview')->subject('Employment Application');
    
    // $attachments is an array with file paths of attachments
    foreach ($attachments as $filePath) {
        $email->attach($filePath);
    }

    return $email;
}

In this case your $attachments variable should be an array with paths to files:

$attachments = [
    // first attachment
    '/path/to/file1',

    // second attachment
    '/path/to/file2',
    ...
];

Also you can attach files not only by file paths, but with MIME type and desired filename, see documentation about second case of use for the `attachment` method: https://laravel.com/docs/master/mail#attachments

For example, your $attachments array can be something like this:

$attachments = [
    // first attachment
    'path/to/file1' => [
        'as' => 'file1.pdf',
        'mime' => 'application/pdf',
    ],
    
    // second attachment
    'path/to/file12' => [
        'as' => 'file2.pdf',
        'mime' => 'application/pdf',
    ],
    
    ...
];

After you can attach files from this array:

// $attachments is an array with file paths of attachments
foreach ($attachments as $filePath => $fileParameters) {
    $email->attach($filePath, $fileParameters);
}
Alexander Reznikov
  • 1,266
  • 1
  • 14
  • 23
  • 1
    This solution works perfectly in L5.8, but make sure to use a different name instead of `$attachments` as the internal Mailable class already has a property with the name `$attachments`. Using the same name overwrites the property and causes errors. – Sven Aug 16 '19 at 23:00
  • @Sven, thanks for your comment. However, you're wrong about the name of this example variable. Even if some class has an `$attachments` property, we still can create a variable with the same name `$attachments` because non-static properties can via the pseudo-variable `$this`, so our variable doesn't interfere with the properties of this hypothetical class. Static properties of any class can be accessed using `static` keyword, so again — our variable doesn't cause any troubles there. – Alexander Reznikov Aug 16 '19 at 23:18
  • @AlexanderReznikov I'm not sure what's the issue then but there might be side effects: https://stackoverflow.com/q/54262711/1815847 ([source](https://github.com/laravel/framework/blob/5.8/src/Illuminate/Mail/Mailable.php#L112)) – Sven Aug 16 '19 at 23:26
  • 1
    In case you mentioned user @Matt E. tries to create an own class property `$attachments` and it overwrites a Laravel `$attachment` class property. You can you variables with the "same" names without any worries, see an example: http://sandbox.onlinephpfunctions.com/code/8b94a2998532abf5535b724b38a6d794441db61c – Alexander Reznikov Aug 16 '19 at 23:30
  • @AlexanderReznikov You're right. It's only an issue with `$this->attachments`. Thank you for your patience. – Sven Aug 17 '19 at 00:40
  • Sure, no problem. – Alexander Reznikov Aug 17 '19 at 00:41
  • There's no need to store it in the `email` variable since you're working with an object. In the end you can just return `$this`. – César Escudero Apr 19 '20 at 02:36
0

Best solution work for me

$email = $this->from($from)->subject("Employment Application")
    ->view('emails.employment_mailview');

foreach ($files as $file) {
    $path = '/path/to/'.$file->file;
    $attachments->push($path);
}

$attachments = collect([]);

foreach ($attachments as $filePath) {
    $email->attach($filePath);
}

return $email;
Simo OM
  • 139
  • 6
0

This worked for me, maybe it will work for more people. As I am getting the files via $request this was the solution works for me.

obs: sorry I'm using translate. From Portuguese(Brazil) to English.

thanks @AlexanderReznikov, it helped me a lot.

class SendMailextends Mailable
   {

      protected $inputs;
      protected $files;

    public function __construct(array $inputs, array $files)
    {
            $this->inputs = $inputs;
            $this->files = $files;

    }

public function build()
{

if (isset($this->files)){
 $email =  $this->from('you@mail')->view('email.email-contact')->subject('Email teste mulptiple files');

        for ($indice = 0; $indice < count($this->files['files']); $indice++) {

                $files = $this->files[$indice];

                $pathName = $files->getPathname();

                $attachments = $pathName;

                $fileName = $files->getClientOriginalName();

                $email->attach($attachments,['as' => "$fileName"]);

            }

        return $email;

    }else{
        // file empty, send email
        return $this->from('you@mail','name')->subject('Email teste mulptiple files')
            ->view('email.email-contact');
    }
}
}