Adding a reply address safely to PHP mail()

Created: 15 October 2013

One of the most common techniques used with the PHP mail() function is to drop the user-submitted email address into a From header. It's popular because it means you can reply directly to the sender just by clicking the Reply button in your email program. What many people fail to understand is that it's also extremely insecure, and exposes your contact form to a malicious exploit known as email header injection, which can turn your site into a spam relay.

Fortunately, the solution is very simple. All you need to do is to check that the user-submitted value is in the correct format for an email address. If it isn't, reject the message.

The following code example uses the filter_input() function, which requires a minimum of PHP 5.2. If your remote server is running an older version of PHP, it's time to move to a different server.

A simple PHP mail() script

This script assumes you have a form that contains input fields called name, email, and comments; and that it has a submit button called send.

<?php if (isset($_POST['send'])) { // validate the email address first $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); // process the form only if the email is valid if ($email) { $to = 'me@example.com'; // where you want to send the mail $from = 'webmaster@example.com'; // a valid address on your domain $subject = 'Comment form'; $message = 'From: ' . $_POST['name'] . "\r\n\r\n"; $message .= 'Comments: ' . $_POST['comments']; $headers = "From: $from\r\nReply-to: $email"; $sent = mail($to, $subject, $message, $headers); if ($sent) { $result = 'Your message has been sent.'; } } else { $result = 'Sorry, there was a problem.'; } } ?>

The filter_input() function takes three arguments:

Both constants are case-sensitive. If the user-submitted data is in the correct format for an email address, the value is stored in $email. If it's invalid, $email is FALSE.

There's no point in going any further if the email address is invalid, so the rest of the processing script is wrapped in a conditional statement.

If the email address is in a valid format, it's safe to insert into the headers. But using the From header is incorrect, and could result in the mail being rejected. The From header indicates where the email is coming from. In this case, it's coming from your web server, so $from needs to be a valid address on your domain.

In order to reply to whoever submitted the form, the script adds the user's email address to the Reply-to header.

Email headers need to be separated by a carriage return and newline character, so the following line creates both headers ready for passing to mail() as the fourth argument:

$headers = "From: $from\r\nReply-to: $email";

The script stores the outcome in a variable called $result, which can be displayed in your page to inform the user what has happened.

Using the fifth argument to mail()

Many hosting companies now require the use of the fifth argument to mail() to ensure that the message originates from a legitimate source. If email from your contact form fails to arrive, check whether this restriction applies to your hosting company.

Normally, the fifth argument is a string beginning with -f followed immediately by a valid email address on your domain. For example, adding an email address called info@example.com as the fifth argument looks like this:

$sent = mail($to, $subject, $message, $headers, '-finfo@example.com');

Other Tutorials

Programming tutorials

Articles on Adobe.com

Over the years, I have contributed a large number of articles to the Adobe Developer Connection and Community publishing. Most of the articles are now in the Adobe archive because they refer to old versions of Dreamweaver. But the following articles are not Dreamweaver-specific and are still relevant.

Books & Videos by David Powers

PHP SolutionsBeginning CSS3Dreamweaver CS6: Learn by VideoDreamweaver CS5.5: Learn by VideoDreamweaver CS5.5 for MobileDreamweaver CS5 with PHP