Attaching a file to a mail using Laravel and Ajax

Attaching a file to a mail using Laravel and Ajax

While sending a mail from your Laravel software isn't much of a problem, attaching a file to the mail can sometimes be a tough tooth to crack. I experienced such a situation and this was how you can be able to get it resolved using Ajax.

The View

After creating your form fields and giving your form an id (in this case, I will use send_mail as the id of the form), you create a javascript (jquery) function to process and send the mail from the form in this way.

function sendMail() {
              var form = $('#post_customer_mail')[0];

              var formData = new FormData(form);

              $.ajax({
                  url: "/send_mail_with_attachment",
                  type: "POST",
                  data:formData,
                  cache: false,
                  contentType: false,
                  processData: false,
                  success:function(response){
                      swal({
                          title: "Done!",
                          text: "Mail sent successfully!",
                          icon: "success",
                          button: "OK!",
                      });
                  },
              });

              // return stop the form from loading
              return false;
          }

From the code snippet above, all the data from the form are collected and stored in the variable, var form. Using the HTML

element, FormData, which is being populated with the current keys and values of the form using the name property of each element as the keys and the submitted input values as the value, and also encodes file input content. With $.ajax, an asynchronous POST request is being sent to the route /send_mail_with_attachment. 

Then set cache, contentType, processData to false. After the mail has been sent, a SweetAlert message is shown to the user for notification. Learn more about SweetAlert here .

The Route

Next is to create a route to which the POST request will be pointing to. This will be done in the web.php file in the routes folder.

Route::post('/send_mail_with_attachment', 'MailController@sendMail');

As seen in the code snippet above, we created a function in the MailController to handle the mailing of the form's current input values.

The Controller

In our MailController, we will set up our sendMail function as follows:

public function sendMail(Request $request)
    {

        $email = $request->email;
        $subject = $request->mail_subject;
        $body = $request->mail_body;
        $file = $request->file('mail_attachment');
        $file_attached = [
             'file' => $file->getRealPath(), [
                 'options' => [
                      'mime' => $file->getClientMimeType(),
                      'as'    => $file->getClientOriginalName()
                   ],
              ],
         ];

         $mail = new SendMail($subject, $body, $file_attached);
         Mail::to($email)->send($mail);


    }

From the code snippet above, we got the file path of the uploaded file, and in the options array, we included the file mime type (also known as media type) and the file's original name. The variables are then passed into the Laravel mail.

The Mail Setup

To set up the SendMail class, we make the variables passed in the sendMail() function in the controller public and pass it through the __construct function as such:

    public $subject;
    public $body;
    public $file_attached;
    public function __construct($subject, $body, $file_attached)
    {
        $this->subject = $subject;
        $this->body   = $body;
        $this->file_attached  = $file_attached;
    }

After that is done, in the build() function, pass the mail body into the markdown template created with the mail using PHP artisan (read more here ). Then using the base64_decode() function (which according to GeeksforGeeks, is an inbuilt function in PHP used to decode data that is encoded in MIME base64) inside the Laravel attachData() function, we decode the file attached to the mail while also passing the options array. Our code should look as so:

public function build()
    {
        return $this->markdown('mails.sample-mail-markdown')
                    ->subject($this->subject)
                    ->attachData(base64_decode($this->file_attached['file']), $this->file_attached[0]['options']['as'], [
                        $this->file_attached[0]['options'],
                    ]);
    }

Now your mail with attachment is now ready. You can test it with your Mailtrap or any mailing platform you prefer.

I hope this was useful to you. Cheers.