Laravel send mail with file attachment example

Sending mail with attachment is always cumbersome work in web application. But Laravel provides easy way to add attachment with email. This will help in sending email with bill, report over email and used don't need to open portal for that.

In this article, I will share you how you can send email with file attachment. I will send image file in email. However you can also send PDF, Excel files in attachment. We will create a view to facilate upload file function with desired email address. So when we input email and file attachment and click Send button, it will send attached file to the input mail.

We will go through step by step from the scratch. For sending email, we will use Mailjet mail server. You can use any mail server including Sendgrid, Gmail, Mailchimp etc. So let's start from creating new Laravel application.

Step 1: Create Laravel application

In the first step, we will create a new Laravel application using Composer command. So open Terminal in Unix system or Command Prompt in Windows system and from your works

composer create-project laravel/laravel mail

And now change working directory in Terminal

cd mail

Step 2: Set mail configuration

In the step, we will configure mail credentials in .env file which is located at root directory of project. So change it as your mail server credentials. Here is the article to send email over Sendgrid.

MAIL_MAILER=smtp
MAIL_HOST=us-v1.mailjet.com
MAIL_PORT=587
MAIL_USERNAME=26**********7ba26
MAIL_PASSWORD=YPAMv*******1yoO78
MAIL_ENCRYPTION=tls
MAIL_FROM_NAME="HackTheStuff"
[email protected]

If you are using Gmail for sending mail, don't forget to disable 2-Step authentication. Here is Gmail configuration for .env. Sometimes you might need to configure  MAIL_DRIVER=sendmail to work correctly sending mail.

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
[email protected]
MAIL_PASSWORD=password
MAIL_ENCRYPTION=tls

Make sure you have whitelisted localhost and your network IPs into mail server's backoffice. Otherwise email will be sent over Spam folder. 

Step 3: Create a controller

Now we will need controller class which will trigger Mailable to send mail. So run the artisan command to create controller.

php artisan make:controller MailController

It will create a new class at app/Http/Controllers/MailController.php file. Open file and add two new methods in it. One method will view attachment view and second method will upload file and send mail.

<?php

namespace App\Http\Controllers;

use File;
use Mail;
use App\Mail\Notification;
use Illuminate\Http\Request;

class MailController extends Controller
{
    /**
     * email send view.
     *
     * @return $this
     */
    public function mailView()
    {
        return view('mailView');
    }

    /**
     * save file and send mail.
     *
     * @return $this
     */
    public function mailSend(Request $request)
    {
        $input = $request->validate([
            'email' => 'required',
            'attachment' => 'required',
        ]);

        $path = public_path('uploads');
        $attachment = $request->file('attachment');

        $name = time().'.'.$attachment->getClientOriginalExtension();;

        // create folder
        if(!File::exists($path)) {
            File::makeDirectory($path, $mode = 0777, true, true);
        }
        $attachment->move($path, $name);

        $filename = $path.'/'.$name;

        try {
            Mail::to($input['email'])->send(new Notification($filename));
        } catch (\Exception $e) {
            return redirect()->back()->with('success', $e->getMessage());
        }

        return redirect()->back()->with('success', 'Mail sent successfully.');
    }
}

Step 4: Create routes

In this step, we will create two new routes to handle controller methods in routes/web.php file. Open file and add new routes as below:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\MailController;

Route::get('mail', [MailController::class, 'mailView'])->name('mailView');
Route::post('send-mail', [MailController::class, 'mailSend'])->name('mailSend');

Step 5: Create mailable class

Now we need mailable class which will send mail with attachment. From the Terminal, run below command to create a mailable.

php artisan make:mail Notification

This will create class in app/Mail directory. Open the file and add following class in build() method.

<?php

namespace App\Mail;

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

class Notification extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * The data.
     *
     * @var array
     */
    public $filename;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($filename)
    {
        $this->filename = $filename;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('notification')
            ->subject('This is notification')
            ->attach($this->filename);
    }
}

We have created object of this class in controller with attachment path. So the variable we passed in controller will be available here.

Step 6: Create blade view

We have done all server side work done. Now its time to create front-end side work. In this step, we will create a blade view from which we will upload attachment. We will also create a template file for mail.

First create a mailView.blade.php file for file upload view.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Send mail</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container m-1">
        <h1 class="lead mt-3">Send mail using attachment</h1>
        <div class="row">
            <div class="md-12">
                <div class="card">
                    <div class="class-body">
                        @if(\Session::has('success'))
                            <div class="alert alert-success m-3">{{ \Session::get('success') }}</div>
                            {{ \Session::forget('success') }}
                        @endif
                        @if(\Session::has('error'))
                            <div class="alert alert-danger m-3">{{ \Session::get('error') }}</div>
                            {{ \Session::forget('error') }}
                        @endif
                        <form method="post" action="{{ route('mailSend') }}" enctype="multipart/form-data" class="m-5">
                            @csrf
                            <div class="mb-3">
                                <label for="email" class="form-label">Email address</label>
                                <input type="email" class="form-control" id="email" placeholder="[email protected]" name="email">
                            </div>
                            <div class="mb-3">
                                <label for="attachment" class="form-label">File upload</label>
                                <input class="form-control" type="file" id="attachment" name="attachment">
                            </div>
                            <input type="submit" name="Send mail" class="btn btn-primary">
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

And now create notification.blade.php file for mail template.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>This is test mail</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container text-center m-1">
        <h1 class="lead mt-3">Send mail using attachment</h1>
        <p class="lead">Please check attachment with this file.</p>
    </div>
</body>
</html>

Now we have completed the coding, its time to test the application. Run the following command in Terminal to start Laravel server.

php artisan serve

In your favourite web browser, open http://localhost:8000/mail url. You will see the view as we have described earlier.

Now enter the email where you want to send mail and add attachment also. Now submit the form. The entered email address will receive the mail with attachment.

Sometimes, you might get error in seding email. In this situation, try to change mail driver. Sometimes it might be issue from mail server, so read official documentation for mail server. You will surely get solution.

Conclusion

So far we have learned how to send mail with attachment in Laravel 8. This will also work with Laravel previous versions also.

I hope you liked this article. Happy coding!

Tags: