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
123456789101112131415161718192021222324252627

<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" />&mdash;
		<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>&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.

JQUERY
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475

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-\.]+@([\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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107

<?php
$recipient_email    = "[email protected]"; //recepient
$from_email         = "info@your_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