Pipe / Send Email to a PHP Script

Sending (or piping) emails to a php script would allows a whole world of fun. I had a spare 30 minutes the other night so I sat down, read a few blog posts and forums and set up emails to pipe to a php script.

The first step for me was to set up a new subdomain in cPanel. This allows me to only send (or pipe) specific email to the script and means I can run a catch-all wildcard forwarder on all emails to that subdomain.

In cPanel I created the subdomain in the normal way. Then I navigated to ‘Email Management Tools -> Default E-mail account’, chose the new subdomain from the dropdown list, clicked ‘Advanced Options’ and selected the radio button for ‘Pipe to a Program’.
In the textbox I added the name of the file that would be used to process the emails. In my case catcher.php which I had already created in the root of my site (not in public_html).

Cpanel is clever enough to add your sites root folder to the name you specify, so will be altered to something like ‘/home/youraccount/catcher.php’

The next step was to prepare catcher.php to deal with the emails being piped to it. Open the file and change the contents to something along the lines of:

#!/usr/bin/php -q

The first line of the script is very important and will tell the email pipe to use php. If your php install is not found at the location show, change it so it is. The -q part tells the pipe not to bounce an email back to the sender. A good thing as we can do that manually in the script.

Make sure you change the permissions of the script to be executable by the email pipe. chmod 755 should do fine.

The script itself will grab the emails contents using fopen on php://stdin which is where the email is temporarily stored. You can then manipulate it using such functions as preg_match to grab the parts you want.

The beauty of this method is it will catch all email to that subdomain, so you can create addresses which include the users id and a hash which can be temporary:

1294710241-w98fqwfhi3ho2ih3f@emailin.mysite.com

which you can use to ensure you only act on emails from the intended user.

Note: If you are using -q but still getting bounces, be sure the script is not outputting any data. That means once you have tested it, no print, no echo, no var_dump. When you run the script directly you should see a blank screen and the source code should be empty.

39 Replies to “Pipe / Send Email to a PHP Script”

  1. Hi Zac,

    As mentioned above. Using -q on the first line of the script should suppress any script output and therefore any bounce. If you are still seeing bounces then you may need to speak to your server team about how to stop them.

    Harry

  2. I’m having a little problem with mine. Every time I try to send a message to the script, it comes back with an error, saying that “local delivery failed”. Any suggestions?

  3. This works perfectly. Thank you.

    I need to take this a couple steps further… maybe you can point me in the right direction:

    1. I need to save an XML file that gets attached to each inbound email so I can parse it and updated my database…

    2. I need to parse the email body to pick out elements that I will be putting into another table in the database…

    What is the best class or method to do this and do you have any examples?

    Your piping example is exactly what I needed to get started here.

  4. Hi Guys,

    This is exactly what I’m after, however I cannot get the script to work. Any test emails I send get bounced back. A quick question:

    How do you determine the exact location of the php install directory (as referred to in line1 of the script). I can then verify it’s correct for my server.

    Thanks.

  5. I had the same problem as Matt, i.e. I was getting “local delivery failed” responses. I set the permissions of the file to 755 as mentioned in this article and all’s well!

  6. if you do the above and your script isn’t working, don’t forget to save your php script in unix format, that is removing Linefeeds or maybe its returns with dos2unix.

  7. Exactly what I needed man! Thanks for posting!!! It would be pretty easy to develop a php class to handle parsing this (likely some out there already)

    To someone elses comment above, if you attach a text file, It will come in as an additional mulitpart message:

    Content-Type: text/plain;
    name=”gourmetburger.csv”
    Content-Transfer-Encoding: 7bit
    Content-Disposition: attachment;
    filename=”gourmetburger.csv”

    “CPHONE”,”NAME”
    “5553649555”, “BOB”
    “5555549555”, “SAM”
    “5553649555”, “ACE”

  8. I have Create a PHP File. and uploaded on server. But the mail is still bouncing and give a error “Local Delivery Failed”. PHP Code is :-

    #/usr/local/lib/php –q

  9. Tremmy,

    You’re correct, but it’s actually a case of any output will cause a bounce back. So that could be output at any point during the script running.

    Harry

  10. I am having a bit of trouble with this. I have the file chmod to 755, have removed any errrant spaces or any out put, when i run the file i get this out put:

    #!/usr/local/lib/php -q

    it was my understanding that there should be absolutly nothing displayed in the source. what am i doing wrong.

  11. hi all,
    i want to develop a web application which reads emails from mailserver whenever a new mail is received at mailserver. iam using a windows 7,xampp package with mercury mail server, could anyone please suggest me how to pipe the emails . and the solution posted states to use a script #/usr/local/lib/php –q, for windows what is path we have to set ,is it # c:/xampp/php ,
    thanks in advance

  12. Hi guys,

    Got the script work. But getting emails to bounced back. This is because I’m getting this error – PHP: Error parsing /usr/local/lib/php.ini on line 794. But I’m not getting whats causing this php error in above script. I also tried to remove most of the code from the script but still getting the error, which is making the emails to bounce back. Any help will be much appreciated.

  13. Hi Neeraj,

    1) Are you sure your php.ini file is located at /usr/local/lib/php.ini ? If not then you need to change that path.

    2) If it is located there, what is on line 794?

    I don’t believe the error is related to the code in this article, unless your path is incorrect.

  14. Hi,

    I finally got to resolve the error. You can find the solution here – http://osticket.com/wiki/Email_Piping
    I updated /etc/exim.conf as explained in the above url and got it to work. Hope it will be helpful for other guys who are facing the same problem.
    Here is what you nee to update on /etc/exim.conf file –

    address_pipe:
    driver = pipe
    return_output

    *change return_output to return_fail_output

    virtual_address_pipe:
    driver = pipe
    group = “${lookup{$domain}lsearch* {/etc/userdomains}{$value}}”
    return_output
    user = “${lookup{$domain}lsearch* {/etc/userdomains}{$value}}”

    *again here change return_output to return_fail_output

  15. I run a club website with members’ details in a database, and would like to be able to forward e-mail sent to “president@myclub.com” to the current president, using the php script to pick up the current president’s e-mail address from the database.

    I know that this is a trivial example, better handled by just editing the forwarding address “by hand” through cpanel, but I have group addresses like “council@myclub.com” where removing last year’s council members from the forwarding list and replacing them with new members becomes tiresome and error-prone, especially if members change their e-mail addresses during the year.

    My question is: Would a message forwarded in this way appear exactly the same as if it had been forwarded by the cpanel-supplied forwarding method?

    TIA

    Michael

  16. Hi Michael,

    If you want to use it for forwarding, you would be much better investing your time in using the cpanel api stuff to create / update / remove forwarders.

    Email is a horrible format and the work would be far more than getting cPanel to deal with it all.

    Harry

  17. Thanks, Harry.

    I thought it might prove awkward.

    Unfortunately, our website isn’t on our own server, and the host server doesn’t allow access to the cpanel API.

    I did find some older references to php files which could be used to log in to cpanel and read and write to the relevant cpanel files, but this seems to be impossible now that the cpanel login is done using directories allocated individually for each login instance.

    Too bad!

    Michael

  18. Thanks again, Harry.

    So all is not lost after all!

    I shouldn’t have any difficulty extracting the necessary e-mail addresses from the database using a php script, but I could do with a few more worked examples with comments to guide me,

    Presumably the $whmusername is the username I would use to log in to cpanel, but how do I generate $whmhash?

    Presumably the php script can be placed with the other scripts used on the site, and the $query is used to access an absolute directory path on the localhost (i.e. the remote server which hosts our website).

    Could you point we towards one or two of the “loads of tutorials”?

    Michael

  19. Hi Michael,

    1) Check your cPanel theme is set to x3
    2) Use the url below with your username, password, site domain / ip, email forwarder details…

    https://##username:##password##@example.com/frontend/x3/mail/doaddfwd.html?email=##from##&domain=##domain##&fwdopt=fwd&fwdemail=##to##&failmsgs=No+such+person+at+this+address&pipefwd=

    to forward harry@example1.com to harry@example2.com I believe you would do…
    from = harry
    domain = example1.com
    to = harry@example2.com

    Be sure to use https. Best of luck

  20. Tried that, and got…

    Secure Connection Failed

    An error occurred during a connection to mysite.com

    SSL received a record that exceeded the maximum permissible length.

    (Error code: ssl_error_rx_record_too_long)

    …I tried removing the failmsgs section at the end, but this didn’t help.

    I’m presuming that the “#” signs are not supposed to be in the URL, but serve to delimit the fields I have to change, so the URL should look like this…

    https://MyLogin:MyPassword@mysite.com/frontend/x3/mail/doaddfwd.html?email=source&domain=mysite.com&fwdopt=fwd&fwdemail=destination@anothersite.com&failmsgs=Failure&pipefwd=

    It seems as though I’m nearly there!

    Michael

  21. Further investigation:

    When I logged on to cpanel this morning, I noticed that…

    cpsess6435503374/

    …was interpolated in the url between “mysite.com/” and “/frontend” once I’d entered my username and password.

    I opened a new tab in my browser, edited the failed URL by putting this additional information into it, and it worked!

    I think the cpsess… section is part of an improvement in security (put in by cpanel), and it may be hard for me to work around.

    Michael

  22. Michael,

    I tried this and got the same SSL error, however, in thinking it through just a second, I thought I’d try it just a bit differently – and it WORKED!

    Here’s your original…
    https://##username:##password##@example.com/frontend/x3/mail/doaddfwd.html?email=##from##&domain=##domain##&fwdopt=fwd&fwdemail=##to##&failmsgs=No+such+person+at+this+address&pipefwd=

    What I did to make it work;
    1. changed ##username to my Cpanel username
    2. change ##password## to my Cpanel password
    3. change example.com to EXACTLY what I get when logged in to my Cpanel (in my case, it was site1675.hostsite.com:2083 – including the entire bit was the ‘key’ here!)
    4. ##from## is the email part only (no @domain!)
    5. ##domain## is the domain part of the ‘from’
    6. change ##to## to the complete forward-to email

    With this in the browser and a couple seconds, I got a logged in screen from Cpanel and a confirmation that all emails would be forwarded!

    FANTASTIC!

    My application is very similar to those mentioned here and I’ve been fighting writing an email application to forward stuff around when all I need is to make the forward, controlled by my back end system.

    A quick explanation of what I was trying to do is;
    We have a 4-letter .com domain name and not all the others (.org, .net, .biz, etc.) and we get a lot of email for the other sites (people tend to send to .com and not check….). So, we thought about selling the .com email to those that need it (hey, why not!)

    the base method we started with
    – take all emails into a ‘catch all’ box
    – read the ‘to’ bit, compare it to my database to see if it is a paid customer and if so, forward the messages – if not paid, send a ‘blast’ to the other tlds to see if we can find the rightful owner (and offer for them to buy the .com email!)
    – keep track of the payment time, send reminders close to renewal time and stop the forwards if not paid.

    The trouble I was having was in forwarding messages with attachments (I got all simple messages to work just fine).

    However, with this method, the system will be slightly different (and a bit simpler overall I think – certainly less processing needed);
    – take in the ‘catch all’ and process as before
    – if paid, turn on the forward as per this thread
    – send the reminders as before
    – if payment runs out, remove (not sure how) or send all emails back to the ‘catch all’ (which would then start the process all over again)

    It’ll take a bit of rethinking on this, but I really like this method a LOT – no worries about what the email is or contains, just if they paid or not!

    Thanks for this page!

Comments are closed.