PHP - Error in IMAP command STORE: Invalid messageset - php

I'm using imap with php and I found this error:
Unknown: IMAP protocol error: Error in IMAP command STORE: Invalid messageset (0.001 + 0.000 secs). (errflg=2)
This happens only with some mailboxes (ex. one hosted on misterdomain.eu).
The error occurs at the end of the script, after imap_close().
This is the simple code. If you have any suggest (far to my first problem), is really accepted.
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect: ' . imap_last_error());
$emails = imap_search($inbox,'SINCE "'.date("d-M-y",strtotime("-3 days")).'"',SE_UID);
if($emails) {
rsort($emails);
foreach($emails as $email_number) {
echo "<h1>".$email_number."</h1>";
$overview = imap_fetch_overview($inbox,$email_number, FT_UID);
if($overview[0]->seen)
imap_clearflag_full($inbox,$email_number,"//Seen");
else
imap_clearflag_full($inbox,$email_number,"//Unseen");
$structure = imap_fetchstructure($inbox,$email_number, FT_UID);
if(isset($structure->parts)){
$flattenedParts = flattenParts($structure->parts);
echo "<pre>";
print_r($flattenedParts);
echo "</pre>";
echo "</br>";
getmsg($inbox, $email_number);
echo "<p>".htmlspecialchars_decode(utf8_decode($plainmsg))."</p>";
}else{
$string_email = utf8_decode(imap_body($inbox, $email_number, FT_UID));
$string_email= strip_tags($string_email);
$string_email = html_entity_decode($string_email,ENT_QUOTES);
echo "<p>".$string_email."</p>";
}
}
}
imap_close($inbox);

You are searching and fetching using UIDs, but storing using message sequence numbers. These ways of numbering the messages don't match, so you are sending invalid message numbers to store. Add the approriate ST_UID flag to imap_clearflag_full.
Also, the system flags use backslashes, not forward slashes: '\\Seen'.
\Unseen isn't a defined flag. You probably want to add the \Seen flag instead.

Related

issues with IMAP functions php

I am facing some problem with imap function. Basically What I need to do is to read unseen mails. There will be a url in all the mails, i should fetch that URL and store.
$inbox = imap_open($hostname,$username,$password);
if($inbox)//if **1
{
/* grab emails */
$emails = imap_search($inbox,'UNSEEN');
/* if emails are returned, cycle through each... */
if($emails) //if **2
{
/* put the newest emails on top */
rsort($emails);
/* for every email... */
$varients=array("1","1.1","1.2","2");
foreach($emails as $email_number) //for loop **1
{
$ids [] = $email_number;
foreach($varients as $cur_varient) //for loop **2
{
echo "\n\nstarting with imap function number ". $cur_varient."\n\n";
$overview = imap_fetch_overview($inbox,$email_number,0);//all varients of like subject, date etc.
$from = addslashes(trim($overview[0]->from));
$inboxed_time = addslashes(trim(strtotime($overview[0]->date)));
$message = (imap_body($inbox,$email_number,$cur_varient));
print addslashes(trim($overview[0]->subject));break;
preg_match_all('#\bhttp?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#', $message, $match);
$link_matched = $match[0];
$input = 'unsubscribe.php';
$linkexists = false;
foreach($link_matched as $curlink)
{
if(stripos($curlink, $input) !== false)
{
$linkexists = true;
$unsublink = $curlink;
$unsublink = str_replace('href="', '', $unsublink);
$unsublink = str_replace('"', '', $unsublink);
break;
}
}
if(isset($unsublink))
{
$unsublink = addslashes(trim(($unsublink)));
$thread = 1;
$time = date("Y-m-d H:i:s");
$iQry = " INSERT INTO `SPAMS`.url_queue VALUES(";
$iQry .= " 'default','".$unsublink."','".$thread."','";
$iQry .= "".$from."','".$inboxed_time."',UNIX_TIMESTAMP('".$time."'))";
//mysql_query($iQry);
print $iQry;
}
}//closing for loop **2
}//closing for loop **1
} //closing if **2
// Setting flag from un-seen email to seen on emails ID.
if(isset($ids))
{
imap_setflag_full($inbox,implode(",", $ids), "\\Seen \\Flagged"); //IMPORTANT
}
// colse the connection
imap_expunge($inbox);
imap_close($inbox);
}//closing if **1
I have used all different varients of imap to make sure it will read different types of mails. Now issue is, sometime the URL matched is broken. Only half URL will be fetched(I printed the entire message, saw that half URL is coming to next line). The other issue is, sometimes, the body fetched will not be the one which the current mail contains. It fetched some other mail content.
I am puzzled what to do, so putting my entire code, please help.
You will have to use a regex modifiers to match multiline texts too, or you can strip newlines and such from the body of the emails.
preg_match("/{pattern}/mi",'Testing');
//m for multiline matches and i for case-insensitive matches
Your second issue is a bit different than you'd think, emails have multiple bodies, one for simple texts, one for html, some for attachments (and their order is different in apple products).
https://www.electrictoolbox.com/php-imap-message-parts/
You are probably facing the issue of grabbing the wrong one. My recommendation would be to fetch all of the email bodies, like this:
$overview = imap_fetch_overview($this->connection, $email_number, 0);
$structure = imap_fetchstructure($this->connection, $email_number);
$message = "";
//$parts = [1, 1.1, 1.2, 2];
if (!$structure->parts)//simple email
$message .= "Simple: ". imap_fetchbody($this->connection, $email_number, 0). "<br/>";
else {
foreach ($structure->parts as $partNumber=>$part){
if ($partNumber != 0)
$message .= "Part ".$partNumber.": ". imap_fetchbody($this->connection, $email_number, $partNumber)."<br/>";
}
}

How to read the Content Type header and convert into utf-8 while Gmail IMAP has utf8 and Outlook has ISO-8859-7?

So I get emails using imap from gmail and outlook.
Gmail encodes like this =?UTF-8?B?UmU6IM69zq3OvyDOtc68zrHOuc67IG5ldyBlbWFpbA==?=
and outlook encodes like this =?iso-8859-7?B?UmU6IOXr6+ft6er8IHN1YmplY3Q=?=
Unfortunately I did not find yet any solution that will help me make this into readable text. Instead I am messing with:
mb_convert_encoding($body, "UTF-8", "UTF-8");
and
mb_convert_encoding($body, "UTF-8", "iso-8859-7");
but I am struggling to find a solution to solve this matter.
This is how I open the IMAP of my account (which has a lot of gmail and outlook messages)
$hostname = '{imappro.zoho.com:993/imap/ssl}INBOX';
$username = 'email#email.com';
$password = 'password';
/* try to connect */
$inbox = imap_open($hostname,$username ,$password) or die('Cannot connect to Zoho: ' . imap_last_error());
/* grab emails */
$emails = imap_search($inbox,'UNSEEN');
Any help?
Unfortunately I did not find yet any solution that will help me make
this into readable text.
Solution
Your strings are base64 encoded.
=?UTF-8?B?UmU6IM69zq3OvyDOtc68zrHOuc67IG5ldyBlbWFpbA==?=
echo base64_decode('UmU6IM69zq3OvyDOtc68zrHOuc67IG5ldyBlbWFpbA==');
prints "Re: νέο εμαιλ new email"
=?iso-8859-7?B?UmU6IOXr6+ft6er8IHN1YmplY3Q=?=
echo base64_decode('UmU6IOXr6+ft6er8IHN1YmplY3Q=');
prints out "Re: subject"
The answer is to use base64_decode in conjunction with your current solutions.
The way to identify base64 encoded text is that it's depicted as letters a-z, A-Z, numbers 0-9 along with two other characters (usually + and /) and it's usually right padded with =.
EDIT:
Sorry, I was already forgetting that the question was to convert from iso-8859-7 to UTF-8 and have it visible.
<?php
$str = base64_decode('UmU6IPP03evt+SDs3u317OE=');
$str = mb_convert_encoding($str,'UTF-8','iso-8859-7');
echo $str;
?>
The result is "Re: στέλνω μήνυμα"
look here
/* connect to gmail */
$hostname = '{imap.gmail.com:993/imap/ssl}INBOX';
$username = 'davidwalshblog#gmail.com';
$password = 'davidwalsh';
/* try to connect */
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to Gmail: ' . imap_last_error());
/* grab emails */
$emails = imap_search($inbox,'ALL');
/* if emails are returned, cycle through each... */
if($emails) {
/* begin output var */
$output = '';
/* put the newest emails on top */
rsort($emails);
/* for every email... */
foreach($emails as $email_number) {
/* get information specific to this email */
$overview = imap_fetch_overview($inbox,$email_number,0);
$message = imap_fetchbody($inbox,$email_number,2);
/* output the email header information */
$output.= '<div class="toggler '.($overview[0]->seen ? 'read' : 'unread').'">';
$output.= '<span class="subject">'.$overview[0]->subject.'</span> ';
$output.= '<span class="from">'.$overview[0]->from.'</span>';
$output.= '<span class="date">on '.$overview[0]->date.'</span>';
$output.= '</div>';
/* output the email body */
$output.= '<div class="body">'.$message.'</div>';
}
echo $output;
}
/* close the connection */
imap_close($inbox);
for reading and decoding look here
<?php
$hostname = '{********:993/imap/ssl}INBOX';
$username = '*********';
$password = '******';
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to server: ' . imap_last_error());
$emails = imap_search($inbox,'ALL');
if($emails) {
$output = '';
rsort($emails);
foreach($emails as $email_number) {
$overview = imap_fetch_overview($inbox,$email_number,0);
$structure = imap_fetchstructure($inbox, $email_number);
if(isset($structure->parts) && is_array($structure->parts) && isset($structure->parts[1])) {
$part = $structure->parts[1];
$message = imap_fetchbody($inbox,$email_number,2);
if($part->encoding == 3) {
$message = imap_base64($message);
} else if($part->encoding == 1) {
$message = imap_8bit($message);
} else {
$message = imap_qprint($message);
}
}
$output.= '<div class="toggle'.($overview[0]->seen ? 'read' : 'unread').'">';
$output.= '<span class="from">From: '.utf8_decode(imap_utf8($overview[0]->from)).'</span>';
$output.= '<span class="date">on '.utf8_decode(imap_utf8($overview[0]->date)).'</span>';
$output.= '<br /><span class="subject">Subject('.$part->encoding.'): '.utf8_decode(imap_utf8($overview[0]->subject)).'</span> ';
$output.= '</div>';
$output.= '<div class="body">'.$message.'</div><hr />';
}
echo $output;
}
imap_close($inbox);
?>
Look here for great tutorial on email structure, and function to extract it.
If you want to decode header elements, there is a PHP function for that: imap_mime_header_decode().
Also, you will need some MIME parser class to decode multipart messages.
To get the headers, you would pass your stream ($inbox) to imap_headers(). There are lots of values you can get in the response, full list: imap_headerinfo
For the actual messages, plain text can be read using imap_body(), passing the stream and the number of the message you want (in $emails after your search). Getting an html/multipart email is a bit trickier. First you need imap_fetchstructure(), which identifies the parts of the message, then imap_fetchbody() to get the piece you are interested in.
Once you have a result from imap_fetchbody(), if you still need to adjust the encoding, it could be done at this point.
I had a task to receive letters from a certain mailbox, parse them and index certain content.
I wanted to have some microservice that would provide me with the data.
Downloading the required content
Convert the received data into a readable format
process the content
So I decided to use ready-made tools.
script for getting emails - imap2maildir
Unix client for processing messages mu
dos2unix converter
Next, I wrote a small bash script that I placed in cron
#!/bin/bash
python /var/mail_dump/imap2maildir/imap2maildir -c /var/mail_dump/imap2maildir/deploy.conf
mu index --maildir=/var/mail_dump/dumps/new
#clean old data
rm -rf /var/mail_dump/extract/*
#search match messages
mu find jivo --fields="l" --nocolor | xargs $1 cp -t /var/mail_dump/extract
#converting
dos2unix -f /var/mail_dump/extract/*
#reassembly of messages in html
cd /var/mail_dump/extract/
for i in /var/mail_dump/extract/*
do
mu extract --parts=0 --overwrite "$i"
rm "$i"
done
Complete !
I got a service that constantly receives emails and prepares them for processing.
php work with the prepared data without thinking about the implementation of low-level logic.

How to copy email from Gmail to my server using PHP IMAP?

How can I copy email from Gmail to my server's /home/email directory after connecting to a Gmail mailbox using PHP's IMAP functionality?
I want to retrieve every email as a file in MIME format and I want to download the complete MIME file with PHP, not just the body or header of the email. Because of this, imap_fetchbody and imap_fetchheader can't do the job.
Also, it seems imap_mail_copy and imap_mail_move can't do the job because they are designed to copy / move email to mailboxes:
imap_mail_copy: Copy specified messages to a mailbox.
imap_mail_move: Move specified messages to a mailbox.
PHP will download the full MIME message from Gmail or any IMAP server using imap_fetchbody when the $section parameter is set to "". This will have imap_fetchbody retrieve the entire MIME message including headers and all body parts.
Short example
$mime = imap_fetchbody($stream, $email_id, "");
Long example
// Create IMAP Stream
$mailbox = array(
'mailbox' => '{imap.gmail.com:993/imap/ssl}INBOX',
'username' => 'my_gmail_username',
'password' => 'my_gmail_password'
);
$stream = imap_open($mailbox['mailbox'], $mailbox['username'], $mailbox['password'])
or die('Cannot connect to mailbox: ' . imap_last_error());
if (!$stream) {
echo "Cannot connect to mailbox\n";
} else {
// Get last week's messages
$emails = imap_search($stream, 'SINCE '. date('d-M-Y',strtotime("-1 week")));
if (!count($emails)){
echo "No emails found\n";
} else {
foreach($emails as $email_id) {
// Use "" for section to retrieve entire MIME message
$mime = imap_fetchbody($stream, $email_id, "");
file_put_contents("email_{$email_id}.eml", $mime);
}
}
// Close our imap stream.
imap_close($stream);
}

how can I display the contents of an email to a website?

I would like to display the body contents of an email. I have tried IMAP in php but something is VERY wrong. The IMAP isn't picking up the body of my message. It is picking up ONLY the signature in the body. So I am looking for alternative methods of reading email body contents to a webpage.
here is the original document of my email:
http://pastebin.com/WQra335P
the disclaimer/copyright blur is being grabbed by IMAP but nothing else in the body is being displayed. anyone have alternative methods of reading email from gmail or any other site that can display the contents to a webpage?
I have given up on making IMAP read it because no one has been able to figure out the problem...I have spent hours so I give up but here is the code...
<?php
/* connect to gmail */
$hostname = '{imap.gmail.com:993/imap/ssl}INBOX';
$username = 'username#gmail.com';
$password = 'password';
/* try to connect */
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to Gmail: ' . imap_last_error());
/* grab emails */
$emails = imap_search($inbox,'ALL');
/* if emails are returned, cycle through each... */
if($emails) {
/* begin output var */
$output = '';
/* put the newest emails on top */
rsort($emails);
/* for every email... */
foreach($emails as $email_number) {
/* get information specific to this email */
$overview = imap_fetch_overview($inbox, $email_number, 0);
$message = imap_fetchbody($inbox, $email_number, 2);
echo $message;
echo imap_qprint($message);
$message = imap_qprint($message);
echo imap_8bit ($message);
$DateFormatted = str_replace("-0500", "", $overview[0] -> date);
/* output the email header information */
$output .= $overview[0] -> subject ;
$output .= $DateFormatted ;
//$bodyFormatted = preg_replace("/This e-mail(.*)/","",$message);
//$bodyFormatted = preg_replace("/Ce courriel(.*)/","",$bodyFormatted);
/* output the email body */
$output .= $message;
}
echo $output;
}
/* close the connection */
imap_close($inbox);
?>
In Addition to what DmitryK suggested,
Adding the below makes everything work fine without the random "=" signs. The Str_replace is used to remove the "="s generated over the pages.
$message = imap_fetchbody($inbox, $email_number, "1.1");
$message = str_replace("=", "", $message);
I dont know 100% why the "="s are generated randomly but this is most likely due to some encryption issue from the Exchange Server's side as our server is about 10 years old.
You are dealing with the multi-part messages (looking at your pastebin e-mail sample).
As a test try using this line:
$message = imap_fetchbody($inbox, $email_number, "1.1");
Plain text version lives under 1.1
HTML version is 1.2
The signature is in the next part - it is 2. And this is what you retrieve in your code sample.
Do you have access to the raw email content (the stuff with all the headers etc)
If so, try using plancacke email parser
I have used it before with good success.
$emailParser = new PlancakeEmailParser(...raw email content...);
$emailTo = $emailParser->getTo();
$emailSubject = $emailParser->getSubject();
$emailCc = $emailParser->getCc();
$emailDeliveredToHeader = $emailParser->getHeader('Delivered-To');
$emailBody = $emailParser->getPlainBody();
$emailHtml = $emailParser->getHTMLBody();
Gmail has some different IMAP settings, follow the original code more closely:
http://davidwalsh.name/gmail-php-imap

How would I move a message from Gmail Inbox to a label?

I'm trying to move messages away from Inbox into Processed label with this code:
$inbox = imap_open($host,$user,$pass) or die('Error: ' . imap_last_error());
if( $emails = imap_search($inbox,'ALL') )
{
foreach($emails as $email_number) {
imap_mail_move($inbox, $email_number, 'Processed') or die('Error');
}
}
imap_expunge($inbox);
imap_close($inbox);
Unfortunately, while the messages get the Processed label, they're still left in Inbox too.
How would I make them go away from Inbox?
Actually... The reason why the emails were left in the inbox was that when imap_mail_move did it's thing, the IDs of all the leftover messages got decremented by one, so when the foreach loop moved to the next message, one message was left behind. This skipping a message repeated for every iteration. That's why it seemed that imap_mail_move was not working.
The solution is to use unique message UIDs instead of potentially repeating IDs:
$inbox = imap_open( $host, $user, $pass );
$emails = imap_search( $inbox, 'ALL', SE_UID );
if( $emails ) {
foreach( $emails as $email_uid ) {
imap_mail_move($inbox, $email_uid, 'processed', CP_UID);
}
}
You have to move the message to the "[Gmail]/All Mail" folder, after you "move it" to a tag folder which is not really a folder as Gmail see's it, just letting Gmail know to add that tag.
So through IMAP:
1) When a message is moved to "[Gmail]/TAG" folder it tells Gmail to add the "TAG" to the message, but does not do any sort of moving of the message.
2) When a message is moved to "[Gmail]/All Mail" folder it tells Gmail to remove it from the Inbox.
#Henno, your diagnosis is correct but you could have simply sorted the emails in descending order.
$inbox = imap_open($host,$user,$pass) or die('Error: ' . imap_last_error());
if( $emails = imap_search($inbox,'ALL') )
{
arsort($emails); //JUST DO ARSORT
foreach($emails as $email_number) {
imap_mail_move($inbox, $email_number, 'Processed') or die('Error');
}
}
imap_expunge($inbox);
imap_close($inbox);
Place this at the end of your file, after you have processed any emails, this will move all found in the inbox, and move them to a folder called 'done'.
$mbox = imap_open('{imap.gmail.com:993/imap/ssl}INBOX', 'emailaddress#gmail.com', 'password');
$countnum = imap_num_msg($mbox);
if($countnum > 0) {
//move the email to our saved folder
$imapresult=imap_mail_move($mbox,'1:'.$countnum,'done');
if($imapresult==false){die(imap_last_error());}
imap_close($mbox,CL_EXPUNGE);
}
use imap_expunge() or imap_close (..., CL_EXPUNGE); but check the return value if true or false if using imap_close (..., CL_EXPUNGE);

Categories