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.
Related
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.
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.
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;
}
}
I am having trouble storing data with emails coming from OUTLOOK. I am using a pipe script to store data from incoming emails into an SQL Table but the issue is that if the email is coming from OUTLOOK, it is separated by ; instead of , So the email addresses in the 'TO' or 'CC' field are not stored in the table, only the first addressee gets stored. It works normally with all other emails. How do I tackle this issue ? Here is the code I am using:
#!/usr/bin/php-cli -c /home/abc/
<?php
// Config
$dbuser = 'abc_user';
$dbpass = '1234';
$dbname = 'abc_testing';
$dbhost = 'localhost';
$notify= 'abc#def.com'; // an email address required in case of errors
function mailRead($iKlimit = "")
{
if ($iKlimit == "") {
$iKlimit = 1024;
}
// Error strings
$sErrorSTDINFail = "Error - failed to read mail from STDIN!";
// Attempt to connect to STDIN
$fp = fopen("php://stdin", "r");
// Failed to connect to STDIN? (shouldn't really happen)
if (!$fp) {
echo $sErrorSTDINFail;
exit();
}
// Create empty string for storing message
$sEmail = "";
// Read message up until limit (if any)
if ($iKlimit == -1) {
while (!feof($fp)) {
$sEmail .= fread($fp, 1024);
}
} else {
while (!feof($fp) && $i_limit < $iKlimit) {
$sEmail .= fread($fp, 1024);
$i_limit++;
}
}
// Close connection to STDIN
fclose($fp);
// Return message
return $sEmail;
}
$email = mailRead();
// 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 {
// not a header, but message
$message .= $lines[$i]."\n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
if ($conn = #mysql_connect($dbhost,$dbuser,$dbpass)) {
if(!#mysql_select_db($dbname,$conn))
mail($email,'Email Logger Error',"There was an error selecting the email logger database.\n\n".mysql_error());
$from = mysql_real_escape_string($from);
$to = mysql_real_escape_string($to);
$subject = mysql_real_escape_string($subject);
$headers = mysql_real_escape_string($headers);
$message = mysql_real_escape_string($message);
$email = mysql_real_escape_string($email);
$result = #mysql_query("INSERT INTO emails (`FROM`,`SUBJECT`,`TO`,`CC`) VALUES('$from','$subject','$to','$headers')");
if (mysql_affected_rows() == 0)
mail($notify,'Email Logger Error',"There was an error inserting into the email logger database.\n\n".mysql_error());
} else {
mail($notify,'Email Logger Error',"There was an error connecting the email logger database.\n\n".mysql_error());
}
?>
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);
}