What we’ll want to do is:
- Build a simple HTML contact form (with optional CSS) and embed it on our website.
- Write a PHP script that will effectively handle sending emails.
- Save the inserted details into a spreadsheet.
- Send an autoresponder to a user, letting them know we’ll handle their request.
We’ll also explain how to secure the form with reCaptcha, validate emails, and handle common errors. So, let’s begin.
Building a Simple PHP Contact Form
For starters, we’ll need to build a simple form with just HTML. If you don’t care much about the visual side of it, it can be as simple as this:
<form>
<h2>Contact us</h2>
<p><label>First Name:</label> <input name="myEmail" type="text" /></p>
<p><label>Email Address:</label> <input style="cursor: pointer;" name="myEmail" type="text" /></p>
<p><label>Message:</label> <textarea name="message"></textarea> </p>
<p><input type="submit" value="Send" /></p>
</form>
Of course, without any CSS, it doesn’t look pleasant:
But it will be just fine for demonstration purposes. If you’re not into writing CSS at the moment, you can use any of the hundreds of available form builders. Some options include Simfatic, 123FormBuilder, and PHP Jabbers. CodeCanyon has hundreds of tools with reviews for each to make a choice easier.
Okay, we’ve got the contact form, but whatever data users insert goes straight into a black hole. So, we’ll need to add two more elements to the form–ACTION and METHOD. ACTION tells the browser what to do when a user hits the ‘Send’ button. METHOD tells it how to approach this move.
In our case, we’ll want to load a new PHP page in the background, which we’ll discuss in the next chapter. Since we’ll be processing the data, we’re legally obliged to protect the user’s details (name and email address), making the POST method a safer option. Using GET would mean these details get included in the URL of the following page, something we’d rather avoid.
All we need to do now is include these two attributes in the code we previously used:
<form method="POST" action="form.php" id="contact-form">
<h2>Contact us</h2>
<p><label>First Name:</label> <input name="name" type="text" /></p>
<p><label>Email Address:</label> <input style="cursor: pointer;" name="email" type="text" /></p>
<p><label>Message:</label> <textarea name="message"></textarea> </p>
<p><input type="submit" value="Send" /></p>
</form>
Data Validation
To get rid of some spammers and protect your users from accidentally mistyping their contact details, it’s worth adding some validation algorithms to the contact form. For the highest chance of success, consider doing this on both the client- and server side.
Client-side validation will quickly return any errors on the front end, letting a user fix them immediately. Server-side validation will also catch those that passed the initial test (for example, disabling JavaScript in the browser) but shouldn’t have.
While you can write your own script, it’s often worth using what’s already been built and tested. We will use a bulletproof solution for schema validation. For simplicity, add a library from a CDN.
<script src="http://cdnjs.cloudflare.com/ajax/libs/validate.js/0.13.1/validate.min.js"></script>
<script>
const constraints = {
name: {
presence: { allowEmpty: false }
},
email: {
presence: { allowEmpty: false },
email: true
},
message: {
presence: { allowEmpty: false }
}
};
const form = document.getElementById('contact-form');
form.addEventListener('submit', function (event) {
const formValues = {
name: form.elements.name.value,
email: form.elements.email.value,
message: form.elements.message.value
};
const errors = validate(formValues, constraints);
if (errors) {
event.preventDefault();
const errorMessage = Object
.values(errors)
.map(function (fieldValues) { return fieldValues.join(', ')})
.join("n");
alert(errorMessage);
}
}, false);
</script>
For the server-side validation, you can use the following code:
<?php
$errors = [];
if (!empty($_POST)) {
$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];
if (empty($name)) {
$errors[] = 'Name is empty';
}
if (empty($email)) {
$errors[] = 'Email is empty';
} else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Email is invalid';
}
if (empty($message)) {
$errors[] = 'Message is empty';
}
}
If either verification doesn’t work, please let the user know. You can use the following code to build an error message:
}” data-lang=””>
<?php
if (!empty($errors)) {
$allErrors = join('<br/>', $errors);
$errorMessage = "<p style="color: red;">{$allErrors}</p>";
}
You are free to render this message anywhere on your page.
PHP Code to Send Email From a Contact Form
Our form is leading somewhere, but it’s not clear where. Let’s add some action points and use the default mail() function to send a simple email after submission.
The code of this PHP contact form specifies the headers and body of a message and sends each email with the mail() method. It also includes the validations we explained in the previous chapter and the HTML form itself.
$bodyParagraphs = [“Name: {$name}”, “Email: {$email}”, “Message:”, $message];
$body = join(PHP_EOL, $bodyParagraphs);
if (mail($toEmail, $emailSubject, $body, $headers)) {
header(‘Location: thank-you.html’);
} else {
$errorMessage=”Oops, something went wrong. Please try again later”;
}
} else {
$allErrors = join(‘
‘, $errors);
$errorMessage = “
{$allErrors}
“;
}
}
?>
” data-lang=””>
<?php
$errors = [];
$errorMessage="";
if (!empty($_POST)) {
$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];
if (empty($name)) {
$errors[] = 'Name is empty';
}
if (empty($email)) {
$errors[] = 'Email is empty';
} else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Email is invalid';
}
if (empty($message)) {
$errors[] = 'Message is empty';
}
if (empty($errors)) {
$toEmail="example@example.com";
$emailSubject="New email from your contant form";
$headers = ['From' => $email, 'Reply-To' => $email, 'Content-type' => 'text/html; charset=iso-8859-1'];
$bodyParagraphs = ["Name: {$name}", "Email: {$email}", "Message:", $message];
$body = join(PHP_EOL, $bodyParagraphs);
if (mail($toEmail, $emailSubject, $body, $headers)) {
header('Location: thank-you.html');
} else {
$errorMessage="Oops, something went wrong. Please try again later";
}
} else {
$allErrors = join('<br/>', $errors);
$errorMessage = "<p style="color: red;">{$allErrors}</p>";
}
}
?>
<html>
<body>
<form action="/mail_form.php" method="post" id="contact-form">
<h2>Contact us</h2>
<?php echo((!empty($errorMessage)) ? $errorMessage : '') ?>
<p>
<label>First Name:</label>
<input name="name" type="text" value="dima"/>
</p>
<p>
<label>Email Address:</label>
<input style="cursor: pointer;" name="email" value="dima@dima.com" type="text"/>
</p>
<p>
<label>Message:</label>
<textarea name="message">dima</textarea>
</p>
<p>
<input type="submit" value="Send"/>
</p>
</form>
<script src="http://cdnjs.cloudflare.com/ajax/libs/validate.js/0.13.1/validate.min.js"></script>
<script>
const constraints = {
name: {
presence: { allowEmpty: false }
},
email: {
presence: { allowEmpty: false },
email: true
},
message: {
presence: { allowEmpty: false }
}
};
const form = document.getElementById('contact-form');
form.addEventListener('submit', function (event) {
const formValues = {
name: form.elements.name.value,
email: form.elements.email.value,
message: form.elements.message.value
};
const errors = validate(formValues, constraints);
if (errors) {
event.preventDefault();
const errorMessage = Object
.values(errors)
.map(function (fieldValues) {
return fieldValues.join(', ')
})
.join("n");
alert(errorMessage);
}
}, false);
</script>
</body>
</html>
If the PHP contact form returns error 500, double-check to see if you specified the parameters of the mail() function properly. Make sure the mail server is properly configured on your machine.
The mail() function doesn’t support external SMTP servers, which is a serious bottleneck. As emails are sent from your own servers rather than those of reputable ESPs (Email Sending Providers), they will frequently go to spam.
PHP contact forms, of course, allow for different email methods. The most popular choice for sending emails in PHP is PHPMailer. If you’re unfamiliar with it, we’ve covered it in detail in our PHPMailer Guide.
Here’s how the PHPMailer code would look for this page:
‘, $errors);
$errorMessage = “
{$allErrors}
“;
} else {
$mail = new PHPMailer();
// specify SMTP credentials
$mail->isSMTP();
$mail->Host=”smtp.mailtrap.io”;
$mail->SMTPAuth = true;
$mail->Username=”d5g6bc7a7dd6c7″;
$mail->Password = ’27f211b3fcad87′;
$mail->SMTPSecure=”tls”;
$mail->Port = 2525;
$mail->setFrom($email, ‘Mailtrap Website’);
$mail->addAddress(‘piotr@mailtrap.io’, ‘Me’);
$mail->Subject=”New message from your website”;
// Enable HTML if needed
$mail->isHTML(true);
$bodyParagraphs = [“Name: {$name}”, “Email: {$email}”, “Message:”, nl2br($message)];
$body = join(‘
‘, $bodyParagraphs);
$mail->Body = $body;
echo $body;
if($mail->send()){
header(‘Location: thank-you.html’); // redirect to ‘thank you’ page
} else {
$errorMessage=”Oops, something went wrong. Mailer Error: ” . $mail->ErrorInfo;
}
}
}
?>
” data-lang=””>
<?php
use PHPMailerPHPMailerPHPMailer;
require __DIR__ . '/vendor/autoload.php';
$errors = [];
$errorMessage="";
if (!empty($_POST)) {
$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];
if (empty($name)) {
$errors[] = 'Name is empty';
}
if (empty($email)) {
$errors[] = 'Email is empty';
} else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Email is invalid';
}
if (empty($message)) {
$errors[] = 'Message is empty';
}
if (!empty($errors)) {
$allErrors = join('<br/>', $errors);
$errorMessage = "<p style="color: red;">{$allErrors}</p>";
} else {
$mail = new PHPMailer();
// specify SMTP credentials
$mail->isSMTP();
$mail->Host="smtp.mailtrap.io";
$mail->SMTPAuth = true;
$mail->Username="d5g6bc7a7dd6c7";
$mail->Password = '27f211b3fcad87';
$mail->SMTPSecure="tls";
$mail->Port = 2525;
$mail->setFrom($email, 'Mailtrap Website');
$mail->addAddress('piotr@mailtrap.io', 'Me');
$mail->Subject="New message from your website";
// Enable HTML if needed
$mail->isHTML(true);
$bodyParagraphs = ["Name: {$name}", "Email: {$email}", "Message:", nl2br($message)];
$body = join('<br />', $bodyParagraphs);
$mail->Body = $body;
echo $body;
if($mail->send()){
header('Location: thank-you.html'); // redirect to 'thank you' page
} else {
$errorMessage="Oops, something went wrong. Mailer Error: " . $mail->ErrorInfo;
}
}
}
?>
<html>
<body>
<form action="/swiftmailer_form.php" method="post" id="contact-form">
<h2>Contact us</h2>
<?php echo((!empty($errorMessage)) ? $errorMessage : '') ?>
<p>
<label>First Name:</label>
<input name="name" type="text" value="dima"/>
</p>
<p>
<label>Email Address:</label>
<input style="cursor: pointer;" name="email" value="dima@dima.com" type="text"/>
</p>
<p>
<label>Message:</label>
<textarea name="message">dima</textarea>
</p>
<p>
<input type="submit" value="Send"/>
</p>
</form>
<script src="http://cdnjs.cloudflare.com/ajax/libs/validate.js/0.13.1/validate.min.js"></script>
<script>
const constraints = {
name: {
presence: {allowEmpty: false}
},
email: {
presence: {allowEmpty: false},
email: true
},
message: {
presence: {allowEmpty: false}
}
};
const form = document.getElementById('contact-form');
form.addEventListener('submit', function (event) {
const formValues = {
name: form.elements.name.value,
email: form.elements.email.value,
message: form.elements.message.value
};
const errors = validate(formValues, constraints);
if (errors) {
event.preventDefault();
const errorMessage = Object
.values(errors)
.map(function (fieldValues) {
return fieldValues.join(', ')
})
.join("n");
alert(errorMessage);
}
}, false);
</script>
</body>
</html>
Several other reliable tools can handle the task as well. Check out our guide to sending emails in PHP for more details.
By all means, use mail() for testing, or if getting a contact form response now and then is all you need from mailing functionality. But if you send many transactional emails, it’s worth looking for a more reliable alternative.
To add one more layer of security, you should add a simple reCaptcha script to your PHP mail form. You can do this in a very simple way.
First, head to Google’s site and fill out the form you’ll find there. You can choose between reCaptcha v2 and v3 (v1 is no longer supported). To make it simple, we’ll opt for the former.
ReCaptcha v2 is sent with a form, and we can easily handle it in the backend with the rest of the form fields. ReCaptcha v3, on the other hand, needs to be called manually on the frontend. This is doable but would require us to rewrite the entire code. Let’s leave this for another occasion.
Submit the form, and you’ll see your individual Site Key and Secret Key.
Since we only want to save a few values somewhere, we can populate a Google Sheet with the results. Let’s connect Zapier’s webhooks with a spreadsheet. For a start, don’t forget to specify table columns, which the app will use to recognize where to put data sent by our form.
Create a new Zap that will connect the webhook and spreadsheets, following the instructions in Zapier. They are super clear so that you can figure it out on your own. In the app, your Zap will look like this.
You can use this code to send a request to Zapier and see how your spreadsheet is populating after each form submission.
Do you sometimes wonder if a contact form is a right approach to email obfuscation? There could be more reliable approaches to filtering out spammers and making life easier for our users by providing constant support. We discuss various approaches to the problem in our article on email obfuscation.