Hello Everyone,

I'm a relatively new web designer and I've been tearing my hair out for the past month, going between my VPS support team and my client's ISP tech support. Here's the issue:

I'm hosting a website with a PHP contact form. When the user submits the form, contactengine.php is run, and the information should get sent directly to my client's email. Unfortunately, some time in December, my client stopped receiving the messages (it had been working fine for 8 months!) I updated the script, and added my email address to the "To" field so that I could ensure the script was still working properly. I receive the form messages 100% of the time. My client receives messages about 5% of the time. Both support teams claim the issue is with the other service, and I'm stuck in the middle with a PHP form that works for me.

So, now, I'm turning to the forums to see if anyone knows of what to possibly try next! Below is the code that I have in my PHP script. Any help would be GREATLY appreciated!

Some notes about the code:
- "client@example.com" is my client's main email address
- "from@example.com" is a new email address created, hosted on the local server, but isn't used than being the "from" address
- "me@example.com" is my email, so that when a message is received from online, I can at least forward those to my client. It's a pain, but it's working.

<?php

$EmailTo = "client@example.com, me@example.com";
$Subject = "Tanoak Boxers - Website Contact Form";
$Name = Trim(stripslashes($_POST['Name'])); 
$Phone = Trim(stripslashes($_POST['Phone'])); 
$Email = Trim(stripslashes($_POST['Email'])); 
$Message = Trim(stripslashes($_POST['Message'])); 
$Headers = 'From: from@example.com' . "\r\n" .
    'Reply-To: ' . $Email;

// validation
$validationOK=true;

if (!$validationOK) {
  print "<meta http-equiv=\"refresh\" content=\"0;URL=error.html\">";
  exit;
}

function formatPhone($num)
{
    $num = ereg_replace('[^0-9]', '', $num);

$len = strlen($num);
if($len == 7)
    $num = preg_replace('/([0-9]{3})([0-9]{4})/', '$1-$2', $num);
elseif($len == 10)
    $num = preg_replace('/([0-9]{3})([0-9]{3})([0-9]{4})/', '($1) $2-$3', $num);

return $num;
} 

// prepare email body text
$Body = "";
$Body .= "Name: ";
$Body .= $Name;
$Body .= "\n";
$Body .= "Phone: ";
$Body .= formatPhone($Phone);
$Body .= "\n";
$Body .= "Email: ";
$Body .= $Email;
$Body .= "\n";
$Body .= "Message: ";
$Body .= $Message;
$Body .= "\n";

// send email 
$success = mail($EmailTo, $Subject, $Body, $Headers);

// redirect to success page 
if ($success){
  print "<meta http-equiv=\"refresh\" content=\"0;URL=contactthanks.php\">";
}
else{
  print "<meta http-equiv=\"refresh\" content=\"0;URL=error.html\">";
}
?>

Thanks in advance,
Mindy : )

    One likely possibility is that spam software on the receiving end is intercepting the messages, in which case, you're probably going to need a wig Real Soon Now(tm).

      I'll try and be a tad more helpful, but you're in for a tough fight, most likely.

      See if you can see the complete received message source, including the headers of all servers the message passed through enroute to its destination.

      In particular, try and make sure that your FROM address exists, and possibly even is the same as the REPLY-TO address.

      Also, there may be a message header added by your VPS server that indicates PHP was sending the message. You might try to add a header to your message that contradicts/contraindicates this header.

      Other than that, evaluate the content of the subject field and the message body themselves. Make the language very accurate, detailed, but not over-punctuated, overly enthusiastic, etc. "Guess what?? You have a new message from your website!!!!!!!" is very likely to be tagged as spam.

      This is really hard to "guess" about, BTW. Good luck to you ... you'll probably need it.

        @Mindy: Welcome to PHPBuilder! When posting PHP code, please use the board's [noparse]

        ..

        [/noparse] bbcode tags as they make your code much easier to read and analyze.

        As for your issue, it's possible that spam filters are marking your generated e-mails as spam simply because they don't look like legitimate messages. To avoid this, you could try adding more headers (e.g. Sender, MIME-Version, Content-Type, Content-Transfer-Encoding, etc.).

        Another issue may be that your e-mail server has been listed on one or more blacklists or RBLs. There are some free online tools (such as this one) that will allow you to search many databases to check this, but note you'd need to know the IP address of your outgoing mail server (which is not necessarily the same as your web server).

        @: No offense meant, but I just wanted to clear up a bit of confusion from your last reply...

        dalecosp;10996344 wrote:

        In particular, try and make sure that your FROM address exists

        Having a valid (or invalid, in terms of whether your mailserver has a valid mailbox associated with the address) 'From' address will neither help nor harm your chances of the message being treated as spam. There's one simple reason why you can be sure of this: it is impossible to determine whether you can actually deliver mail to a given e-mail address.

        Now, that's not to say that you shouldn't make the message look as if it originated from somewhere on the domain from which it is being sent; failing to do that will definitely make most spam filters reject the message. However, note that the 'From' header really isn't what most (RFC-compliant) spam filters will be interested in; it's really the 'Sender' header that makes claims as to where the message is actually being sent from. It just so happens that they should also assume the 'Sender' is the same as the 'From' address if you don't explicitly specify the former.

        dalecosp;10996344 wrote:

        and possibly even is the same as the REPLY-TO address.

        That definitely won't help; the whole point of the Reply-To header even existing or being used is to state that the originating e-mail address is not to be used as the destinations of replies.

        If the addresses were the same, then there'd be no point in using the 'Reply-To' header at all.

        dalecosp;10996344 wrote:

        Also, there may be a message header added by your VPS server that indicates PHP was sending the message.

        Not likely, because the MTA shouldn't know that PHP was even sending the message. There's no handshaking process where an MTA will identify which application/process is attempting to use it in order to deliver mail.

        Now, what is possible, however, is that PHP is voluntarily identifying itself in the form of an "X-" header (which aren't usually considered in terms of scoring the message in terms of spaminess), e.g. via mail.add_x_header or even an 'X-Mailer:' header that many applications commonly include in PHP-generated messages.

          bradgrafelman;10996347 wrote:

          Now, what is possible, however, is that PHP is voluntarily identifying itself in the form of an "X-" header (which aren't usually considered in terms of scoring the message in terms of spaminess), e.g. via mail.add_x_header or even an 'X-Mailer:' header that many applications commonly include in PHP-generated messages.

          My point exactly --- thanks for specifically describing the mechanism by which this occurs. 😉

            Your script is vulnerable to email header injection. I'm not sure how useful that link will be, but it looked alright on cursory inspection.

            The basic idea is that if your email form is accessible to the public, then someone could exploit it by ignoring your form and posting their own data to your script. By posting an Email value with a newline character in it, they could CC anyone they like. Minimally, you should fix your script by making sure that Email doesn't have any newline chars in it.

            Given that your script is vulnerable, it may currently be in use as a spam relay which may have resulted in your server being blacklisted. While this is generally bad, it's not the end of the world as you can send email from any arbitrary email account using PHPMailer or PEAR::Mail instead of PHP's built in [man]mail[/man] function. By using one of those mailer libraries, your server could connect to another server (say gmail) and send the mail using their system. If they also block gmail, then you could try an email address hosted by their own domain in which case it might completely bypass their spam filter. I frequently use this technique when trying to send email from a cloud VPS like Amazon EC2. As a matter of policy, every Amazon EC2 instance is on a 'policy block list.' I'm not sure the exact mechanism by which this happens but I seem to recall that Amazon, being the good internet citizens they are, voluntary instruct spam block lists to include the IPs associated with their EC2 instances as a preventive measure against spam because anyone in the world -- including organized crime -- can pay a few cents an hour to rent out these virtual machines for sending spam.

            I prefer PEAR::Mail. I've used it to connect to gmail. It has a debug flag you can set to get more information -- which may even tell you the response you get when trying to send mail that gets blocked.

              sneakyimp;10996412 wrote:

              Minimally, you should fix your script by making sure that Email doesn't have any newline chars in it.

              It'd probably be a lot more worthwhile (and still quite simple) to instead check if it's a valid e-mail address, say by using [man]filter_var/man.

              sneakyimp;10996412 wrote:

              While this is generally bad, it's not the end of the world as you can send email from any arbitrary email account using PHPMailer or PEAR::Mail instead of PHP's built in [man]mail[/man] function.

              Technically the same could be said about the internal mail() function, with the only stipulation (which probably turns out to be a deal-breaker more often than not) is that PHP's internal mail() function can't do SMTP authentication or (I believe) SSL/TLS.

              sneakyimp;10996412 wrote:

              It has a debug flag you can set to get more information -- which may even tell you the response you get when trying to send mail that gets blocked.

              Doubtful, since the only error message you'd be able to get is from your local MTA when it accepts (or rejects) the message for delivery. If an error occurs at that stage, then you should already be able to get that information from PHP's error messages since it too checks to see if the local MTA returned a successful 'queued for delivery' type of response.

              Since the actual transmission of the message to the destination mail server is an asynchronous process, however, the only place to view the errors returned by the remote MTA would be via the local MTA's error logs. And that is evening assuming that the remote MTA actually returned an error response rather than silently accepting the message and storing it safely in /dev/null. :p

                bradgrafelman;10996414 wrote:

                It'd probably be a lot more worthwhile (and still quite simple) to instead check if it's a valid e-mail address, say by using [man]filter_var/man.

                Yes.

                bradgrafelman;10996414 wrote:

                Technically the same could be said about the internal mail() function, with the only stipulation (which probably turns out to be a deal-breaker more often than not) is that PHP's internal mail() function can't do SMTP authentication or (I believe) SSL/TLS.

                Given the basic nature of the original script, I'm guessing (perhaps wrongly) that it would be easier to stay away from server config. Perhaps I'm missing something about how one can use the [man]mail[/man] function?

                bradgrafelman;10996414 wrote:

                Doubtful, since the only error message you'd be able to get is from your local MTA when it accepts (or rejects) the message for delivery. If an error occurs at that stage, then you should already be able to get that information from PHP's error messages since it too checks to see if the local MTA returned a successful 'queued for delivery' type of response.

                This is not necessarily true. Both PHPMailer and PEAR::Mail can be configured to connect via SMTP to a remote host/port/auth configuration. I personally have found it extremely helpful when using PEAR::Mail to have the debug flag turned on so that I can see the output of the session with the remote server. Depending on the configuration of the SMTP server you choose, you may get more or less detail about why your message was rejected. Obviously in the case of a spam filter at the receiving end, you may not be so lucky. If the server you use to send mail is the same server that receives mail for that domain, it may report useful information about why the message was rejected -- even including stuff related to spam. I don't recall exactly all the messages I've seen, but I believe I've seen "SPF failure" reported in such conditions.

                  sneakyimp;10996425 wrote:

                  Perhaps I'm missing something about how one can use the [man]mail[/man] function?

                  D'oh, I keep forgetting that the SMTP directive is Windows-only. Disregard.

                  sneakyimp;10996425 wrote:

                  Depending on the configuration of the SMTP server you choose, you may get more or less detail about why your message was rejected.

                  Maybe this is true, e.g. that some SMTP servers are configured such that sending mail through them is a synchronous process. However, I would be very, very surprised to learn that this is a common practice. (And if you do happen to find SMTP servers where this works, do let us know so we can stay away from them... I can't imagine such servers wouldn't have degraded performance as compared to ones with asynchronous delivery.)

                    you may want to try adding a fifth parameter to the 'mail' call

                    change:
                    
                    $success = mail($EmailTo, $Subject, $Body, $Headers); 
                    
                    to
                    
                    $pfive='-fwebmaster@example.com'; 
                    
                    $success = mail($EmailTo, $Subject, $Body, $Headers,$pfive); 

                    worked for me in a similar situation
                    see the 'mail' page in php manual

                      First off, thanks to everyone who has posted trying to help. I must admit, the vast majority of the discussion goes way over my head, however, I'm working to implement an updated script that uses PEAR::Mail.

                      My VPS support team has helped install PEAR, and I have then further installed the Mail and MIME modules (I've seen "MIME" used in the same sentences as Mail, and thought it wouldn't hurt to install that, too). From my cPanel, I see that the "Location of Your PHP Extension(s) and Application(s)" is stored at the following...
                      Path: /home/tanoak/php

                      I try to run my new script which has the command: require_once "mail.php";
                      but I get an error when trying to load the script that the file can't be found. Is there somewhere within the script or cPanel that I need to specify the path?

                      Any more help would be greatly appreciated!

                      Thanks,
                      Mindy 🙂

                        I believe the require statement is going to be case sensitive and the file is Mail.php, not mail.php. If your team has installed things correctly, it should be:

                        require_once 'Mail.php';

                          Hi sneakyimp,

                          I modified the script to be case-sensitive, as you suggested, but am still receiving an error when the script tries to run:

                          Warning: require_once(Mail.php) [function.require-once]: failed to open stream: No such file or directory in /home/tanoak/public_html/contactenginePEAR.php on line 2

                          Fatal error: require_once() [function.require]: Failed opening required 'Mail.php' (include_path='.:/usr/lib/php:/usr/local/lib/php') in /home/tanoak/public_html/contactenginePEAR.php on line 2

                          I see the path listing, and notice it's different from what's given in cPanel, but I have no idea whether that matters.

                          Any new hints?

                          Thanks again!
                          Mindy : )

                            It sounds to me like your team may not have installed PEAR properly. Specifically, they have not modified the include_path configuration variable for your server.

                            Your script's error message tells you where it's looking for the PEAR scripts by reporting the include path:

                            Failed opening required 'Mail.php' (include_path='.:/usr/lib/php:/usr/local/lib/php') in /home/tanoak/public_html/contactenginePEAR.php

                            I don't recall the exact sequence that PHP uses to look for a require/include, but it's probably looking in /home/tanoak/public_html first because that's where your script is stored. if PHP fails to find Mail.php in that same directory, it will then use the include_path values. There are three paths there separated by colons:

                            .
                            /usr/lib/php
                            /usr/local/lib/php
                            

                            The single period refers to the current working directory which will correspond to the PHP file being requested via web server or executed via command line. The other paths are where PHP and its libraries are installed.

                            An alternative to relying on your team to fix this problem is just manually downloading the PEAR files to your public_html directory and including them there. Note that if you are using PEAR mail to send mime messages, then you'll need to also get Mail_Mime.php. If you are using PEAR mail to send mail via SMTP you'll need to download a Net_SMTP.php. You'll probably have to download/install 4-6 files in all and make sure they are stored in the correct directory structure.

                              I have a similar issue. My quiz/form gathers 3 sessions and is suppose to be sent to a COMCAST.net email address, using the PHP mail() function to email out the gathered data.
                              However after looking around online I found several people who had this same issue. They called the Email Host and had their site white listed for the PHP mail() function.

                              See:
                              http://www.tectite.com/vbforums/showthread.php?1647-Can-t-E-Mail-to-comcast.net-addresses

                              The link is a thread showing this guys same problem and how he ended up calling the email host. I just posted a thread asking if there is a way to "Mask" the PHP()function. Doubtful, but we'll see.

                              Good luck!

                                Hello again,

                                An alternative to relying on your team to fix this problem is just manually downloading the PEAR files to your public_html directory and including them there. Note that if you are using PEAR mail to send mime messages, then you'll need to also get Mail_Mime.php. If you are using PEAR mail to send mail via SMTP you'll need to download a Net_SMTP.php. You'll probably have to download/install 4-6 files in all and make sure they are stored in the correct directory structure.

                                This may sound straight-forward to you, but I'm not quite sure how to go about doing this on my own. With PEAR installed, I see the "php" folder in the same location on the server as the "public_html" folder. I've read online that some people simply copy the entire PHP folder to the location where my website html/php files exist, but then I read follow-ups that say doing such is a bad idea.

                                I don't trust that my VPS support team would know what steps to try. If possible, I'd like to tackle this on my own. If you have the time, step-by-step instructions would be wonderful!

                                My fingers are crossed that I can get this resolved soon!

                                Thanks again,
                                Mindy 🙂

                                  Do you have access to modify php.ini, or to provide your own php.ini file which will get parsed after the host's php.ini config? If so, the step-by-step instructions are as simple as:

                                  1. Add the PEAR library path to the list of directories found in the include_path PHP directive (as suggested above)

                                  (And, if not, why in the world are you doing business with this host? 😉)

                                    I believe it's also feasible to set the include_path value in your script.

                                    FYI, the include_path is a list of directories where PHP will check when you say "include file.php". You can see the value of the include_path like this:

                                    echo ini_get('include_path');
                                    

                                    If you know the path to the PEAR directory, and the PEAR directory contains all the necessary files, you can set the include_path value to look in that directory too. Suppose your PEAR directory is located at /path/to/PEAR

                                    <?php ini_set('include_path',ini_get('include_path') . PATH_SEPARATOR . "/path/to/PEAR");  ?> 
                                    

                                    Downloading the files manually into your public_html directory is not super-hard, but involves including the file Mail.php (which you can download from pear.php.net) and once that works, you'll see complaints about it trying to include other files, etc. Each time it complains about not finding a file, you have to go to pear.php.net to find the right file and then put it in the right subdirectory of your public_html directory.

                                      sneakyimp;10996764 wrote:

                                      I believe it's also feasible to set the include_path value in your script.

                                      True, but it would get rather annoying if you constantly had to include that ini_set() statement in all of your PHP files.

                                      Plus, what happens if the path ever changes? Even though you just got done adding that statement to n PHP files, you now get to go back through all n of them and update the path.

                                      sneakyimp;10996764 wrote:

                                      Downloading the files manually into your public_html directory is not super-hard

                                      Agreed, and note that this is all that "installing PEAR" really means... just downloading various PHP files into a certain directory. Other than setting your include_path correctly, there really is no "installing" PEAR per sé.

                                      sneakyimp;10996764 wrote:

                                      but involves including the file Mail.php (which you can download from pear.php.net) and once that works, you'll see complaints about it trying to include other files, etc. Each time it complains about not finding a file, you have to go to pear.php.net to find the right file and then put it in the right subdirectory of your public_html directory.

                                      You could do that, but that would get quite tedious for some packages.

                                      A much better alternative would be to "install" PEAR yourself; see the PEAR manual for PEAR in hosting environments. PEAR already includes a nice web-based frontend that you can use if you don't have access to the CLI.

                                        bradgrafelman;10996765 wrote:

                                        True, but it would get rather annoying if you constantly had to include that ini_set() statement in all of your PHP files.

                                        Plus, what happens if the path ever changes? Even though you just got done adding that statement to n PHP files, you now get to go back through all n of them and update the path.

                                        That's what auto_prepend is for.