Troubleshoot PHP mail function (Centos 6, VPS)


I just spent about 4 hours troubleshooting an issue I had implementing the PHP mail() function. On the surface it looks fairly straight-forward. You call the method, pass the parameters and email gets sent.

If the stars are aligned, everything will work great for you the first time. If, however, you don't have the dependencies installed things won't go quite as smoothly.

Notes:

  • PHP Mail function [php.net]
  • Forum post showing how to change PHP default sender [webhostingtalk.com]
  • Be sure you have sendmail / postfix setup correctly on your VPS / Server
  • Be sure that your From email address is valid and verifiable by the destination mail server
  • This article assumes that you are using sendmail on localhost to send emails

Background:

To help me troubleshoot web application issues more quickly, I implemented a Send Bug Report button on one of my web applications. When clicked the button will Generate a bug report (using Javascript) and send me an email (PHP webservice).

When I clicked the button I could see that the bug report was getting generated, but an email never arrived in my inbox. This prompted a 4 hour troubleshooting journey to figure out what was going wrong.

This is the PHP Code I was using to send my email:

// Grab the message
$message = $_POST['bugreport'];

// Set the headers
$headers = 'From:webservice@regexraptor.net';

// Send an email
mail('developer@bluehost_hosted_domain.com', 'Bug report from RegexRaptor.net', $message, $headers);

echo "Mail Sent.";
?>

As you can see from the bolded line above, I'm not doing anything terribly fancy with the mail() method.

Troubleshooting Steps that led to a resolution:

  1. Check the mail log on the VPS
    1. Since this was a Centos 6 server I could find it here: /var/log/maillog

      Nothing interesting was found while investigating the log
  2. Send an email via CLI: echo -e "bbb" | mail -s "Test Email" developer@bluehost_hosted_domain.com
    1. The email failed to send
    2. Turned out that sendmail was not active
  3. Turned on sendmail using: service sendmail start
    1. Used chkconfig to ensure it starts on boot: chkconfig sendmail on
  4. Sent an email from the PHP web application
    1. Be sure to tail -f /var/log/maillog
    2. I found the following messages while tailling:

      Mar 12 03:25:22 webapps3 sendmail[20414]: q2C0PLJl020414: from=apache, size=243, class="0", nrcpts=1, msgid=, relay=apache@localhost
      Mar 12 03:25:23 webapps3 sendmail[20416]: q2C0PNSb020416: from=, size=492, class="0", nrcpts=1, msgid=, proto=ESMTP, daemon=MTA, relay=localhost [127.0.0.1]
      Mar 12 03:25:25 webapps3 sendmail[20414]: q2C0PLJl020414: to=user@maildomain.com, ctladdr=apache (48/48), delay=00:00:04, xdelay=00:00:02, mailer=relay, pri=30243, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (q2C0PNSb020416 Message accepted for delivery)
      Mar 12 03:25:25 webapps3 sendmail[20418]: STARTTLS=client, relay=maildomain.com., version=TLSv1/SSLv3, verify=FAIL, cipher=AES256-SHA, bits=256/256


      Mar 12 03:25:26 webapps3 sendmail[20418]: q2C0PNSb020416: to=, ctladdr= (48/48), delay=00:00:03, xdelay=00:00:01, mailer=esmtp, pri=120492, relay=maildomain.com. [173.254.21.179], dsn=5.1.1, stat=User unknown

      Mar 12 03:25:26
      webapps3 sendmail[20418]: q2C0PNSb020416: q2C0PQSb020418: DSN: User unknown

      Mar 12 03:25:30
      webapps3 sendmail[20418]: q2C0PQSb020418: to=root, delay=00:00:04, xdelay=00:00:03, mailer=local, pri=31743, dsn=2.0.0, stat=Sent


      The last 3 lines above (Separated by spaces to make it easier to read) indicate that there was a problem delivering the mail and that a return to sender message was sent back to us

  5. Check the root user's mailbox to see the returned mail message
    1. nano /var/spool/mail/root let me see the root mailbox
    2. I found the following relevant messages inside (Scroll to bottom of the file in nano by using ctrl-v (page down) to see the latest message received):

      ----- The following addresses had permanent fatal errors -----

      (reason: 550-Verification failed for )

      ----- Transcript of session follows -----
      ... while talking to maildomain.com.:
      >>> DATA
      <<< 550-Verification failed for

      <<< 550-The mail server could not deliver mail to apache@webapps3.softwaredomain.com. The account or domain may not exist, they may be blacklisted, or missing the proper dns entries.

      <<< 550 Sender verify failed
      550 5.1.1 ... User unknown

      <<< 503-All RCPT commands were rejected with this error:
      <<< 503-Sender verify failed
      <<< 503 Valid RCPT command must precede DATA


    3. I spaced out and bolded the relevant messages. It looks like the destination email server (in this case the destination email server is hosted by bluehost) is rejecting my emails

  6. Next, Telnet into your localhost smtp server to see if you can send messages that way
    1. Here is a transcript of my Telnet attempt:

      [root@webapps3 spool]# telnet localhost 25
      Trying 127.0.0.1...
      Connected to localhost.
      Escape character is '^]'.
      220 webapps3.softwaredomain.com ESMTP Sendmail 8.14.4/8.14.4; Mon, 12 Mar 2012 03:19:26 +0300
      HELO softwaredomain.com
      250 webapps3.softwaredomain.com Hello localhost [127.0.0.1], please d to meet you
      MAIL FROM:user@maildomain.com
      250 2.1.0 user@maildomain.com... Sender ok
      RCPT TO:user@maildomain.com
      250 2.1.5 user@maildomain.com... Recipient ok
      DATA
      354 Enter mail, end with "." on a line by itself
      this is a test
      .
      250 2.0.0 q2C0JQHc020397 Message accepted for delivery
      500 5.5.1 Command unrecognized: ""
      QUIT

    2. The bolded lines above were entered by me
    3. In my case the above telnet session worked: an email was received in my mailbox
  7. The only appreciable difference between the Telnet attempt and my PHP code is that I specified the "From" address in Telnet.
  8. So the next thing I tried was forcing PHP to use a valid "From" email address as it had been using apache@webapps3.softwaredomain.com (Default setup) previously
    1. Open /etc/php.ini (Default location on Centos 6)
    2. Search for sendmail_path
    3. Append -f USER@DOMAIN.TLD to the end of the line

      For example, Here is my mail config before applying -f:

      ; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
      ; http://www.php.net/manual/en/mail.configuration.php#ini.sendmail-path
      sendmail_path = /usr/sbin/sendmail -t -i

      And here is the mail config After I applied -f:

      ; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
      ; http://www.php.net/manual/en/mail.configuration.php#ini.sendmail-path
      sendmail_path = /usr/sbin/sendmail -t -i -f user@boredwookie.net

  9. After changing the From address (Step 8) Restart httpd:

    This works on Centos 6: service httpd restart

Now that I have gone through these steps, the Bug report button on my web-app is working correctly.
To summarize:
  • Ensure that your MTA (Mail Transfer Agent) is up and running
  • Ensure that the From address you are using in PHP will be accepted by the destination server
  • Try sending email via Telnet to see if you get any descriptive error messages
  • Check the root user's mailbox for returned mail messages. Search the most recent message for descriptive errors.