PHP pipe to script email - php

I am trying to forward all emails from support#example.com to PHP script to be inserted into MySql.
My script works, but I have two issues.
The from email address shows the name of the sender, not the email address.
The email body content shows for eg.
--00000000000095430105a9347fe3
Content-Type: text/plain; charset="UTF-8"
This is a test email
--00000000000095430105a9347fe3
Content-Type: text/html; charset="UTF-8"
This is a test email
--00000000000095430105a9347fe3--
Instead of just the body of the email This is a test email
This is my code:
// handle email
$lines = explode("\n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
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];
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
} else {
// content/main message body information
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
I have tried
$message = imap_fetchbody($mbox,1,'1');
$message = strip_tags(quoted_printable_decode(imap_fetchbody($mbox,1,"1")));
$message = strip_tags($message, '<body>');
$message = explode(">", $message);
$message = explode("<", $message[1]);
$message = str_replace(" ", "", $message[0]);
$message = html_entity_decode($message);
$message = trim($message);
And I tried this but could not figure out how to make it work:
$emailnumberPattern = "--[0]{12}";
$replacement = " ";
preg_replace($emailnumberPattern, $replacement, $string);
$message .= $lines[$i]."\n";
Any help would be welcome to show the sender email as well as remove unwanted content from the email body.

Parsing emails is no easy task that can be solved with a couple of regexes. You should definitely use a dedicated extension or program. Also, you shold avoid loading the entire message into a single string (or array).
This one is just a single composer command away: composer require zbateson/mail-mime-parser.
require __DIR__ . '/vendor/autoload.php';
$handle = fopen('php://stdin', 'r');
$message = \ZBateson\MailMimeParser\Message::from($handle);
fclose($handle);
$from = $message->getHeaderValue('from');
$body = $message->getTextContent();
That said, you can obtain some results with your code, which I've modified as little as possible:
$lines = explode("\n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
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];
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
} else {
if (preg_match('/Content-Type: text\/plain; charset=/', $lines[$i])) {
$m = true;
continue;
}
if (preg_match('/Content-Type:/', $lines[$i])) {
$m = false;
}
if ($m) {
$message .= $lines[$i]."\n";
}
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
if (preg_match('/ <(.*)>/', $from, $matches)){
$from = $matches[1];
}
Those results are not guaranteed, and highly dependent on the input format. For a robust solution, please use a well-tested parser.

Related

Email Piping with PHP Script using cpanel

I am trying to email piping with cpanel and PHP script. Its working fine. I am looking for get From Address, Subject and Message from received email. My script is like below
#!/usr/bin/php -q
<?php
/*$fd = fopen( "php://stdin", "r" );
$message = "";
while ( !feof( $fd ) )
{
$message .= fread( $fd, 1024 );
}
fclose( $fd );*/
$fd = fopen("php://stdin", "r");
$message = "";
while (!feof($fd)) {
$message .= fread($fd, 1024);
}
fclose($fd);
//split the string into array of strings, each of the string represents a single line, received
$lines = explode("\n", $message);
// initialize variable which will assigned later on
$from = "";
$subject = "";
$headers = "";
$message = "";
$is_header= true;
//loop through each line
for ($i=0; $i < count($lines); $i++) {
if ($is_header) {
// hear information. instead of main message body, all other information are here.
$headers .= $lines[$i]."\n";
// Split out the subject portion
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
//Split out the sender information portion
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
} else {
// content/main message body information
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$is_header = false;
}
}
$to = 'myemail#gmail.com';
$subject = 'the subject';
$message1 = "You have new message from :".$from. "and message is" .$message;
$headers = 'From: webmaster#mydomain.com' . "\r\n" .
'Reply-To: webmaster#mydomain.com' . "\r\n" .
'X-Mailer: PHP/' . phpversion();
mail($to, $subject, $message1, $headers);
?>
I am getting result in my email like below
You have new message from :FirstName LastName <senderemail#gmail.com>and message is--00000000000045a1e5059ef97af8
Content-Type: text/plain; charset="UTF-8"
This is Body text Message
--00000000000045a1e5059ef97af8
Content-Type: text/html; charset="UTF-8"
<div dir="ltr"><div class="gmail_default" style="font-family:georgia,serif;font-size:large">This is text<br></div></div>
--00000000000045a1e5059ef97af8--
However its contain unnecessary words in it. I want plain output like below
You have new message from :senderemail#gmail.com and message is This is Body text Message
Sorry I am new in PHP and does not able to solve the issue. Let me know if anyone can help me for extract and get output like this.
Thanks!

email pipe to PHP script and forward to another email

I am trying to write a script which will be used to get emails piped to it and then forwarded to another email address with a different "From" field
#!/usr/local/bin/php56 -q
<?php
$fd = fopen("php://stdin", "r");
$message = "";
while (!feof($fd)) {
$message .= fread($fd, 1024);
}
fclose($fd);
//split the string into array of strings, each of the string represents a single line, received
$lines = explode("\n", $message);
// initialize variable which will assigned later on
$from = emailFrom#example.com;
$subject = "";
$headers = "";
$message = "";
$is_header= true;
//loop through each line
for ($i=0; $i < count($lines); $i++) {
if ($is_header) {
// hear information. instead of main message body, all other information are here.
$headers .= $lines[$i]."\n";
// Split out the subject portion
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
//Split out the sender information portion
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
} else {
// content/main message body information
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$is_header = false;
}
}
mail( "emailTo#example.com", $subject,$message, $from );
?>
this script is getting us bounced emails with delivery failure message "local delivery failed".
What am I doing wrong?
You need to verify that it's parsing the incoming messages properly. Add this line following your mail() command to verify the script's output:
echo "Subject:".$subject."\nFrom:".$from."\nMessage:".$message;
Then pass the script a test email from the command line and watch the screen. Something probably isn't getting parsed correctly.

Email Piping - Read Attachment (.txt file)

I'm using email piping to save data sent by an end user through email; however, one requirement is that the user sends a text file with additional information.
Therefore, I need the email piping script to get the attachment, and read it. It's a simple text (.txt) document, base64 encoding, example:
Content-Type: text/plain; charset=UTF-8
Content-ID: <text_doc>
Content-Location: text_doc.txt
Content-Transfer-Encoding: BASE64
This is my Email Piping script. The email passes through fine, I just need to get the attachment.
<?php
chdir(dirname(__FILE__));
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
if(strlen($email)<1) {
die();
}
// handle email
$lines = explode("\n", $email);
// empty vars
$from = "";
$to="";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
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];
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}

passing paremeters from PHP Email piping

I have a PHP Script that received information from a piped email forwarder.
Currently everything works perfectly. I just want to manipulate the received parameters to receive only the data I want from the email
the script is:
#!/usr/local/bin/php -q
<?PHP
//get email
$fd = fopen("php://stdin", "r");
$email_content = "";
while (!feof($fd)) {
$email_content .= fread($fd, 1024);
}
fclose($fd);
//get email end
//get variables from email start
//split the string into array of strings, each of the string represents a single line, recieved
$lines = explode("\n", $email_content);
// initialize variable which will assigned later on
$from = "";
$subject = "";
$headers = "";
$message = "";
$is_header= true;
//loop through each line
for ($i=0; $i < count($lines); $i++) {
if ($is_header) {
// hear information. instead of main message body, all other information are here.
$headers .= $lines[$i]."\n";
// Split out the subject portion
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
//Split out the sender information portion
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
} else {
// content/main message body information
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$is_header = false;
}
}
Currently, the variable $email returns:
"Person name" <person#domain.net>
How can I modify this variable to only get the email portion?
Secondly, the variable message returns a whole pile of data including formatting and tags as below:
This is a multipart message in MIME format.
------=_NextPart_000_0031_01CD9CA8.9BE5F470
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
testing
------=_NextPart_000_0031_01CD9CA8.9BE5F470
Content-Type: text/html;
charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
<html xmlns:v=3D"urn:schemas-microsoft-com:vml" = xmlns:o=3D"urn:schemas-microsoft-com:office:office" = xmlns:w=3D"urn:schemas-microsoft-com:office:word" = xmlns:m=3D"http://schemas.microsoft.com/office/2004/12/omml" = xmlns=3D"http://www.w3.org/TR/REC-html40"><head><META = HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; = charset=3Dus-ascii"><meta name=3DGenerator content=3D"Microsoft Word 14 = (filtered medium)"><style><!--
/* Font Definitions */
#font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
span.EmailStyle17
{mso-style-type:personal-compose;
font-family:"Calibri","sans-serif";
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri","sans-serif";}
#page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext=3D"edit" spidmax=3D"1026" /> </xml><![endif]--><!--[if gte mso 9]><xml> <o:shapelayout v:ext=3D"edit"> <o:idmap v:ext=3D"edit" data=3D"1" /> </o:shapelayout></xml><![endif]--></head><body lang=3DEN-US link=3Dblue = vlink=3Dpurple><div class=3DWordSection1><p class=3DMsoNormal>Ninety = nine<o:p></o:p></p></div></body></html>
------=_NextPart_000_0031_01CD9CA8.9BE5F470--
. I want to extract only the content of my body in plain text. so if body of email was simply 'testing' then I want the variable to return testing?
Help appreciated as always.
Thanks again.
edit as per #hakra
#!/usr/local/bin/php -q
<?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;
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;
}
}
$buffer = [$email] // Mail Content from Pipe
$mail = mailparse_msg_create();
mailparse_msg_parse($mail, $buffer);
$struct = mailparse_msg_get_structure($mail);
foreach ($struct as $st) {
$section = mailparse_msg_get_part($mail, $st);
$info = mailparse_msg_get_part_data($section);
}
?>
You can parse address lines with imap_rfc822_parse_adrlistDocs or mailparse_rfc822_parse_addressesDocs.
To parse the body of the email message, you can make use of the Mail Parse extensionDocs:
$buffer = [...] // Mail Content from Pipe
$mail = mailparse_msg_create();
mailparse_msg_parse($mail, $buffer);
$struct = mailparse_msg_get_structure($mail);
foreach ($struct as $st) {
$section = mailparse_msg_get_part($mail, $st);
$info = mailparse_msg_get_part_data($section);
print_r($info);
}

php email piping

Im trying to setup a program that will accept an incoming email and then break down the "sender" and "message" into php variables that i can then manipulate as needed, but im unsure where to start.
I already have the email address piped to the php file in question (via cpanel)
Start with:
$lines = explode("\n",$message_data);
$headers = array();
$body = '';
$in_body = false;
foreach($lines as $line)
{
if($in_body)
{
$body .= $line;
}
elseif($line == '')
{
$in_body = true;
}
else
{
list($header_name,$header_value) = explode(':',$line,2);
$headers[$header_name] = $header_body;
}
}
// now $headers is an array of all headers and you could get the from address via $headers['From']
// $body contains just the body
I just wrote that off the top of my head; haven't tested for syntax or errors. Just a starting point.
Have a look at the eZ Components ezcMailParser class. You'll need to implement an interface - ezcMailParserSet - to use it.
Here is working solution
#!/usr/bin/php -q
<?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;
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;
}
}
echo $from;
echo $subject;
echo $headers;
echo $message;
?>
Works like a charm.

Categories