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 (a control panel my affordable host includes). 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 <?php // read from stdin $fd = fopen("php://stdin", "r"); $email = ""; while (!feof($fd)) { $email .= fread($fd, 1024); } fclose($fd); mail('you@yoursite.com','From my email pipe!','"' . $email . '"'); ?>
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.
nice up to date post – any idea why i’m still receiving bounces though? i’m using the -q but still getting them
Posted by G on March 28th, 2009.
Do you have any more information G?
The -q should suppress output from the script and therefore ensure no error, and therefore no bounce.
Posted by Harry on March 29th, 2009.
[...] suppose you could use email alerts in combination with a Pipe Email to PHP Script to make them more flexible, but you are still only getting limited information to act on, and [...]
Posted by Internet Banking and Webhooks Part 2 | Harry Bailey on May 6th, 2009.
Hey, did you solve that bounce problem? I have the same issue.
Posted by Zac on December 6th, 2009.
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
Posted by Harry on December 6th, 2009.
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?
Posted by Matt on March 5th, 2010.
Nevermind, I got it! Great post though!!
Posted by Matt on March 5th, 2010.
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.
Posted by Bill on June 22nd, 2010.
this is again emailing I would like to save values to database
Posted by computer tech news on July 13th, 2010.
@Matt: Could you please share how you solved the problem?
Posted by Andreas from Xavier Media on July 24th, 2010.
Any suggestion on how to use email piping without cPanel? I am at GoDaddy and they do not have cPanel.
Posted by Joseph on August 15th, 2010.
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.
Posted by Andy on August 15th, 2010.
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!
Posted by T on August 15th, 2010.
Hi Andy,
Create a php file with just the function phpinfo() in it:
< ?php
phpinfo();
?>
The php install location is often listed in there.
Posted by Harry on August 16th, 2010.
Hi Joseph,
Not sure I’m afraid. cPanel takes care of the tough part so how you would do it without a powerful control panel I have no idea.
Posted by Harry on August 16th, 2010.
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.
Posted by Marky on August 17th, 2010.
Hi, There are a few remotely hosted solutions for piping email that I would strongly recommend checking out. These can make receiving the email already parsed into different parts much easier. Some I would recommend are:
http://mailnuggets.com
http://smtp2web.com
http://mailhooks.com
Posted by Markus on October 4th, 2010.
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”
Posted by J Cash on December 18th, 2010.
I am looking some script which handle the attachment as well.
and HTML and text based email
any one help me from where i can get it ?
Posted by zahid on February 3rd, 2011.
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
Posted by Vikas Lasod on March 8th, 2011.
You cannot have ANY spaces after your closing php tag (?>). This will cause a bounce back.
Posted by tremmy on March 22nd, 2011.
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
Posted by Harry on March 22nd, 2011.
I had the bounceback issue, CHMOD file to 755 – all was well
Thanks for the code Harry
Posted by Andy on June 17th, 2011.
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.
Posted by Adam on July 20th, 2011.
i think it didnt work the last 2 hours because of that silly inline comment “// read from stdin” that’s just sad..
Posted by Alfred on July 21st, 2011.
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
Posted by apsar on September 9th, 2011.
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.
Posted by Neeraj on May 17th, 2012.
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.
Posted by Harry on May 17th, 2012.
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
Posted by Neeraj on May 21st, 2012.
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
Posted by Michael Hendry on June 2nd, 2012.
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
Posted by Harry on June 2nd, 2012.
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
Posted by Michael Hendry on June 2nd, 2012.
You don’t need api access to call the cpanel functionality from php. This page is an example of how you can call a normal page in cpanel with your auth details and the relevant parameters, but there are loads of tutorials out there about it…
http://wiki.donkeydonkeydonkey.com/index.php/Cpanel_add_e-mail_account_from_command_line_/_api_example
Posted by Harry on June 2nd, 2012.
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
Posted by Michael Hendry on June 2nd, 2012.
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
Posted by Harry on June 2nd, 2012.
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
Posted by Michael Hendry on June 2nd, 2012.
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
Posted by Michael Hendry on June 4th, 2012.
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!
Posted by TechCoder on November 29th, 2012.
wow it’s working
i change catcher file permission change to 755
Posted by linto cheeran on December 19th, 2012.