Ajax Contact Form with an Attachment (jQuery & PHP)

Today let’s create an Ajax based contact form, that will allow users to send attachments in email message. This tutorial has been updated recently and is based on my recent post here. I’ve added Ajax part to the the example here, it will send form data without refreshing the page.


contact-form-attachment-example

Mark Up

In order to send file as an attachment, first we must allow users to upload file using contact form. As you can see I have added file input field called file_attach[] to our form, you can add as many file input field with same name for multiple attachments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<div id="contact_results"></div>
<form id="contact_body" method="post" action="contact_me.php">
    <label for="name"><span>Name <span class="required">*</span></span>
        <input type="text" name="name" data-required="true"/>
    </label>
    <label for="email"><span>Email <span class="required">*</span></span>
        <input type="email" name="email" data-required="true"/>
    </label>
    <label><span>Phone <span class="required">*</span></span>
        <input type="text" name="phone1" maxlength="4" placeholder="+91" data-required="true"/>&mdash;
        <input type="text" name="phone2" maxlength="15" data-required="true"/>
    </label>
    <label><span>Attachment</span>
        <input type="file" name="file_attach[]"  />
    </label>
   
        <label for="subject"><span>Regarding</span>
        <select name="subject">
        <option value="General Question">General Question</option>
        <option value="Advertise">Advertisement</option>
        <option value="Partnership">Partnership Oppertunity</option>
        </select>
    </label>
    <label for="message"><span>Message <span class="required">*</span></span>
        <textarea name="message" data-required="true"></textarea>
    </label>
    <label><span>&nbsp;</span>
        <button type="submit">Submit</button>
    </label>
</form>

jQuery Ajax Form Submit

Before we submit our form data to server using Ajax, we need to make sure input fields are not empty, and file type is allowable, and its size is not too big. For that we use HTML5 File API to read file data and validate it with our jQuery code. Once we validate our input fields, we can then send form data using jQuery $.ajax(). You can check-out my other post for more info about Ajax form submit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
var allowed_file_size = "1048576"; //allowed file size
var allowed_files = ['image/png', 'image/gif', 'image/jpeg', 'image/pjpeg']; //allowed file types
var border_color = "#C2C2C2"; //initial input border color

$("#contact_body").submit(function(e){
    e.preventDefault(); //prevent default action
    proceed = true; //set proceed flat to true
   
    //simple input validation
    $($(this).find("input[data-required=true], textarea[data-required=true]")).each(function(){
            if(!$.trim($(this).val())){ //if this field is empty
                $(this).css('border-color','red'); //change border color to red  
                proceed = false; //set do not proceed flag
            }
            //check invalid email
            var email_reg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
            if($(this).attr("type")=="email" && !email_reg.test($.trim($(this).val()))){
                $(this).css('border-color','red'); //change border color to red  
                proceed = false; //set do not proceed flag              
            }  
    }).on("input", function(){ //change border color to original
         $(this).css('border-color', border_color);
    });
   
    //check file size and type before upload, works in modern browsers
    if(window.File && window.FileReader && window.FileList && window.Blob){
        var total_files_size = 0;
        $(this.elements['file_attach[]'].files).each(function(i, ifile){
            if(ifile.value !== ""){ //continue only if file(s) are selected
                if(allowed_files.indexOf(ifile.type) === -1){ //check unsupported file
                    alert( ifile.name + " is unsupported file type!");
                    proceed = false;
                }
             total_files_size = total_files_size + ifile.size; //add file size to total size
            }
        });
       if(total_files_size > allowed_file_size){
            alert( "Make sure total file size is less than 1 MB!");
            proceed = false;
        }
    }
   
    //if everything's ok, continue with Ajax form submit
    if(proceed){
        var post_url = $(this).attr("action"); //get form action url
        var request_method = $(this).attr("method"); //get form GET/POST method
        var form_data = new FormData(this); //constructs key/value pairs representing fields and values
       
        $.ajax({ //ajax form submit
            url : post_url,
            type: request_method,
            data : form_data,
            dataType : "json",
            contentType: false,
            cache: false,
            processData:false
        }).done(function(res){ //fetch server "json" messages when done
            if(res.type == "error"){
                $("#contact_results").html('<div class="error">'+ res.text +"</div>");
            }
           
            if(res.type == "done"){
                $("#contact_results").html('<div class="success">'+ res.text +"</div>");
            }
        });
    }
});

Once the form data is sent to server successfully, the server should return JSON data, which we will grab and output message within the #contact_results div element.

PHP mail

Below is the complete PHP code that sends mail with attachments, taken from my other post PHP mail with Multiple Attachments. We will do simple server-side validation and play with PHP $_FILES before attaching file to mail header. If there’s no file uploaded for the attachment, we will simply switch to plain email.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
$recipient_email    = "recipient@yourmail.com"; //recepient
$from_email         = "info@your_domain.com"; //from email using site domain.


if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
    die('Sorry Request must be Ajax POST'); //exit script
}

if($_POST){
   
    $sender_name    = filter_var($_POST["name"], FILTER_SANITIZE_STRING); //capture sender name
    $sender_email   = filter_var($_POST["email"], FILTER_SANITIZE_STRING); //capture sender email
    $country_code   = filter_var($_POST["phone1"], FILTER_SANITIZE_NUMBER_INT);
    $phone_number   = filter_var($_POST["phone2"], FILTER_SANITIZE_NUMBER_INT);
    $subject        = filter_var($_POST["subject"], FILTER_SANITIZE_STRING);
    $message        = filter_var($_POST["message"], FILTER_SANITIZE_STRING); //capture message

    $attachments = $_FILES['file_attach'];
   
   
    //php validation
    if(strlen($sender_name)<4){ // If length is less than 4 it will output JSON error.
        print json_encode(array('type'=>'error', 'text' => 'Name is too short or empty!'));
        exit;
    }
    if(!filter_var($sender_email, FILTER_VALIDATE_EMAIL)){ //email validation
        print json_encode(array('type'=>'error', 'text' => 'Please enter a valid email!'));
        exit;
    }
    if(!filter_var($country_code, FILTER_VALIDATE_INT)){ //check for valid numbers in country code field
        $output = json_encode(array('type'=>'error', 'text' => 'Enter only digits in country code'));
        exit;
    }
    if(!filter_var($phone_number, FILTER_SANITIZE_NUMBER_FLOAT)){ //check for valid numbers in phone number field
        print json_encode(array('type'=>'error', 'text' => 'Enter only digits in phone number'));
        exit;
    }
    if(strlen($subject)<3){ //check emtpy subject
        print json_encode(array('type'=>'error', 'text' => 'Subject is required'));
        exit;
    }
    if(strlen($message)<3){ //check emtpy message
        print json_encode(array('type'=>'error', 'text' => 'Too short message! Please enter something.'));
        exit;
    }

   
    $file_count = count($attachments['name']); //count total files attached
    $boundary = md5("sanwebe.com");
           
    if($file_count > 0){ //if attachment exists
        //header
        $headers = "MIME-Version: 1.0\r\n";
        $headers .= "From:".$from_email."\r\n";
        $headers .= "Reply-To: ".$sender_email."" . "\r\n";
        $headers .= "Content-Type: multipart/mixed; boundary = $boundary\r\n\r\n";
       
        //message text
        $body = "--$boundary\r\n";
        $body .= "Content-Type: text/plain; charset=ISO-8859-1\r\n";
        $body .= "Content-Transfer-Encoding: base64\r\n\r\n";
        $body .= chunk_split(base64_encode($message));

        //attachments
        for ($x = 0; $x < $file_count; $x++){      
            if(!empty($attachments['name'][$x])){
               
                if($attachments['error'][$x]>0) //exit script and output error if we encounter any
                {
                    $mymsg = array(
                    1=>"The uploaded file exceeds the upload_max_filesize directive in php.ini",
                    2=>"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
                    3=>"The uploaded file was only partially uploaded",
                    4=>"No file was uploaded",
                    6=>"Missing a temporary folder" );
                    print  json_encode( array('type'=>'error',$mymsg[$attachments['error'][$x]]) );
                    exit;
                }
               
                //get file info
                $file_name = $attachments['name'][$x];
                $file_size = $attachments['size'][$x];
                $file_type = $attachments['type'][$x];
               
                //read file
                $handle = fopen($attachments['tmp_name'][$x], "r");
                $content = fread($handle, $file_size);
                fclose($handle);
                $encoded_content = chunk_split(base64_encode($content)); //split into smaller chunks (RFC 2045)
               
                $body .= "--$boundary\r\n";
                $body .="Content-Type: $file_type; name=".$file_name."\r\n";
                $body .="Content-Disposition: attachment; filename=".$file_name."\r\n";
                $body .="Content-Transfer-Encoding: base64\r\n";
                $body .="X-Attachment-Id: ".rand(1000,99999)."\r\n\r\n";
                $body .= $encoded_content;
            }
        }

    }else{ //send plain email otherwise
       $headers = "From:".$from_email."\r\n".
        "Reply-To: ".$sender_email. "\n" .
        "X-Mailer: PHP/" . phpversion();
        $body = $message;
    }
       
    $sentMail = mail($recipient_email, $subject, $body, $headers);
    if($sentMail) //output success or failure messages
    {      
        print json_encode(array('type'=>'done', 'text' => 'Thank you for your email'));
        exit;
    }else{
        print json_encode(array('type'=>'error', 'text' => 'Could not send mail! Please check your PHP mail configuration.'));  
        exit;
    }
}

That’s it, you can just download the sample file and start testing out the script, but I can’t show you the demo because it involves file uploading, you can try out the other demo here which works exactly same but without file uploading feature. Good luck!

Download

  1. after submition when mail arive it doesnot contain name and no. pl slove ,otherwise fab

     Reply
  2. Hi I’ve implemented your code for my website form, but I’m getting a parse error when passing jquery data via FormData.. Any ideas why it’s so?
    SyntaxError: Unexpected end of JSON input

     Reply
  3. I want to change the file type and file size….
    How to implement???
    My need is mp4, avi, mpeg format and minimum 10mb size
    Help me!!!

     Reply
  4. christophe fongemie

    Hello
    Is it possible to add a loader when files are uploading ?

     Reply
  5. What is the md5(sanwebe.com), and what purpose does it serve?

     Reply
  6. I have tried to implement your script on the server but when it sends text message it appears to be in unreadable characters like: 1ë,j ’H ]™H \ ÜÚ] Y [Û™^H [ È H ™\]Y\Ý Y XØÛÝ[

     Reply
  7. Mohammad Nishat

    what if we need more than one file input? in form?

     Reply
  8. hello nice work very thankful for that work :)

    I’m new and trying to dublicate the attachment, I need 5 attachments in that form but i’m not able to do that,
    please help me with that .

     Reply
  9. Thank you very much, it worked!

     Reply
  10. Thank you, so helpful! Exactly what I needed!

     Reply
  11. I also would like to solve multiple-files sending function. Please contact me and I will message you with detailed issue instructions. Thanks!

     Reply
  12. Hi,
    I was wondering if you can help me to solve a JQuery, AJAX, PHP multiple attachment issue. Here is what I have done so far:
    1. completed all the JQUERY, AJAX, and PHP code to process the FORM fields for a single attachment, which deals with uses the FormData() to append the file input info into (m_data.append( ‘userfile’, $(‘input[name=userfile]’)[0].files[0]);). This step works with the $.ajax({
    url: “././form/attach.php”, data: m_data, processData: false, contentType: false, type: ‘POST’, … etc… that is then able to decode in PHP, utilizing the $_FILES super global parameter.
    However, if I am loading multiple files with a file type array, I am unable to properly push the array into the ForData() that I am using with ajax. I am able to test and do verify that the array has the names of all the files, but on the PHP side, the $_FILES is empty…
    So, I am stuck with using a direct php code inside the form page, which is not the approach that I would like to implement.

    Thank you for your support.

     Reply
  13. I like your attachment form tutorial and got it to work for my client requests. I was trying to get the other tutorial with multiple attachments working but I am unable to figure-out how to get the ajax and php to work together to get the array and process / attach the files from the form.

    Would you be able to provide a little guidance on the JQuery portion that append the attachments array for processing on the PHP side?

    Thanks for your great work.

     Reply
  14. How I do if I want to pass multiple checkboxes? Help me plesase.

     Reply
  15. Hello
    Can u show us how can we add more file upload with ajax query & php
    i just have see the other tutorial http://www.sanwebe.com/2015/12/php-mail-with-multiple-attachments but it’s not the same
    because it’s not the same php code and no ajax so when i try to adapt the form, the message doesn’t send
    Can someone help me please ?

     Reply
Message Type : Question Comment ?
  • Question : Can include code, jsFiddle, codePen etc using Markdown Syntax.
  • Comment : Short comments and questions.