Hi,

I just read thought a tutorial on how to email pipe via evolk.
When i try to send an email to the email address that is suppose to do the job, i get an error.
"Mail delivery failed: returning message to sender
pipe to |/home/username/public_html/pipe/email_pipe.php
generated by test@website.com
local delivery failed
"

I dont know what i am doing wrong. Any suggestions? My code is below:

#!/usr/bin/php
//header('Content-Type: text/html; charset=utf-8');
require_once ('includes/functions.inc.php');
require_once ('includes/mysql_connect.php');

// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
    $email .= fread($fd, 1024);
}
fclose($fd);

// handle email
$lines = explode("\n", $email);

// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;

//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;
    }
    
    $a = "RE: [119-24] Work Order Request - test - dsfsd";
    preg_match("/\[[0-9]*-[0-9]*\]/",$subject,$matches);
    list($jobid, $custid) = split('[-]', $matches[0]);
}
$cur_date = returnLocalDate();
$cur_time = returnLocalTime();
$insertQ = mysql_query("INSERT INTO test_pipe (job_id, cust_id, description, reply_date, reply_time, displayed) 
                        VALUES ($jobid, $custid, '$message', '$cur_date', '$cur_time', 1)") or trigger_error("Query: $insertQ\n<br />MySQL Error: " .mysql_error());                
if (mysql_affected_rows() > 0) {
    $new_reply_id = mysql_insert_id();
    echo $new_reply_id;
}

note: my Server API is CGI.

Recommended Answers

All 15 Replies

What is the command you're using in the pipe?

What MTA (mailserver) are you using.

What is the command you're using in the pipe?
What MTA (mailserver) are you using.

1. "| php -q /home/user/public_html/pipe/email_pipe.php"
2. php PHPMailer()

1. "| php -q /home/user/public_html/pipe/email_pipe.php"
2. php PHPMailer()

Are you using CPanel?

Try this for the pipe command:

| php -q /home/user/public_html/pipe/email_pipe.php >> /tmp/pipe_error.txt 2>&1

This redirects input and errors from the process to /tmp/pipe_error.txt

You can replace this with any file path.

Then read the file pipe_error.txt

See what is going wrong.

MTA's won't like it when any output is created by the process it sends the email to. It just see's this as an error.

Also the shebang really doesn't serve any purpose here.

#!/usr/bin/php

It is meant to tell the system which interpreter to use for the script, but in this case you're already using PHP. It really wouldn't matter though since PHP should interpret it as a comment...

If you have shell access to the server (ssh or telnet etc.) you could try executing a file with PHP and see if it works. That would be a start...

i get the following mail delivery system:

This message was created automatically by mail delivery software.

A message that you sent could not be delivered to one or more of its recipients. This is a permanent error. The following address(es) failed:

pipe to |/home/myuser/public_html/pipe/email_pipe.php >> /pipe/pipe_error.txt 2>&1
generated by test@milano4you.com

The following text was generated during the delivery attempt:

------ pipe to |/home/myuser/public_html/pipe/email_pipe.php >> /pipe/pipe_error.txt 2>&1
generated by test@milano4you.com ------

X-Powered-By: PHP/5.2.8
Content-type: text/html

I changed the forward to:
| php -q /home/myuser/public_html/pipe/email_pipe.php >> /pipe/pipe_error.txt 2>&1

But i dont see this file in folder "pipe"

????????

i get the following mail delivery system:

I changed the forward to:
| php -q /home/myuser/public_html/pipe/email_pipe.php >> /pipe/pipe_error.txt 2>&1

But i dont see this file in folder "pipe"

????????

Does the directory /pipe exist in the Root of your server? I'f you're not the root user, you won't be able to create it. Your PHP process won't be running as root, so it can't create it.

You probably want:

/home/myuser/pipe/pipe_error.txt

if you're not root.

If you are root, you have to make sure that folder is writable by the PHP process. ie: use chmod() or chown() as you see fit.

I added this forward:

All email sent to test@milano4you.com will now be copied to |/home/user/public_html/pipe/email_pipe.php >> /home/user/pipe/pipe_error.txt 2>&1


I get a mail delivery again, this is what it says:

This message was created automatically by mail delivery software. A message that you sent could not be delivered to one or more of its recipients. This is a permanent error. The following address(es) failed:

pipe to |/home/user/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1
generated by test@milano4you.com

The following text was generated during the delivery attempt:

------ pipe to |/home/user/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1
generated by test@milano4you.com ------

X-Powered-By: PHP/5.2.8
Content-type: text/html

1. I am using cPanel x3.
2. Reseller hosting package.
3. I put writeable permission on the pipe folder, as well as the .txt file.

What do u suggest?

I just noticed that you don't have php tags around your code.

Unlike most other scripting languages, the PHP interpreter requires the <?php tags to consider the code to be PHP.

If you haven't also remove the shebang. Though it should be ignored by the PHP interpreter, it doesn't serve any purpose.

You don't want even a single empty line, or space before your <?php tags.

Also make sure you have the full path to the PHP interpreter correct.

If you use:

| /home/user/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1

As your command, then make sure the shebang #!/usr/bin/php has the correct path to the PHP interpreter.

Or you can use:

| /usr/bin/php /home/user/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1

Where /usr/bin/php is the path to teh PHP interpreter.

You don't want the -q flag sent to the PHP interpreter as the previous commands you were using, since you now send errors to the log file.

If you have shell access, you should really just test out the commands you're using - it will give you instant feedback.

So now i changed my forward to:

| /home/user/public_html/pipe/email_pipe.php >> /home/user/pipe/pipe_error.txt 2>&1

My code didn't change, it looks like this:

#!/usr/bin/php
<?php
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
    $email .= fread($fd, 1024);
}
fclose($fd);

// handle email
$lines = explode("\n", $email);

// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;

//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;
    }
	
	$a = "RE: [119-24] Work Order Request - test - dsfsd";
	preg_match("/\[[0-9]*-[0-9]*\]/",$subject,$matches);
	list($jobid, $custid) = split('[-]', $matches[0]);
}
?>

I dont have shell access, because this is a shared reseller hosting.

I still get this error:

This message was created automatically by mail delivery software.

A message that you sent could not be delivered to one or more of its recipients. This is a permanent error. The following address(es) failed:

pipe to |/home/user/public_html/pipe/email_pipe.php >> /home/user/pipe/pipe_error.txt 2>&1
generated by test@milano4you.com

The following text was generated during the delivery attempt:

------ pipe to |/home/user/public_html/pipe/email_pipe.php >> /home/user/pipe/pipe_error.txt 2>&1
generated by test@milano4you.com ------

X-Powered-By: PHP/5.2.8
Content-type: text/html

Ask your hosting what the path to the PHP interpreter is. It probably isn't at /usr/bin/php

Like I mentioned before, it is better to use:

| /usr/bin/php /home/user/public_html/pipe/email_pipe.php >> /home/user/pipe/pipe_error.txt 2>&1

That way you dont need the shebang, and you don't need to make the file /home/user/public_html/pipe/email_pipe.php executable.

Just make sure the path to the interpreter is correct.

You can also test this by running the command from within PHP.

Get the text for a sample email message.

eg:

$email = '
To: user@example.com
From: "example.com" <test@example.com>
Subject: This is a test email
Message-ID: <blablalba@example.com>
X-Priority: 3
X-Mailer: PHPMailer [version 1.72]
MIME-Version: 1.0
Content-Type: text/plain

Hi Jim,

Example text, example text etc.
';

You can then feed this to your php script in the same way the MTA would. I've written a function to do this:

/**
 * Start a child process, and write input to it's STDIN
 * @return Array An array with the format array(stdout=>'', stderr=>'', return=>''). 
 * 
 * stdout - Standard Output from child process
 * stderr - Standard Error from child process
 * return - Return code of child process
 * 
 * @param $cmd String
 * @param $input String[optional]
 */
function childProcess($cmd, $input = '') {
	$pipe_descriptions = array(
	   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
	   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
	   2 => array("pipe", "w") // stderr is a pipe that the child will write to
	);
	if (is_resource($process = proc_open( $cmd , $pipe_descriptions, $pipes))) {
		// $pipes now looks like this:
	    // 0 => writeable handle connected to child stdin
	    // 1 => readable handle connected to child stdout
	    // 2 => readable handle connected to child stderr
		
		set_socket_blocking($pipes[0], 0);
	
	    fwrite($pipes[0], $input);
	    fclose($pipes[0]);
	
		// get the output
	    $return['stdout'] = stream_get_contents($pipes[1]);
	    fclose($pipes[1]);
		
		// get the errors
		$return['stderr'] =  stream_get_contents($pipes[2]);
	    fclose($pipes[2]);
	
	    // It is important that you close any pipes before calling
	    // proc_close in order to avoid a deadlock
		$return['code'] = proc_close($process);
		return $return;
	} else {
		trigger_error('Could not create child process.');
		return false;
	}
}

Now you can run your test as such:

$return = childProcess('/usr/bin/php /home/user/public_html/pipe/email_pipe.php >> /home/user/pipe/pipe_error.txt 2>&1', $email);

var_dump($return);

See what you get returned.

Or to have errors displayed directly.

$return = childProcess('/usr/bin/php /home/user/public_html/pipe/email_pipe.php', $email);
var_dump($return);

If it gives an error like, "/usr/bin/php - no such file or directory", then that means it cannot find the php executable.

I changed the forward to:
All email sent to test@milano4you.com will now be copied to |/usr/lib/php /home/milano4y/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1

I copied your code, but when i try to test it, i get an error:
url: http://www.milano4you.com/pipe/test.php
Error: Warning: proc_open() has been disabled for security reasons in /home/milano4y/public_html/pipe/test.php on line 42

Line 42: if (is_resource($process = proc_open( $cmd , $pipe_descriptions, $pipes))) {

I asked the hosting company to enable proc_open(), but they told me since im on a shared reseller hosting, they cannot allow that.

Btw, thanks so much for your time and patience with this :)

What else can we do?

By the way, this is the test.php code:

<?
$email = '
	To: test@milano4you.com
	From: "meytal@dachooch.com" <meytal@dachooch.com>
	Subject: This is a test email
	Message-ID: <meytal@dachooch.com>
	X-Priority: 3
	X-Mailer: PHPMailer [version 1.72]
	MIME-Version: 1.0
	Content-Type: text/plain
	
	Hi Jim,
	
	Example text, example text etc.
';



/**
 * Start a child process, and write input to it's STDIN
 * @return Array An array with the format array(stdout=>'', stderr=>'', return=>''). 
 * 
 * stdout - Standard Output from child process
 * stderr - Standard Error from child process
 * return - Return code of child process
 * 
 * @param $cmd String
 * @param $input String[optional]
 */
function childProcess($cmd, $input = '') {
	$pipe_descriptions = array(
	   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
	   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
	   2 => array("pipe", "w") // stderr is a pipe that the child will write to
	);
	if (is_resource($process = proc_open( $cmd , $pipe_descriptions, $pipes))) {
		// $pipes now looks like this:
	    // 0 => writeable handle connected to child stdin
	    // 1 => readable handle connected to child stdout
	    // 2 => readable handle connected to child stderr
		
		set_socket_blocking($pipes[0], 0);
	
	    fwrite($pipes[0], $input);
	    fclose($pipes[0]);
	
		// get the output
	    $return['stdout'] = stream_get_contents($pipes[1]);
	    fclose($pipes[1]);
		
		// get the errors
		$return['stderr'] =  stream_get_contents($pipes[2]);
	    fclose($pipes[2]);
	
	    // It is important that you close any pipes before calling
	    // proc_close in order to avoid a deadlock
		$return['code'] = proc_close($process);
		return $return;
	} else {
		trigger_error('Could not create child process.');
		return false;
	}
}


$return = childProcess('/usr/lib/php /home/milano4y/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1', $email);

var_dump($return);
?>

any ideas?

Try piping to an empty PHP script.

See if that gives a different error message, or works, etc.

Also put an exit(0);

At the end of your PHP script just in case the MTA is waiting for a clean exit status.

You could also try piping some other program and seeing if it works. Eg: to a bash shell script, or perl etc.

didnt work.

this is the email error i get:

This message was created automatically by mail delivery software.

A message that you sent could not be delivered to one or more of its recipients. This is a permanent error. The following address(es) failed:

pipe to |/usr/lib/php /home/milano4y/public_html/pipe/email_pipe.php >> /home/milano4y/pipe/pipe_error.txt 2>&1
generated by test@milano4you.com
local delivery failed

OK i found the solution:

for cPanel "fowarder", add the following line:

| php -q -n /home/youruser/public_html/scriptfile.php

(make sure the script file is CMOD 777)

In the scriptfile.php page, add the following:

#!/usr/bin/php -q
<?php
header('Content-Type: text/html; charset=utf-8');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");    // Date in the past 
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");  // always modified 
header("Cache-Control: no-store, no-cache, must-revalidate");  // HTTP/1.1 
header("Cache-Control: post-check=0, pre-check=0", false); 
header("Pragma: no-cache");                          // HTTP/1.0  
date_default_timezone_set('America/New_York');
ob_start();

// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
    $email .= fread($fd, 1024);
}
fclose($fd);

// handle email
$lines = explode("\n", $email);

// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;

//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;
    }
}
return true;
ob_end_flush();
?>

thanks for all your help :)
hope this helps someone else along the lines.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.