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.
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
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.
<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:
<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