Contact Form - PHP

Bootstrap 5 Contact Form with PHP

This is a step-by-step guide tutorial on how to easily create beautiful contact forms using the Bootstrap framework, PHP and JavaScript. It also covers validation of data, sending requests using AJAX and other form related topics.

Contact Form integration build with the latest Bootstrap 5 and PHP. Plenty of implementation examples such as frontend validation and clear installation tutorials.

For creating Contact Forms using NodeJS environment please follow the link

Final code for examples of this tutorial you can find inside integrations folder of the MDB Advanced package


Form HTML

First, create basic contact form which will be our base for validating and sending data.

Within this tutorial we are using the Material Design for Bootstrap library, you can download it for free from here. Without the library, the form will still work — however it may look and behave differently. It's recommended to use this library along with the tutorial.

Contact us

Copy and paste the following HTML and JavaScript code into your file (e.g. index.html):

        
            
          <form id="contact-form" action="mail.php" method="POST">
            <h2>Contact us</h2>

            <!-- Name input -->
            <div class="form-outline mb-4">
              <input type="text" id="name" name="name" class="form-control" />
              <label class="form-label" for="name">Name</label>
            </div>

            <!-- Email input -->
            <div class="form-outline mb-4">
              <input type="email" id="email" name="email" class="form-control" />
              <label class="form-label" for="email">Email address</label>
            </div>

            <!-- Subject input -->
            <div class="form-outline mb-4">
              <input type="text" id="subject" name="subject" class="form-control" />
              <label class="form-label" for="subject">Subject</label>
            </div>

            <!-- Message input -->
            <div class="form-outline mb-4">
              <textarea class="form-control" id="message" name="message" rows="4"></textarea>
              <label class="form-label" for="message">Message</label>
            </div>

            <!-- Submit button -->
            <button id="submit-form" type="submit" class="btn btn-primary btn-block mb-4">
              Send
            </button>
          </form>
        
        
    

Create PHP file

Create a new file called mail.php within the same folder as the contact form and place within it the following code:

        
            

          <?php
          $name    = (isset($_POST['name'])) ? $_POST['name'] : '';
          $email   = (isset($_POST['email'])) ? $_POST['email'] : '';
          $message = (isset($_POST['message'])) ? $_POST['message'] : '';
          $subject = (isset($_POST['subject'])) ? $_POST['subject'] : '';

          $content    = "From: $name \n Email: $email \n Message: $message";
          $recipient  = "youremail@here.com";

          $mailheader = array(
            'From' => $email,
            'Content-Type' => 'text/html;charset=UTF-8',
          );
          mail($recipient, $subject, $content, $mailheader) or die("Error!");
          echo "Email sent!";
          ?>

        
        
    

Now just replace youremail@here.com with your email address and it's done. Remember that in order for the script to work you will need to keep it on PHP-supporting server such as Apache.


Frontend validation

Our form now works fine. However currently if the user makes a mistake by clicking send without filling in the form first, this will result in sending an empty email. The other potential problem is that user might make a mistake in his email address so he would never get a response from us.

MDB Validation

MDBootstrap form components provide built-in validation which can be used to validate user data before sending email via PHP script. Read more about MDBootstrap form validation here.

In the example below all inputs were marked as required, and JavaScript code enabling custom MDB Form Validation was added.

Contact us

Please provide your name.
Please provide your email.
Please provide mail subject.
Please provide a message text.
        
            
            <form id="mdb-validate-form" action="mail.php" method="POST" class="needs-validation"
              novalidate>
              <h2>Contact us</h2>

              <!-- Name input -->
              <div class="form-outline mb-4">
                <input type="text" id="name" name="name" class="form-control" />
                <label class="form-label" for="name">Name</label>
                <div class="invalid-feedback">
                  Please provide your name.
                </div>
              </div>

              <!-- Email input -->
              <div class="form-outline mb-4">
                <input type="email" id="email" name="email" class="form-control" />
                <label class="form-label" for="email">Email address</label>
                <div class="invalid-feedback">
                  Please provide your email.
                </div>
              </div>

              <!-- Subject input -->
              <div class="form-outline mb-4">
                <input type="text" id="subject" name="subject" class="form-control" />
                <label class="form-label" for="subject">Subject</label>
                <div class="invalid-feedback">
                  Please provide mail subject.
                </div>
              </div>

              <!-- Message input -->
              <div class="form-outline mb-4">
                <textarea class="form-control" id="message" name="message" rows="4"></textarea>
                <label class="form-label" for="message">Message</label>
                <div class="invalid-feedback">
                  Please provide a message text.
                </div>
              </div>

              <!-- Submit button -->
              <button type="submit" class="btn btn-primary btn-block mb-4">
                Send
              </button>
            </form>
          
        
    
        
            
            (() => {
              'use strict';

              const forms = document.querySelectorAll('.needs-validation');

              Array.prototype.slice.call(forms).forEach((form) => {
                form.addEventListener('submit', (event) => {
                  if (!form.checkValidity()) {
                    event.preventDefault();
                    event.stopPropagation();
                  }
                  form.classList.add('was-validated');
                }, false);
              });
            })();
          
        
    

Custom Validation

If you don't want to use MDB default validation and want to create your own functionality instead, you have to change the behavior of the form submission. So first change the existing code in our JavaScript

        
            

            submitButton.addEventListener('click', function(){
              document.getElementById('contact-form').submit()
            };

          
        
    

with the following code, which instead of directly submitting the form will call our validation function:

        
            

            submitButton.addEventListener('click', validateForm);

          
        
    

Now we have to create our validation function. Example of the form with the custom validation function could be looking like this:

Contact us

        
            
              <form id="custom-validate-form" action="mail.php" method="POST" class="needs-validation"
                novalidate>
                <h2>Contact us</h2>

                <!-- Name input -->
                <div class="form-outline mb-4">
                  <input type="text" id="name" name="name" class="form-control" />
                  <label class="form-label" for="name">Name</label>
                  <div class="invalid-feedback">
                    Please provide your name.
                  </div>
                </div>

                <!-- Email input -->
                <div class="form-outline mb-4">
                  <input type="email" id="email" name="email" class="form-control" />
                  <label class="form-label" for="email">Email address</label>
                  <div class="invalid-feedback">
                    Please provide your email.
                  </div>
                </div>

                <!-- Subject input -->
                <div class="form-outline mb-4">
                  <input type="text" id="subject" name="subject" class="form-control" />
                  <label class="form-label" for="subject">Subject</label>
                  <div class="invalid-feedback">
                    Please provide mail subject.
                  </div>
                </div>

                <!-- Message input -->
                <div class="form-outline mb-4">
                  <textarea class="form-control" id="message" name="message" rows="4"></textarea>
                  <label class="form-label" for="message">Message</label>
                  <div class="invalid-feedback">
                    Please provide a message text.
                  </div>
                </div>

                <!-- Submit button -->
                <button id="custom-validation-button" type="submit" class="btn btn-primary btn-block mb-4">
                  Send
                </button>

                <!-- Status message -->
                <div id="status"></div>
              </form>
            
        
    
        
            

              submitButton.addEventListener('click', (e) => {
                e.preventDefault();
                const {isDataValid, statusMessage} = validateForm();

                if (!isDataValid) {
                  document.getElementById('status').innerHTML = statusMessage;
                  return;
                }

                document.getElementById('status').innerHTML = `<p class="note note-success">Sending...</p>`;
                document.getElementById('custom-validate-form').submit();
              });

              function validateForm() {
                let isDataValid = true;
                let statusMessage = '';

                const name = document.getElementById('custom-validation-name').value;
                if (name === "") {
                  statusMessage += `<p class="note note-danger"><strong>Name</strong> cannot be empty</p>`;
                  isDataValid = false;
                };

                const email = document.getElementById('custom-validation-email').value;
                if (email === "") {
                  statusMessage += `<p class="note note-danger"><strong>Email</strong> cannot be empty</p>`;
                  isDataValid = false;
                } else {
                  const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<p>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

                  if(!re.test(email)){
                    statusMessage += `<p class="note note-danger"><strong>Email</strong> is invalid</p>`;
                    isDataValid = false;
                  }
                }

                const subject = document.getElementById('custom-validation-subject').value;
                if (subject === "") {
                  statusMessage += `<p class="note note-danger"><strong>Subject</strong> cannot be empty</p>`;
                  isDataValid = false;
                }
                const message = document.getElementById('custom-validation-message').value;
                  if (message === "") {
                  statusMessage += `<p class="note note-danger"><strong>Subject</strong> cannot be empty</p>`;
                  isDataValid = false;
                }

                return {isDataValid, statusMessage};
              }
            
        
    

Server-side validation

Since user can easily disable Javascript on his side, it's very important to also validate the submitted form on the server side. In order to add similar validation as we did in the previous point, update the mail.php file by adding the following code:

        
            

          <?php
          $name    = (isset($_POST['name'])) ? $_POST['name'] : '';
          $email   = (isset($_POST['email'])) ? $_POST['email'] : '';
          $message = (isset($_POST['message'])) ? $_POST['message'] : '';
          $subject = (isset($_POST['subject'])) ? $_POST['subject'] : '';

          if ($name === '') {
            die("Name cannot be empty.");
          }
          if ($email === '') {
            die("Email cannot be empty.");
          } else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            die("Email format invalid.");
          }
          if ($subject === '') {
            die("Subject cannot be empty.");
          }
          if ($message === '') {
            die("Message cannot be empty.");
          }

          $content    = "From: $name \n Email: $email \n Message: $message";
          $recipient  = "youremail@here.com";

          $mailheader = array(
            'From' => $email,
            'Content-Type' => 'text/html;charset=UTF-8',
          );
          mail($recipient, $subject, $content, $mailheader) or die("Error!");
          echo "Email sent!";
          ?>

        
        
    

Sending email without reloading the page using AJAX

Our contact form is working correctly, however the user experience leaves much to be desired. Instead of reloading the page, we would like to send contact form on the same page. Let’s replace following JavaScript code

        
            

          form.addEventListener('submit', (e) => {
            e.preventDefault();

            const formData = new FormData(e.target);

            const {isDataValid, statusMessage} = validateForm();

            if (!isDataValid) {
              document.getElementById('status').innerHTML = statusMessage;
              return;
            }

            fetch('mail.php', {
              method: 'POST',
              body: formData
            })
            .then((response) => {
              response.json();
            })
            .then((response) => {
              if (response.code) {
                // If mail was sent successfully, reset the form;
                const values = document.querySelectorAll('.form-control');
                values.forEach( value => {
                  value.textContent = '';
                });

                document.getElementById('status').innerHTML = `<p class="note note-success">${response.message}</p>`;
                setTimeout(()=> {
                  document.getElementById('status').innerHTML = '';
                }, 2000)
              } else {
                document.getElementById('status').innerHTML = `<p class="note note-danger">${response.message}</p>`;
              }
            })
            .catch((err) => {
              document.getElementById('status').innerHTML = `<p class="note note-danger">An unexpected error occured. Please try again</p>`;
            });
          });

        
        
    

We also need to adjust our PHP code. Instead of sending a simple string with the message, we will send a slightly more complex object which will contain both status and the message. If everything goes fine and the email was successfully sent. We will return status 1 and clean our form to make sure that user does not send it multiple times. In case of validation errors we will return 0 and keep the data within the form.

        
            
          <?php
          $name    = (isset($_POST['name'])) ? $_POST['name'] : '';
          $email   = (isset($_POST['email'])) ? $_POST['email'] : '';
          $message = (isset($_POST['message'])) ? $_POST['message'] : '';
          $subject = (isset($_POST['subject'])) ? $_POST['subject'] : '';

          header('Content-Type: application/json');
          if ($name === '') {
            $response =  json_encode(array(
              'message' => 'Name cannot be empty',
              'code' => 0
            ));
            die($response);
          }
          if ($email === '') {
            $response =  json_encode(array(
              'message' => 'Email cannot be empty',
              'code' => 0
            ));
            die($response);
          } else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $response =  json_encode(array(
              'message' => 'Email format invalid.',
              'code' => 0
            ));
            die($response);
          }
          if ($subject === '') {
            $response =  json_encode(array(
              'message' => 'Subject cannot be empty',
              'code' => 0
            ));
            die($response);
          }
          if ($message === '') {
            $response =  json_encode(array(
              'message' => 'Message cannot be empty',
              'code' => 0
            ));
            die($response);
          }

          $content    = "From: $name \n Email: $email \n Message: $message";
          $recipient  = "youremail@here.com";

          $mailheader = array(
            'From' => $email,
            'Content-Type' => 'text/html;charset=UTF-8',
          );
          mail($recipient, $subject, $content, $mailheader) or die("Error!");
          $response =  json_encode(array(
            'message' => 'Email successfully sent!',
            'code' => 1
          ));
          die($response);
          ?>

        
        
    

Anti-spam

Once you create your contact form it's worth adding an anti spam mechanism. Unfortunately, there are hundreds of thousands of spambots browsing the Internet every second looking for unsecured forms and submitting them. How they work? They simply fill typical inputs like name or email and automatically submit the form. In the best case you will get occasional frustrating spam messages. In worst they can bring down your website by submitting the contact form hundreds of times a second.

The simplest (but also the weakest) way to secure a contact form is to add a custom field, then ask the customer to fill it in a certain way, and submit the form only if the entered value is correct. Real humans will easily perform this task, but bots most probably won't be able to pass the check.

Other questions

  • Q: How many eyes does a typical person have? (ex: 1) A: 2
  • Q: How many legs on a typical dog? (ex: 5) A: 4
  • Q: How many units in a dozen? (ex: 11) A: 12
  • Q: Name of the actor Di Caprio? (ex: Rafaelo) A:Leonardo
  • Q: How many days in a week? (ex: 8) A: 7
  • Q: How many days in July? (ex: 28) A: 31

If you want a more sophisticated solution read about Google's reCAPTCHA service


Other inputs

We've already used text inputs as well as the text area for larger pieces of text but there are yet more useful input types we can use to enhance our contact form.

Checkbox

        
            
            <div class="form-check">
              <input type="checkbox" class="form-check-input" name="updates" id="updates" value="1">
              <label for="updates" class="form-check-label">Notify me about new updates</label>
            </div>
          
        
    
        
            
            submitButton.addEventListener('click', (e) => {
              e.preventDefault();

              const form = document.querySelector('form');
              const data = new FormData(form);

              form.submit();
            });
          
        
    
        
            
            $updates = if(isset( $_POST['updates'])) ? $_POST['updates'] : '';
          
        
    

Multiple checkboxes

How did you get to know about us?
        
            
            <h5 class="h5 mb-3">How did you get to know about us?</h5>

            <div class="form-check">
                <input type="checkbox" class="form-check-input" name="channel[]" id="checkbox1" value="nl">
                <label for="checkbox1" class="form-check-label">Newsletter</label>
            </div>

            <div class="form-check">
                <input type="checkbox" class="form-check-input" name="channel[]" id="checkbox2" value="ad">
                <label for="checkbox2" class="form-check-label">Advertisement</label>
            </div>

            <div class="form-check">
                <input type="checkbox" class="form-check-input" name="channel[]" id="checkbox3" value="ot">
                <label for="checkbox3" class="form-check-label">Other</label>
            </div>
          
        
    
        
            
            submitButton.addEventListener('click', (e) => {
              e.preventDefault();

              const form = document.querySelector('form');
              const data = new FormData(form);

              form.submit();
            });
          
        
    
        
            
            if(isset( $_POST['channel'])){
              foreach ($_POST['channel'] as $value) {
                //loop through all checked checkboxes and do logic
              }
            }
          
        
    

Radio/Option buttons

What is your preferred contact method?
        
            
            <h5 class="h5 mb-3">What is your preferred contact method?</h5>

            <div class="form-check mb-4">
                <input class="form-check-input" type="radio" id="radio1" name="cmethod" value="phone" checked>
                <label class="form-check-label" for="radio1">Phone</label>
            </div>

            <div class="form-check mb-3">
                <input class="form-check-input" type="radio" id="radio2" name="cmethod" value="mail">
                <label class="form-check-label" for="radio2">Email</label>
            </div>

            <div class="form-check mb-3">
                <input class="form-check-input" type="radio" id="radio3" name="cmethod" value="post">
                <label class="form-check-label" for="radio3">Post</label>
            </div>
          
        
    
        
            
            submitButton.addEventListener('click', (e) => {
              e.preventDefault();

              const form = document.querySelector('form');
              const data = new FormData(form);

              form.submit();
            });
          
        
    
        
            
            $updates = if(isset( $_POST['cmethod'])) ? $_POST['cmethod'] : '';