We all know how to send email from PHP. Actually, it's quite easy: mail("to@me", "Hello", "Hello"); Handling mail the other way, sending email to PHP is a task much more unknown. In this article, we will write and install a script that we can send an email to.
We want to write and install a script that handles incoming mail. We want our script not to be reachable by a web browser, but by our email client. Sending an email to script@example.com would suffice for running our script and processing the mail.
Well, that's a stupid question, because we don't know how to do it and it's fun. You're reading evolt because you want to learn something, aren't you? But this script could be useful. For example:
Because the script is triggered by an email, we will have to take a bit of a different approach than when our script is run by someone requesting a web page. Our script has to be started by the mail system. You will need:
The first thing we have to do, is tell our mail system to send all mail addressed to script@example.com to our script. How to accomplish this, depends on which mail system you use.
There are two different approaches for forwarding mail to a program in Sendmail. You can create a real user for our script and create a .forward file, or you can create an alias in your aliases file. If you have root access, the latter would be the best option.
If using the aliases file, this can be found in /etc, you add the following line. script is the email alias for our script, /our/script.php should be substituted with the full path to the script.
script: "|/our/script.php"
If using a forward file, create a file named .forward in your home dir. Then add the following line and save the file. Email sent to you, will be forwarded to the script. If you'd also like the email sent to another address, you can add that address before the script and tailed by a comma. /our/script.php should be substituted with the full path to the script.
"|/our/script.php"
or:
myemail@example.com,"|/our/script.php"
Watch out: if you don't add another address to your .forward file, the email is deleted after being sent to the script. You will lose your email.
There are two different approaches for forwarding mail to a program in Exim. You can create a real user for our script and create a .forward file, or you can create an alias in your aliases file. If you have root access, the latter would be the best option.
If using the aliases file, this can be found in /etc, you add the following line. script is the email alias for our script, /our/script.php should be substituted with the full path to the script.
script: |/our/script.php
You also have to edit your exim.conf, found at /etc/exim.conf. Look for a part containing 'address_pipe'. If there is such a part, replace it with the text below. If there is no such text, paste this text somewhere in exim.conf. Save the file.
address_pipe: driver = pipe pipe_as_creator
If using a forward file, create a file named .forward in your home dir. Then add the following line and save the file. Email sent to you, will be forwarded to the script. If you'd also like the email sent to another address, you can add that address before the script and tailed by a comma. /our/script.php should be substituted with the full path to the script.
|/our/script.php
or:
myemail@example.com,|/our/script.php
Watch out: if you don't add another address to your .forward file, the email is deleted after being sent to the script. You will lose your email.
There are two different approaches for forwarding mail to a program in Qmail. You can create a real user for our script and create a .qmail file, or you can create an alias. If you have root access, the latter would be the best option.
One thing I like about Qmail, is the possibility of creating custom aliases. If you are a normal user, you can create an alias by saving a file called .qmail-foo in your home directory. Email sent to yourusername-foo@example.com is then sent as specified in this file.
If you want to create just an alias, without being an user, eg. myscript@example.com, you create a .qmail file in the /var/qmail/alias directory. .qmail-myscript should do it.
Add the following to your .qmail file and save it. /our/script.php should be substituted with the full path to the script.
|/our/script.php
Because the email is passed to the script as a raw email, it is useful to take a closer look at the structure of an email.
Received: from gijs ([192.168.55.2]) by debian with smtp (Exim 3.12 #1 (Debian)) id 17AYXZ-0002BE-00 for ; Wed, 22 May 2002 18:00:41 +0200 From: "Gijs van Tulder" To: Subject: Test Date: Wed, 22 May 2002 18:00:41 +0200 Message-ID: <KNEOKJCOCHEDPIMPAIMIOEOJCJAA.gijs@debian> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0) Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000 This is my message. Thank you.
The first part of the raw email contains the headers. A header contains information about the email. The header has a name, before the colon, and a value: Header-Name: Value. Important headers are the Subject header, containing the subject of the email, the From header, containing the origin of the email, and the To header, which tells us something about the recipient. The other headers are of minor importance.
An empty line marks the end of the header part. After the first empty line, follows the body of the email.
Since our script will function as a shell script, the first line should contain the path to the PHP CGI program. This is most likely located at /usr/bin/php of /usr/local/bin/php. This tells the operating system that this script must be parsed by PHP.
#!/usr/bin/php <?php
The email is sent to the script through stdin. This is a special 'file' that can be reached by opening php://stdin. We will do that now and read the email.
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
Now we have the full text of the email in the $email variable, we can start splitting headers from body. We will do that line by line, so the first step would be splitting the email. We also empty the variables that we will fill with the From header, the Subject header, and save other information in.
// handle email
$lines = explode("\n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
We have just set the $splittingheaders variable to true. As long as this variable is true, and we have not yet seen an empty line, the text should be added to $headers. If we find a Subject or a From header, we will save it in the appropriate variable.
After we have seen the first empty line, we have processed the headers and can start adding the lines to $message.
for ($i=0; $i < count($lines); $i++) {
if ($splittingheaders) {
// this is a header
$headers .= $lines[$i]."\n";
// look out for special headers
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
?>
We now have the headers, the message, the From and Subject information and can save these in a database. You could also use the mail() function to send an automatic reply. That's up to you.
Now you wrote and saved the script, you have to copy it to its final destination, the location you configured in your mail system. You should also make the script executable: chmod 755 Remember: it's a shell script, not a web page.
When an email arrives at the address you configured, it is piped to the script we just wrote. The script processes the headers and the message and returns is in a few useful variables. You can use this as a first building block to write your own mailing list, or do something else with it.
As usually, you can copy and paste the parts of this script, or download it as a text file.
Comments
HTML
question
Sendmail aliases
Mime attachments
Mime attachments
While you could easily implement attachment handling in this script, you don't need to. The script in this article doesn't modify the incoming email. It splits header and body of the message, that's all.
This script is just the first step in the handling of an incoming email. It saves the headers in the $headers variable, extracts the $from and $subject field from that headers and saves the rest of the message, the body, in $message. You can then use these values in your own script, ie. your MIME attachment extracting script.
(You could, for example, use the PEAR Mail_mimeDecode class to parse MIME messages.)
please help me debug
smrsh: script.php4 not available for sendmail programs
554 5.0.0 "|/path/script.php4"... Service unavailable
mean:
a.) script not found (i flubbed the path somehow)
b.) sendmail doesn't have access to that file (i set it to 0777, but it might still be in a directory it can't see)
c.) sendmail won't run PHP as a CGI
d.) something you can't tell from this little information,
and/or
e.) something else entirely?
Sendmail question
includes problems & error capturing
Failure Notice
I am using Exim and added the following line to the alias file
test: |/home/path/to/script.php which executes and works great.
but the only thing is i receive a Failure Delivery Message bcoz exim tries to send message to this test: |/home/path/to/script.php statement
The address_pipe configuration i have is
address_pipe:
virtual_address_pipe:
pipe_transport = virtual_address_pipe
pipe_transport = virtual_address_pipe
pipe_transport = virtual_address_pipe
pipe_transport = address_pipe
pipe_transport = address_pipe
How do i stop the Failure Messages?
Piping emails using postfix
I have been trying to pipe incoming mails to postfix to a php script using a few variations but to no avail (in my alias file)
emailaddress: (followed by one of the following)
| "/path/to/script/myscript.php"
"|/path/to/script/myscript/php"
| "/usr/bin/php /mypathagain/script/php"
"|/usr/bin/php /mypathagain/script/php"
I get no error messages, no bounced emails etc but at the same time no results - on activation my script should write a file to disk to show it was executed. It works from the command line e.g.
$ echo "some data" | mysscript.php
and postfix appends the incoming email to a file if i just put in aliass emailaddress: | somefile
so what on earth is wrong? I am at a loss. If anyone can help I will be very grateful.
update to previous messages
To rub salt into the wound, I have now solved this problem. If anyone else has similar problems, make sure that your permissions are set properly - using this method postfix does pipe correctly, but if you need ouput to a file, make sure the file is in a directory with write permissions for others.
what a mess! :)
Couple of tips for sendmail users
I was frustrated by many of the problems reported in the posts above, a couple of notes for everybdy in the same boat
1)
I had an /etc/aliases and an /etc/mail/aliases
I found by adding a line in /etc/aliases rather than /etc/mail/aliases in this format
alias: "|/usr/bin/php /full/path/to/script.php"2)
Make sure that smrsh (the send mail shell can access your PHP executable by creating a symlink in /etc/smrsh
ln -s /usr/local/bin/php /etc/smrsh/phpRE: Failure Notice
See Vishal's comment above .
Using EXIM I was successfully passing the mail to the script but was also getting delivery failure errors returned to the sender of the original email.
I added the following line to the very end of the script.
return NULL;
My guess as to why this works: The reason for this is that EXIM on my server is configured to send ANY output from a script which received an email back to the sender as a delivery failure error. I can only assume at this point that Tulder's script as is returns 0 or 1. By explicitly telling the script to return no values it produces no output and therefore exim doesn't send the failed delivery report.
How receives mail by php
Problem with POSTFIX-MYSQL piping to a script
Processing incoming mail on Postfix
We included a function to forward an email indicating the mail had been received and the script executed. This email is despatched fine. However, it appears that the incoming email content is not placed in "PHP://stdin" by Postfix because the script is unable to read anything from that source, hence none of the rest of the example script does anything.
Can anyone help?? Please?
Incoming Mail and PHP
Hi,
I was visiting this forum:
http://forums.devshed.com/archive/t-96700
It too has the same issue ..with some comments on it. I hope it helps.
Mail Delivery Failure
I modified the first line to the following, but I still receive the failure message.
#!/usr/bin/php -q
Any ideas as to why I am getting this and what I can do to fix it?
#!/usr/bin/php
smrsh: script.php4 not available for sendmail prog
As I couldn't find a clear post on it, I hope the following will be useful.
The problem on my server was that smrsh wasn't allowing sendmail to use php.
Although I saw several posts saying "put a soft link to php in /etc/smrsh", I didn't have an /etc/smrsh. Creating one and putting a soft link to php in it didn't work.
Eventually, I did "man smrsh". The 2nd paragraph said "Briefly, smrsh limits programs to be in the directory /usr/adm/sm.bin, allowing the system administrator to choose the set of acceptable commands".
So I went to /usr/adm/sm.bin and typed
ln -s /usr/bin/php php
After that, sendmail could get to php, and everything worked !
Now I'm off to make the php script do something useful... : - )
Forward All Emails
qmail Success!
This will write to a textfile: email address: blog@example.net
Contents of.qmail-example:net-blog|/usr/local/bin/php -q /usr/home/pscan/blogATexampleDOTnet_mail_proc.phpHere is the script,
blogATexampleDOTnet_mail_proc.php, taken from script in this article and modified to write to file (initial test).<?php// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
$outFile = fopen("/usr/home/pscan/emailResult.txt","w");
fwrite($outFile,$email);
fclose($outFile);
?>
Note that the shebang line is removed, and instead, path to php is put in the .qmail.. file.
I created the file emailResult.txt initially, then set permissions on emailResult.txt to be world-writable. This will overwrite it every time an email comes in. you can use fopen() with "a" to append.
It finally worked!
Apache Module
why I can not see the complete article?
Re: why I can not see the complete article?
exim gotcha
If you're tearing your hair out trying to get this to work with exim, there's a gotcha... If your script name has an underscore in it, it will ALWAYS generate an MTA failure message!
Except if you wrap the script name with quotes. Bizarre? You bet. Should you care? Probably not; just wrap the script name in quotes and you'll be golden!
Example:
Bad: script: |/our/stupid_script.php
Good: script: |"/our/stupid_script.php"
delivery failure errors
Thank you!!
HTML Formatted E-Mails
If it receives E-Mails formatted in HTML, it doesn't catch the message properly. I've tried to filter out the extra headers but I can't manage it.
------=_Part_6485_7914052.1162641263809 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inlineJust a test.
------=_Part_6485_7914052.1162641263809 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline
Just a test.
------=_Part_6485_7914052.1162641263809--
Now sending of messages by
condredirect
two comments.
#1. I couldn't get the above to work on my linux system until I: a. removed the line fclose($fd); b. made sure that the .qmail file was read only (i.e. chmod 400)
Otherwise, it works great. second comment.
I tried getting this to work with .qmail's conredirect. this is a utility which will conditionally redirect the email to another address if your program/script exits with a certain error code. According to the .qmail manual, if the program exits with code 0, the email is redirected to another address and execution stops in the .qmail file. if the program exits 99, the .qmail instructions are executed normally. In my .qmail file, I used this:
|condredirect bounceback@domain.com /bouncebacks.php
./Maildir/
How this should work (from what I understand). qmail runs the bouncebacks.php script with the message on stdin. In the bouncebacks.php script, I test the subject for a typical bounceback subject heading (i.e. failure, undeliverable, etc). If the file finds that the email bounced, it returns 0 (therefore the email is forwarded to a bounce back address). If not, the email ends up being processed as usuals (in my case, to ./Maildir). I do this because I regularly send out to a mailing list, and typically get bombarded with bouncebacks to the address I'm sending from. with the php file, I ideally wanted to do two things. 1. return a code such that qmail forwards the message to a general bounceback address, and two, log the recipients email in a database, and automatically exclude it from future mailings.
Everything seems to work except for the fact that condredirect doesn't care what is returned from my php file (0 or 99). It always redirects the email to bounceback. I also striped my php file to test this theory:
#!/usr/local/bin/php <?php return 0; ?>
and
#!/usr/local/bin/php <?php return 99 ?>
...both have the same result.
I guess the way around this is to not use conredirect at all, and have the php file do all the work (i.e. repackage the email and send it using the headers/email body with Pear_Mail or something). I just think using conredirect is a more elegant solution....if it works with php. I wonder if it has something to do with the way php returns codes.
woooops
I just answered my own question. If you want the above to work, use exit in php, not return.
so, when testing the email, if you want qmail to redirect it, follow the above, but make sure you have this line in the php file:
exit(0);
and it will be redirected. otherwise, use exit(99), and it will be processed as usuals.
nice. it's good to talk things out :)
Message not fully parsed
permission problem?
|/etc/bin/php -q |/var/www/vhosts/domain.com/httpdocs/_phpcgi/test.php|/etc/bin/php |/var/www/vhosts/domain.com/httpdocs/_phpcgi/test.php<?php// Send
mail('test@gmail.com','test subject', 'my message goes here');
?>
When i try and switch it around: .qmail looks like this
|/var/www/vhosts/domain.com/httpdocs/_phpcgi/test.php#!/usr/bin/php -q<?php
// Send
mail('test@gmail.com','test subject', 'my message goes here');
?>
I'm running plesk 8.1 on Fedora, My permissions are as follows:
-rwxr-xr-x 1 ftpuser psacln 98 May 15 01:37 test.php
and for qmail:
-r-------- 1 popuser popuser 73 May 15 01:36 .qmail
Any help is really appreciated. Is this the latest method or is there some other way to get this going?
hello
Mail delivery notification
Many people here have problems with mail delivery notifications, and so had I.
I'm using EXIM, and PHP as an Apache module. In cPanel I had the option to add a forwarder using a pipe to a script. At first I got delivery notifications that the e-mails sent to the e-mail address using the script could not be delivered.
This works for me:
#!/usr/bin/php -q<?phpreturn true;instead ofreturn NULL;?>I use MIME Parser to parse the e-mail.
Got it working, but...
hexburner, I got it working, following your instructions, but messages come out all run together (not separated by mime type for a multi part message).
Can you post the Mime Parser code you use to forward the message.
It sounds like we are doing a similar thing. I want someone to be able to send an email, using their email address, given by my site, then when the receiver hits reply, it should go to the PIPE program. Then I want the program to reprocess the message, and send it out, to my user, at his existing email address.
I got that all working, except when the email is multi part.
Any help there would be appreciated.
thanks!
loop problem
Hi! I created a bounced email management system. All bounced email are returned to a specified email and from this email it will be redirected to a script that will parse the bounced email so that I can be able to get the recipients address and the reason why it is bounced. It perfectly redirected to my script but the problem is when I loop over it, it doesn't store to a variable ($strReason). Here's the code:
// read from stdin $fd = fopen("php://stdin", "r"); $email = "";
while (!feof($fd)) { $email .= fread($fd, 1024); } fclose($fd);
// handle email $lines = explode("\n", $email); $strReason = "";
for ($x = 0; $x < count($lines); $x++){ $strReason .= $lines[$x]; }
// Store bounced email to database $sql = "INSERT INTO tbl_bounced_email(Reason) VALUES('$strReason')"; $r = mysql_query($sql, $link) or die (mysql_error().' '.$sql);
but when i set the loop to 16 only, it stores the message to $strReason for ($x = 0; $x < 16; $x++){ $strReason .= $lines[$x]; }
404
http://gvtulder.f2o.org/evolt/mail/mail.php.txt = 404
I've spent ages trying to make this work. My symptoms are very similar to fishnyc22 above. My .qmail file is located in...
/var/qmail/mailnames/myDomainName.com/EmailUserNameI'm running Apache 2, PHP 5 as CLI, Qmail. It's a 1&1 server, and I am wondering if they are imposing restrictions on me.
My Qmail file looks like this...
| true./Maildir/&myEmailAddress@gmail.com|/usr/bin/php -q /var/www/vhosts/myDomainName.com/cgi-bin/test/emailtophp.phpAnd my PHP file looks like this (chmod 777 emailtophp.php):
< ?PHP $message = "Bla bla bla"; $message = wordwrap($message, 70); mail('myEmailAddress@gmail.com', 'My Subject', $message); exit(); ? >(Spaces in php declaration due to technical restrictions on this site) I get returned emails saying...
Hi. This is the qmail-send program at myServerName. I'm afraid I wasn't able to deliver your message to the following addresses. This is a permanent error; I've given up. Sorry it didn't work out. myDomainName.com>: preline: fatal: unable to run /var/www/vhosts/myDomainName.com/cgi-bin/test/emailtophp.php: access deniedIt's the "access denied" bit I'm annoyed about. I've tried all I can. Running the script (without the pipe) directly from the command line works, but I can't get the file to execute when a mail has been sent to it. Gurr!!!
Figured it out - Qmail Working
Ok, I figured out what the problem was. Permissions! Yes, I did chmod 777 of the file (777 is dangerous, but good for debugging), but the cgi-bin (two levels beneath) didn't have the right permissions. So I changed the php file to be in a new purpose made directory under myDomainName.com called phpcgi (because I'm running php as cgi).
Then I ran:
chgrp popuser phpcgichown popuser phpcgi
chmod 777 phpcgi
And done the same for the file as for the directory.
It all works fine now! Phew.
access denied error
What I think
locate usernameForMyEmailAddressls -al/usr/bin/php /home/stempag/phpcgi/testrun.php|/usr/bin/php /home/stempag/phpcgi/testrun.phpMIME Parser
Access denied solved but mail delivery failed
Hm
Issues with Plesk & Piping
I've been ripping my hair out trying to figure out this issue.
I'm using the following:
Plesk 8.2 on linux system
bounces@domain is the email i'm setting up
I've edited the .qmail file located in /var/qmail/mailnames/domain/bounces/ with the following
|/usr/bin/php -q /path to php file/./Maildir/
I've chmod 755 the php file.
The beginning of the php file has the following
#!/usr/bin/php -q<?php
// read from stdin
$email = "";
$fp = fopen("php://stdin", "r");
while(!feof($fp)) $email .= fgets($fp, 4096);
fclose($fp);
After that i'm inputing the $email value into a database.
In order to test the system i'm sening an email to bounces@domain and i get a returned email with failure, and the information isn't submitted into the database.
My reply is as follows
bounces@domainNo Input File Specified.
can anyone help with this issue.
Email2HTTP for handling incoming email
email2php.com
Hosted by a company