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.
HTML
  • 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_form" 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="number" name="phone1" maxlength="3" placeholder="+91" />— <input type="number" name="phone2" maxlength="15" data-required="true"/> </label> <label><span>Attachment</span> <input type="file" name="file_attach[]" multiple/> </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> </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.
jQuery
  • 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
var allowed_file_size = "1048576"; //1 MB allowed file size var allowed_file_types = [ 'image/png', 'image/gif', 'image/jpeg', 'image/pjpeg', 'application/x-zip-compressed', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ]; //Allowed file types var border_color = "#C2C2C2"; //initial input border color var maximum_files = 2; //Maximum number of files allowed $("#contact_form").submit(function(e){ e.preventDefault(); //prevent default action proceed = 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-\.][email protected]([\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 all modern browsers if(window.File && window.FileReader && window.FileList && window.Blob){ var total_files_size = 0; if(this.elements['file_attach[]'].files.length > maximum_files){ alert( "Can not select more than "+maximum_files+" file(s)"); proceed = false; } $(this.elements['file_attach[]'].files).each(function(i, ifile){ if(ifile.value !== ""){ //continue only if file(s) are selected if(allowed_file_types.indexOf(ifile.type) === -1){ //check unsupported file alert( ifile.name + " is not allowed!"); 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; } } 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); //Creates new FormData object //if everything's ok, continue with Ajax form submit if(proceed){ $.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>"); } }); } }); </script>
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.
PHP
  • 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 = "[email protected]"; //recepient $from_email = "[email protected]_domain.com"; //from email using site domain. 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, exit outputting json string if(strlen($sender_name)<4){ 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(!$phone_number){ //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"); //construct a message body to be sent to recipient $message_body = "Message from $sender_name\n"; $message_body .= "------------------------------\n"; $message_body .= "$message\n"; $message_body .= "------------------------------\n"; $message_body .= "$sender_name\n"; $message_body .= "$sender_email\n"; $message_body .= "$country_code$phone_number\n"; 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_body)); //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_body; } $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
  • Drew
    Hello. The contact form worked fine when I would use it on my localhost server. When I made my website live, however, I get an error message saying "Couldn't send mail. Check PHP configuration." Is there something I need to change in the code for when your using it on a live website?
    • san
      • 1
      • 2
      $msg = "the test message"; mail("[email protected]","My subject",$msg);
      If you can't send this simple message, there's probably something wrong with your mail configuration. Try contacting host or the alternative https://github.com/PHPMailer/PHPMailer
  • Denis
    OMG !!! Thanks you very much! I searching something like this to long and finally find this ! God bless you !)