Looking for a secure PHP email script
November 16, 2005 3:18 PM   Subscribe

I need a PHP-based email script that will take the name, email, subject, and message form fields I pass to it and send them to me with the name and email used as the "From" field in the message header. I also need to put a value in the header that identifies the sender's IP address. And, of course, I need a script that is not vulnerable to header injection spam attacks. Any recommendations?
posted by punishinglemur to Computers & Internet (7 answers total) 2 users marked this as a favorite
PHP has a built-in mail() function that you can use and supply all sorts of customized headers. Here's the manual page on it.

As to how secure your script is, it depends on how you accept input. If you're accepting it from a FORM post, make sure that the referrer is from your own URL (so, no foreign POST actions). If it's from a GET, do the same, but god help you -- it's the easiest thing to overpower or just get wrong.

To get the sender's IP address, you have to depend on the Server variables from the web request, and then inject that into your custom headers.
posted by thanotopsis at 3:29 PM on November 16, 2005

Is the information in this article not sufficient for you to roll your own simple one? That combined with this tip would likely be sufficient to head off injection issues, though if your mail reader does ROT13 you could always just ROT the subject area...
posted by phearlez at 3:34 PM on November 16, 2005

There are thousands of downloadle scripts online that do just that. Download some and take a look at how they handled it.

Here is one I've used in the past:


posted by meta87 at 3:44 PM on November 16, 2005

Punishinglemur, I'd recommend using PHP's built-in mail() function as well unless you have a lot of tricky stuff going on; in that case, I've had good luck with PHPMailer in a few of my projects. (I'm not too terribly pleased with the pace of development on PHPMailer, though; after finding a few bugs and having my reports of them ignored, I flat-out asked to just get sufficient access to the project and fix them myself, and even that was rebuffed.) Either way, there won't be a way for a web client to inject headers into the email without it either being caused by you allowing their input to get fed into the email as a header or by being a bug in the underlying functions (mail() or PHPMailer's classes), so you're reasonably safe from that.

Thanotopsis, checking referrers is equally insecure; a referrer is as much a user-supplied piece of information as anything else on a POSTable form. (It's the client browser that provides the string... and there are scores of ways for a client to inject whatever it wants into that field of the HTTP request.) Really, the only way to feel safe that your script isn't going to be used to send out mass spam is to never ever let a user custom-define a recipient of the email without having to go through some level of authentication first. So for some of my PHP mailing scripts, the recipient of the final email is predetermined (like my website contact form, which sends email to me and me alone); for other scripts, the user has to log into the larger website, and even then can only send mail to a predetermined dropdown of recipients. (And that dropdown isn't foolish enough to contain email addresses which are fed into the script, but rather contains ID numbers that the script has to lookup in a database for the corresponding email addresses.)

Punishinglemur, your premise is correct -- there's a lot of thought that needs to go into creating a script that does what you want without exposing itself as a tool for evildoers. But it's entirely possible, and doesn't take a lot of actual effort in the end.
posted by delfuego at 3:50 PM on November 16, 2005

I stole this from somewhere (probably php.net) and slightly modified it for my homebrewed blogware (I think I modified it, but I no longer remember). It's pretty foolproof, whether they have a proxy or not:

function GetIP()
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
$ip = getenv("HTTP_CLIENT_IP");
else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
$ip = getenv("HTTP_X_FORWARDED_FOR");
else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
$ip = getenv("REMOTE_ADDR");
else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
$ip = "unknown";

and this guy has a nice function for sanitizing your email headers.
posted by evariste at 4:31 PM on November 16, 2005

This is basically what I use for my personal site's contact form, quickly altered. It probably is still functional. It doesn't do exactly what you've described, but should be fairly easy to alter. Let me know if you need clarification or whatever; email's in my profile.

File 1, form.php:
<form action="send.php" method="post">
<input type="text" value="" name="name" / ><br />
<input type="text" value="" name="email" /><br />
<textarea name="message"></textarea>
<input type="submit" value="Send it." /> <input type="reset" value="Clear it." />

File 2, send.php:
function GetIP() {
// use evariste's function above
$message = str_replace("\n.", "\n..", $_POST['message']);
$name = $_POST['name'];
$email = $_POST['email'];
$subject = $_POST['subject'];
$ipaddr = GetIP();
if (($email!="") AND ($email!="@")) $semail = $email;
else $semail = "[[a default sender email address if user leaves it blank]]";
if ($message!="null") $mailsent = mail("[[your email address]]", $subject,
"$message\n\n$name\n$email\n$ipaddr", "From: $name < $semail>\r\nReturn-Path:
if ($mailsent) echo "[[Some pretty text about how the message was sent & thanks.]]";
posted by fidelity at 9:52 AM on November 17, 2005

punishinglemur -- I have a php form mail script that I've been meaning to update against a few attacks and add the remote IP header feature to for a while, and coming upon your question seemed as good a reason as any to stop procrastinating so... I just did it. Feel free to download, and I'd be happy to help you make it work if needed and take feedback.
posted by weston at 8:37 PM on November 28, 2005

« Older I've got a month of spare time to kill.   |   He's 13. What can I do? Newer »
This thread is closed to new comments.