How to Send Email from an HTML Contact Form

Implementing Sendmail and PHPMailer

by Tibor Kopca Date: 10-05-2021 PHP JavaScript programming sendmail PHPMailer web development


In today’s article we will write about how to make a working form that upon hitting that submit button will be functional and send the email (to you as a web creator and to the user or customer as well).
If you’re a PHP developer, there's a high probability that you can't avoid having to send or process emails. Functional form on your site is one of the basic needs or standards nowadays. If you don't have a form on your website, you could be missing out on more leads, potential customers or just simply subscribers, with added benefit of security.

Prerequisites


Knowledge of HTML, CSS, JavaScript and it won't hurt if you know a bit of PHP.
Also for PHP code to work, we will test the functionality on XAMPP, this could be omitted if you would upload the code to the web host upon every change, so the host would be the one running PHP, this way it is possible to work in a kinda ‘live’ environment.
(Note: when we’re running XAMPP, it is run under admin rights, by clicking right mouse and choosing this option.)
We assume that you have an existing Gmail account for the testing of this code, and that you will use Gmail’s SMTP server to transmit email.

Sendmail_xampp


Basic form

This code will create a really basic form that asks for the contact's name, email, both with a maximum length of 40 characters,  message upto 500 characters, and a submit button. For a more comprehensive one, we'll have to add some more lines of code, but that we will do later.
Also this code is rather non-functional - it doesn't send directly to email address, but it opens an email client window to submit the form, so the input field for email we just asked to be filled by the user is pretty much useless.
(Note: this is similar to HTML <address> Tag with syntax <a href=”mailto:[email protected]”>John Doe</a> )

Sendmail_Plain_html

PHP code - Server Side Handling


So to make the magic happen, we assume that your website will have some working PHP server, even local or live host.

method="POST"
This determines how the form data is submitted to the server, there are two ways to do this, POST or GET. We will use POST so the filled data in form will be sent “behind the scenes” and they won't appear in our URL as they would with GET. So NEVER use GET to send sensitive data as the submitted form data is visible in the URL!
POST has no size limitations, and can be used to send large amounts of data.
accept-charset="utf-8"

Action parameter will determine where the filled data will be sent to, this will be a new file we create in file structure. Choose the name of the file whatever you want, for example subscribersform.php, in our case we will name it sendmail.php.


This could be even the same page we started on - index.html with php code before all the HTML code and renamed to index.php. This would work the same way.
What happens here is by having sendmail.php in the action parameter, after hitting submit, the code will send the form data to sendmail.php where it will be captured.
If we write our code like the one below, it would redirect us to that file - effectively launching another webpage.

<form class="" accept-charset="utf-8" action="sendmail.php" method="POST" enctype="multipart/form-data">
  • application/x-www-form-urlencoded - this is the default value, if the enctype is not specified,
  • multipart/form-data is necessary when your users are required to upload a file through the form.
  • text/plain is a valid option, though not recommended as it sends the data without any encoding at all.


Let’s jump to sendmail.php.
Here we put the PHP code which will handle all the action. Now if you want to try already filling the form and hitting submit, you will discover that suddenly you're stuck in this file, so to return to the main page, we write this part of code, putting it always at the end. Also for test purposes, we also print text to console>

<script>
console.info('virtual email sent from sendmail.php.');
//REDIRECT TO THE MAIN PAGE
window.location.href = './index.html';
</script>

Using Sendmail

It's time to write the code that sends us something. A PHP script starts with <?php and ends with ?> .
So we are in sendmail.php right, and we write>

<?php
if($_POST["message"]) {
    mail("[email protected]", "Test subject line", "fictional email body", "From: [email protected]");
}?>

What does this code mean?
First we check if the message was filled and if it is, the code inside IF will execute, effectively launching mail( ) function. "mail" sends the completed form as an email to "[email protected]," and the subject line is what follows.

With that, we have the really really basic code, without any validation or security checks, surely we can do better than this.

Now remember that we have input HTML elements in our form right? Every one of the fields we want to process, has a parameter name to it and we will work with those in sendmail.php. Data filled by a user will be converted into a variable with that name from which input it came. For this to work, of course the name parameters need to have unique ‘names’, note that we have only one of each - name=”name”, name=”email”, name=”message” , etc.
As we spoke these variables are all packed in a PHP superglobal variable called $_POST . If you add this to the sendmail.php, upon filling the form, you should see the data that are being submitted.

<?php
echo "<pre>";
    print_r($_POST);
echo "</pre>";
?>

Now we set some variables to break out the $_POST to work with the data. Now we have our code like this>

if($_POST["message"]) {
    $name = $_POST["name"];
    $visitorEmail = $_POST["email"];
    $message = $_POST["message"];
    $OUR_MAIL = '[email protected]';
    
$errors = "";
//NORMAL OPERATION - NO ERRORS        
    if(empty($errors)){
        $EMAIL_SUBJECT = "New Form Contact From " . $name . " @ Your Portfolio Website!";
        $emailBody = "User name: " . $name . "rn".
                     "User email: " . $visitorEmail . "rn".
                     "User message: " . $message . "rn";
 
        $TARGET_EMAIL = "[email protected]";
//HEADERS
        $headers = "From: " . $OUR_MAIL . "rn";
        $headers .= "Reply-To: " . $visitorEmail . "rn";
}}
?>

(Note: rn will do the line break - the line structured text)
For now, we don't have any code validation, nor actual mail function, but that is going to change as we show it in the code next. Headers are optional, serve for things like BCC, Reply-To addresses, and things like that.

Mail Function


PHP mail is the built in PHP function that is used to send emails from PHP scripts.

mail($TARGET_EMAIL, $EMAIL_SUBJECT, $emailBody, $headers)
$TARGET_EMAIL is where the message will be sent to.
$OUR_MAIL is the address - email server from where the message will be sent. This is for example a production server where we have hosted our website.


We added resolution of success or failure of the mail function, it will even show the user message according to what is the result. Last thing will be the redirection to the index.html page, effectively refreshing the window.

$success = mail($TARGET_EMAIL, $EMAIL_SUBJECT, $emailBody, $headers);
//SUCCESS OR FAIL FOR CORRECT TEXT
if ($success){
        ?>
      <script language="javascript" type="text/javascript">
      //REDIRECT TO THE MAIN PAGE or alternatively to 'thank you page'
 alert('Thank you for the message. I will be in contact with you shortly.');
       window.location.href = './index.html';
      </script>
      <?php
} else{
      //mail failed for some reason
      ?>
      <script language="javascript" type="text/javascript">
        alert('Message failed. Please, contact me by an alternative way.');
        window.location.href = './index.html';
      </script>
      <?php
}

Sendmail_gmail_inbox

Sendmail_script_thank_you

XAMPP settings


If you for some reason see this message - Failed to connect to mailserver at “localhost”.. , now we will give you some hints on how to resolve this issue.

Sendmail_PHP_Fail

PHP must be configured correctly in the php.ini file with the details of how your system sends email.
Open php.ini file in XAMPP directory and find the section headed [mail function].


Windows users should ensure that the directive called SMTP that defines your email server address is set to the SMTP = smtp.gmail.com . The second is called sendmail_from which defines your own email address, so that one you need to set to the gmail address EXACTLY like we have $OUR_MAIL variable.


Another important thing is to configure sendmail.ini for email notifications. In PHP.ini locate sendmail_path and replace it with sendmail_path = ""C:xamppsendmailsendmail.exe" -t" . Obviously the drive and path must be pointing to the sendmail.exe, be sure it is.

Sendmail_PHP_ini

Edit the sendmail.ini file in the sendmail subdirectory of your XAMPP installation directory. Inside this file, find the [sendmail] section and replace these lines. The values should be like this>
Smtp_server = smtp.gmail.com
Smtp_port = 465
Smtp_ssl = auto
Error_logfile = error.log
Auth_username = [email protected]
Auth_password = gmail password

After this, restart the Apache server using the XAMPP control panel.


Gmail Email Client

Also as the last advice, using Gmail SMTP server for sending emails works only if you have allowed less secure apps  to access your account(If you don't use 2-Step Verification).
And in settings enable IMAP access.
Sendmail_Google_less_secured_settings

Validate Form Data With PHP

Were almost at the end. The thing is, we might be victims of some malevolence everytime we put any form out there, we might have to have more security set up. Lets focus on the back-end, about how to validate HTML forms we wrote in the other article, there you can get information on how to do the Javascript front-end code.

So we modify yet again our code. Remember we have our code checking for errors but they haven't been captured yet. Now only when no errors exist the code will proceed to mail() function.

//EMPTY SPACE VALIDATION
    if(empty($name) || empty($visitorEmail) || empty($message)){
        $errors .= "n All fields are required";
    }
 
    //NAME VALIDATION
    $string_exp = "/^[A-Za-z .'-]+$/";
    if (!preg_match($string_exp, $name)) {
        $error_message .= "n The Name you entered does not appear to be valid.";
    }
 
    //EMAIL REGEX VALIDATION
    $email_exp = "/^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,3})$/i";
    if (!preg_match($email_exp, $visitorEmail)){
        $errors .= "n Invalid email address";
    }

Sendmail_Pig_user

Good, so far we have validation IF the user submitted the form, and we have validation if there are missing fields or data we don't want. Next we need to get rid of potencial exploits from cross-site scripting(XSS), we must prevent attackers from injecting client-side script into our code.

  • Strip unnecessary characters (extra space, tab, newline) from the user input data (with the PHP trim() function), we also get rid of HTML tags in this one step.
  • Remove backslashes () from the user input data (with the PHP stripslashes() function)
  • By using the htmlspecialchars() this function will convert the special characters into entities to prevent browsers from using it as an HTML elements. This is useful to prevent code from running when we want to do so, for example if the user tries to submit or run his code put in the text field. This doesn't delete the characters, but they won't be handled as HTML code anymore, but as plain text.
    <script>location.href('http://www.facebook.com')</script>
    will become:  
    &lt;script&gt;location.href('http://www.facebook.com')&lt;/script&gt;
     .
  • Lastly we defined a function to replace the empty character of all the unnecessary text we don't want to appear in our mailbox, note that we moved all the text to lowercase for this.

Now, we can check all the incoming data (all our form fields) which we are writing to variables with the test_input() function, and with the function we will strip the data from potentially harming hacker attempts.

//TEST INPUT DATA FOR INJECTION
function testInputData($data){
  $data = strip_tags(trim($data));    //trim extra space, tab, newline from the user input data
  $data = stripslashes($data);        //Remove backslashes () from the user input data
  $data = htmlspecialchars($data);    //data would be saved as HTML escaped code, so safe to display
  $data = preg_replace("([rn])", "", $data); //removes newlines
  $data = cleanString(strtolower($data));      //removing unwanted strings
return $data;
}
 
//Returns empty if encounters any unwanted characters in $inputString
function cleanString($inputString){
  $unwantedChars = array("content-type", "bcc:", "to:", "cc:", "href", "https");
  return str_replace($unwantedChars, "", $inputString);
}
//SEND MAIL CODE
    $name = testInputData($_POST["name"]);
    $visitorEmail = testInputData($_POST["email"]);
    $message = testInputData($_POST["message"]);

PHPMailer


Lets talk about why PHPMailer is better than native PHP mail.


PHPMailer is perhaps the most popular open-source PHP library for sending emails and since its release it has become a PHP developer’s favorite. It is an alternative to PHP mail() function, but with more flexibility for your needs. For instance PHPMailer is object oriented, it can use a non-local mail SMTP server, which is better than mail()s local mail server, it can print error messages when email sending fails. And is also used by popular PHP CMS (content management systems) like WordPress, Drupal, and Joomla.

So we need to go to PHPMailer Github repository and download it as a zip file.
Extract and put files from the src directory of the archive to our application directory to the ‘mail’ folder.

Sendmail_PHPMailer_files
To illustrate how it can be used with our Gmail account, we create totally different script named sendmailphpmailer.php, link it in the index.html instead of sendmail.php and we add this code inside>

<?php
use PHPMailerPHPMailerPHPMailer;
use PHPMailerPHPMailerException;
 
require $_SERVER['DOCUMENT_ROOT'] . '/Portfolio_Tibor/mail/Exception.php';
require $_SERVER['DOCUMENT_ROOT'] . '/Portfolio_Tibor/mail/PHPMailer.php';
require $_SERVER['DOCUMENT_ROOT'] . '/Portfolio_Tibor/mail/SMTP.php';
 
//TEST INPUT DATA FOR INJECTION
function testInputData($data){
    $data = strip_tags(trim($data));
//trim extra space, tab, newline from the user input data
    $data = stripslashes($data);
//Remove backslashes () from the user input data
    $data = htmlspecialchars($data);                    
//data would be saved as HTML escaped code, so safe to display
    $data = preg_replace("([rn])", "", $data);        
//removes newlines
    $data = cleanString(strtolower($data));             
//removing unwanted strings
    return $data;
}
//Returns empty if encounters any unwanted characters in $inputString
function cleanString($inputString){
    $unwantedChars = array("content-type", "bcc:", "to:", "cc:", "href", "https");
    return str_replace($unwantedChars, "", $inputString);
}
 
//_POST VALUES
$name = testInputData($_POST["name"]);
$visitorEmail = testInputData($_POST["email"]);
$message = testInputData($_POST["message"]);
 
$errors = '';
//EMPTY SPACE VALIDATION
if(empty($name) || empty($visitorEmail) || empty($message)){
    $errors .= "n All fields are required.";
}
 
//NAME VALIDATION
$string_exp = "/^[A-Za-z0-9 .'-]+$/";
if (!preg_match($string_exp, $name)) {
    $errors .= "n The Name you entered does not appear to be valid.";
}
 
//EMAIL REGEX VALIDATION
$email_exp = "/^[A-Za-z0-9._%-][email protected][A-Za-z0-9.-]+.[A-Za-z]{2,4}$/";
$email_exp2 = "/^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,3})$/i";
if (!preg_match($email_exp2, $visitorEmail)){
    $errors .= "n Invalid email address.";
}
 
//PHPMailer Object
$mail = new PHPMailer(true);                                                        //Argument true in constructor enables exceptions
 
//SERVER SETTINGS
$mail->isSMTP();
//Send using SMTP
$mail->SMTPDebug  = 0;
//0 = off(for production use)/1 = client messages/2 = client and server messages
$mail->Host       = 'smtp.gmail.com';                       
//Set the SMTP server to send through
//$mail->Host = gethostbyname('smtp.gmail.com');              
//if your network does not support SMTP over IPv6
$mail->SMTPSecure = 'tls';                                  
// ssl is deprecated
$mail->SMTPAuth   = true;                                   
//Enable SMTP authentication
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;         
//Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
$mail->Port       = 587;                                    
//TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
$mail->SMTPOptions = array(
    'ssl' => array(
    'verify_peer' => false,
    'verify_peer_name' => false,
    'allow_self_signed' => true
    )
);
 
//AUTHENTIFICATION
$mail->Username   = '[email protected]';     //SMTP username
$mail->Password   = 'websiteGmailAccountPassword';           //SMTP password
 
//RECIPIENTS
$mail->setFrom('[email protected]', 'Tibor Kopca Portfolio');        
//From email and name
$mail->addAddress("[email protected]", "Recipient : Tibor Kopca");           
//To address and name
$mail->addReplyTo($visitorEmail, "Reply to " . $name );                          
//Address to which recipient will reply
 
//CC and BCC
//$mail->addCC("[email protected]");
$mail->addCC($visitorEmail, $name);                      
//carbon copy to visitor email address
$mail->addBCC('[email protected]');
 
//CONTENT
$mail->isHTML(false);                                                              
//Send HTML or Plain Text email
$mail->Subject = "New Form Contact From " . $name . " @ Your Portfolio Website!";
$mail->AltBody = "This is the plain text version of the email content";    
// If html emails is not supported by the receiver, show this body
$mail->msgHTML("<h2>Thank you for the message. We will contact you shortly.</h2> <br>" .
                "<h3>User name: " . $name . " <br>" .
                "User email: " . $visitorEmail . "<br>" .
                "User message: " . $message . "<h3>" );
 
//ERROR HANDLING AND SEND MAIL
if ($errors) {
//error messages exists - the message shouldnt be send
    echo "Mailer Error: " . $errors;
}else{
    try {
        $mail->send();
        ?>
        <script language="javascript" type="text/javascript">
            alert('Thank you for the message. We will contact you shortly.');
            window.location.href = './index.php?action=message_sent#contact';
        </script>
        <?php
    } catch (Exception $e) {
        echo "Message could not be sent. Mailer Error: " . $mail->ErrorInfo; //can return error messages in 43 different languages.
        ?>
        <script language="javascript" type="text/javascript">
            alert('Message failed. Please, contact me by an alternative way.');
            window.location.href = './index.php?action=message_failed#contact';
            </script>
        <?php
    }
}
?>

Sendmail_PHPMailer_form

Sendmail_PHPMailer_gmail

Note2: at the end we modified the redirection to our index.html with some extra code to pass the content we want in the URL. This way we can catch that content in the page we are going to be redirected. For this to work, we renamed index.html to index.php and we added this code where the HTML form element is. Basically when the message runs successfully, form won't appear again but the message we coded instead.

<div class="container">
   <?php
   $action = isset($_GET['action']) ? $_GET['action'] : "";
   switch ($action) {
       case "message_sent":
           ?><h3>Thank you for the message, I will respond ASAP.</h3><?php
             break;
     case "message_failed":
           ?><h3>Message failed. Please, contact me by an alternative way.</h3><?php
           break;
        default:
          ?><form class="formular" accept-charset="utf-8" action="sendmailPHPMailer.php" method="POST" enctype="multipart/form-data">
          <input type="text" name="name" placeholder="name" maxlength="40" required>
          <input type="email" name="email" placeholder="email" maxlength="40" required>
          <textarea name="message" id="" maxlength="500" name="message" placeholder="message"></textarea>
          <input type="reset" class="button" value="Clear">
          <input type="submit" class="button" value="Send">
          </form>
   <?php } ?>
</div>

And this will be the result when all would run correctly.

Sendmail_thankyou

JavaScript Form Validation


We advise you to also add frontend form validation, because in this article we did not show any. If you want to know how it could be made, that we covered in our other article.

Conclusion


And that’s it! We covered PHP built in mail() function and PHPMailer library as an alternative.
To this subject there is much more to be learned but hopefully in this tutorial we provided the basics of sending emails from your website form.
Next time we’d write about how to implement Whatsapp messenger to our website, so stay tuned.

Main Image by M. H. from Pixabay,
Images and editing by Tibor Kopca

 
by Tibor Kopca Date: 10-05-2021 PHP JavaScript programming sendmail PHPMailer web development hits : 1919  
 
Tibor Kopca

Tibor Kopca

From tinkering with computers as a teenager, through a career in datacenter he stepped into web development with full force and started coding. Absorbs all information like a sponge.
Fan of aerospace, engineering, information technologies and watches.

 
 
 

Related Posts

Difference between arrow and normal functions in JavaScript

In this tutorial we are going to see how arrow functions differ from normal JavaScript functions. We will also see when you should use one and when you should use…

JavaScript Arrow functions: What they are and how to use them

In this article we are going to see what they are and how to use JavaScript Arrow Functions, a new feature introduced with the ES6 standard (ECMAScript 6). What are Arrow…

How to insert an element into an array with JavaScript

In this brief tutorial you will learn how to insert one or more elements into an array with JavaScript. For this we will use the splice function. The splice function will not…

What is the difference between primitives types and objects in JavaScript?

In this short tutorial we are going to look at the differences between primitive types and objects in JavaScript. To start with, we're going to look at what primitive types…

How to get DOM elements with JavaScript

When you access any element of the DOM, it is usual to save it in a variable. This is something that at first might seem very simple, but if you…

How to reverse an array in JavaScript

In this tutorial we are going to see how you can change the order of the elements of an array so that they are inverted. You could use a loop…

How synchronize the scroll of two divs with JavaScript

In case you have two divs of different sizes you may sometimes want to scroll both at the same time but at different speeds depending on their size. For example,…

How to use the codePointAt method in JavaScript

The JavaScript codePointAt method has more or less the same function as the charCodeAt method, used to get the 16-bit Unicode representation of the character at a certain position in…

How to check if a value is a number in JavaScript

In this short tutorial we are going to look at the various methods that exist to find out if a value is a number in JavaScript.   1. Using the isNaN() function   One…

How to use the charCodeAt method in JavaScript

The charCodeAt method is accepted by strings in JavaScript, returning the 16-bit Unicode code of the character at the position we pass as a parameter to the method. The charCodeAt method…

How to use the charAt method in JavaScript

The charAt method is accepted by strings in JavaScript, returning the position of the character passed as a parameter within the string. If the string contains multiple occurrences of the character…

Strings in JavaScript: What they are and how to use them

In this tutorial we are going to explain what strings are and how they are used in JavaScript. The tutorial is intended for people who are learning to program in…

We use our own and third-party cookies to improve our services, compile statistical information and analyze your browsing habits. This allows us to personalize the content we offer and to show you advertisements related to your preferences. By clicking "Accept all" you agree to the storage of cookies on your device to improve website navigation, analyse traffic and assist our marketing activities. You can also select "System Cookies Only" to accept only the cookies required for the website to function, or you can select the cookies you wish to activate by clicking on "settings".

Accept All Only sistem cookies Configuration