Check new email in gmail inbox using PHP - php

So my current code is this in PHP:
$mailbox = imap_open('{imap.gmail.com:993/imap/ssl}INBOX', 'example#gmail.com', 'password') or die('Cannot connect to Gmail: ' . imap_last_error());
This code allows PHP to see my email inbox using IMAP and it works fine.
Now my question is, how to make it so that It checks all the new emails in my inbox and outputs "n New Emails!" and marks each of them as seen automatically.
I would really appreciate It If someone were to shed some light on this as I am very new to IMAP and handling emails programmatically in general.

You could use a combination of imap_search1 and imap_setflag_full2
$mailbox = imap_open('{imap.gmail.com:993/imap/ssl}INBOX', 'example#gmail.com', 'password');
// This gives an array of message IDs for all messages that are UNSEEN
$unseenMessages = imap_search($mailbox, 'UNSEEN');
// Keep in mind that imap_search returns false, if it doesn't find anything
$unseenCount = !$unseenMessages ? 0 : count($unseenMessages);
echo "$unseenCount New Emails!\n";
if ($unseenMessages) {
// The second parameter of imap_setflag_full function is a comma separated string of message IDs
// It can also be a range eg 1:5, which would be the same as 1,2,3,4,5
imap_setflag_full($mailbox, implode(',', $unseenMessages), '\Seen');
}

Related

Retrieving email from outlook with imap_fetchbody() broken

I have been using php-imap-client for some time and has always worked great. The issue is that recently it seems to break with fetching email from outlook/office365 mailboxes now and I can't pinpoint the issue. As far as I know it seems to be breaking with imap_fetchbody() but that is as far as I get.
getMessages() basically does not work and I was wondering if anyone has come across this yet and maybe can shed some light to a solution to fix it.
Things like countMessages and countUnreadMessages work fine but once you try get the email contents that is where it breaks.
$overallMessages = $imap->countMessages();
$unreadMessages = $imap->countUnreadMessages();
Here is all my code
$mailbox = $row['imap_server_address'];
$username = $row['imap_username'];
$password = $row['imap_password'];
$encryption = Imap::ENCRYPT_SSL; // TLS OR NULL accepted
// Open connection
try{
$imap = new Imap($mailbox, $username, $password, $encryption);
// You can also check out example-connect.php for more connection options
}catch (ImapClientException $error){
echo $error->getMessage().PHP_EOL; // You know the rule, no errors in production ...
die(); // Oh no :( we failed
}
// Select the folder INBOX
$imap->selectFolder('INBOX');
// Count the messages in current folder
$overallMessages = $imap->countMessages();
$unreadMessages = $imap->countUnreadMessages();
// Fetch all the messages in the current folder
echo "This echos fine";
$emails = $imap->getMessages();
echo "This does not echo";
var_dump($emails);
I can connect to the server just fine. I can select the INBOX, I can get overall messages and as well as unread. var_dump($email) produces nothing. And there are unread emails in the inbox.
When I echo after $emails = $imap->getMessages(); nothing is echo'd to the screen so something is breaking here.

php imap how to search unread and also sort them by date?

Is it possible to get the unread messages and also sort them messages by date ? I have
$messages = imap_search($imap,"UNSEEN");
imap_sort($imap, SORTDATE, 1);
but I'm wondering if it shouldn't be
imap_sort($imap, SORTDATE, 1);
$messages = imap_search($imap,"UNSEEN");
or something else ?
You may use
$messages = imap_search($imap,"UNSEEN");
$sorted = array_reverse($messages);
Here is a code which will help you:
$host = '{imap.gmail.com:993/imap/ssl}INBOX';
// Connect to the pop3 email inbox belonging to $user
$con = imap_open("$host", $user, $pass) or die("Can't connect: " . imap_last_error());
// after some sleeping
if (!imap_ping($con)) {
// do some stuff to reconnect
die("The user is no longer logged in.");
} else {
echo ('Connection Successful !');
}
$MC = imap_check($con);
// Get the number of emails in inbox
$range = "1:".$MC->Nmsgs;
// Retrieve the email details of all emails from inbox
$response = imap_fetch_overview($con,$range);
$response = array_reverse($response);
// displays basic email info such as from, to, date, subject etc...
foreach ($response as $msg) {
// extra filters to show records which are Unread/Not seen
if($msg->seen == "0" && $msg->recent == "0"){
echo '<pre>';
var_dump($msg);
echo '</pre><br>-----------------------------------------------------<br>';
}
}
Eventually, you can put condition for date wise sorting or key wise sorting with ksort function
If you use imap_sort you don't need to use imap_search, as imap_sort admits a parameter $search_criteria as well as imap_search. Let's say imap_sort is like imap_search, but you can also get the results ordered.
$messages = imap_sort($imap, SORTDATE, 1, SE_UID, 'UNSEEN');
U r performing two different actions on the original set of data independently. One possible way is to take all the data from first command(search), store it in some variable and then implement your own sort functionality.

I can't seem to delete all messages except the most recent

I'm using the following code which you may recognise from php.net to delete all the emails in my inbox:
function deleteEmails($emailAddress)
{
// connect to gmail with your credentials
$hostname = '{imap.gmail.com:993/imap/ssl}INBOX';
$username = $emailAddress; # e.g somebody#gmail.com
$password = '****************';
// try to connect
$inbox = imap_open($hostname,$username,$password) or die('Cannot download information: ' . imap_last_error());
$check = imap_mailboxmsginfo($inbox);
echo "Messages before delete: " . $check->Nmsgs . "<br />\n";
imap_delete($inbox, '1:*');
$check = imap_mailboxmsginfo($inbox);
echo "Messages after delete: " . $check->Nmsgs . "<br />\n";
imap_expunge($inbox);
$check = imap_mailboxmsginfo($inbox);
echo "Messages after expunge: " . $check->Nmsgs . "<br />\n";
imap_close($inbox);
}
which helps deal with a clog in my account that happens on occasion if I let it get out of hand. However, what I really need is for it to delete all my email except the most recent one. I have tried to change imap_delete($inbox, '1:*'); to imap_delete($inbox, '2:*'); but this just caused it to not work at all.
What am I missing?
EDIT
With advise below I tried the following:
imap_delete($inbox, "2:$check->Nmsgs");
But interestingly it deleted all but one of the 'conversations' but in gmail 'conversations' can max out at 61 emails! I'm not sure how to get around this. Also, the deleted ones returned after a few mins...
I know gmail does some interesting stuff with just tagging it differently and putting it in an All Mail folder, since there aren't actual "Folders" like on most IMAP systems. Have you tried just giving it a range, such as
imap_delete($inbox,2:$check->Nmsgs);
If that doesn't work, you might have to just loop through marking them for deletion and then expunge after that.
I found the issue. Gmail by default is set up using 'conversations' meaning any emails coming in with the same subject get grouped together. This screws with everything but it can be turned off in gmail settings. Once done I needed to make sure I was deleting all but the most recent. using imap_delete($inbox,2:$check->Nmsgs); deleted all but the oldest. so the following code did it for me:
$emails = ($check->Nmsgs)-1;
imap_delete($inbox, '1:' . $emails);
so that I was getting the numbers but was deleting all up to the last one to come in (the most recent)
Done

how can I pull out the contents from an email and write them in a mysql table?

How can I make it so when a user email's to my email address their email text/information is written into a mysql table? So basically extract the contents of a new email and write them into mysql table.
I tried this but I get nothing:
<?php
$imap = imap_open("{gmail.com}", "username", "password");
if( $imap ) {
//Check no.of.msgs
$num = imap_num_msg($imap)
//if there is a message in your inbox
if( $num >0 ) {
//read that mail recently arrived
echo imap_qprint(imap_body($imap, $num));
}
//close the stream
imap_close($imap);
}
?>
We are using an exchange server..I am a coop student so I am not really advanced at this.
I tried this as a test to see if it works, logging in gmail to read email. It didnt work.
<?php
// connect to the mailbox
$m_mail = imap_open("{mail.https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=https://mail.google.com/mail/&ss=1&scc=1&ltmpl=default&ltmplcache=2}INBOX", "username", "password");
//get all messages
$m_search=imap_search ($m_mail, 'ALL ');
// Order results starting from newest message
rsort($m_search);
//loop through and do what's necessary
foreach ($m_search as $onem) {
//get imap header info for obj thang
$headers = imap_headerinfo($m_mail, $onem);
$head = imap_fetchheader($m_mail, $headers->Msgno);
$body = imap_body($m_mail, $headers->Msgno, FT_INTERNAL );
echo $body;
}
//purge messages (if necessary)
imap_expunge($m_mail);
//close mailbox
imap_close($m_mail);
?>
use IMAP functions for that. Set up another email account if necessary. Here's the example code:
// connect to the mailbox
$m_mail = imap_open("{mail.YOURHOST.com:993/imap/ssl/novalidate-cert}INBOX", "address#YOURHOST.com", "YOURPASSWORD");
//get all messages
$m_search=imap_search ($m_mail, 'ALL ');
// Order results starting from newest message
rsort($m_search);
//loop through and do what's necessary
foreach ($m_search as $onem) {
//get imap header info for obj thang
$headers = imap_headerinfo($m_mail, $onem);
$head = imap_fetchheader($m_mail, $headers->Msgno);
$body = imap_body($m_mail, $headers->Msgno, FT_INTERNAL );
//
DO WHAT YOU NEED TO DO HERE - insert to the database, etc
}
//purge messages (if necessary)
imap_expunge($m_mail);
//close mailbox
imap_close($m_mail);
read your mailbox via pop3 or imap and add the new emails to your database
Take a look a this class: http://php.net/manual/en/book.imap.php
you could read the pop3/imap in some intervals.
other method would be to redirect your email to a php script. I don't know which email system you are using on your server but here is an example with postfix.
the pop3/imap method is easier and you don't need to edit your server configs but the second method is faster because your script will start as it receives an email.

Zend Mail - how to read without emails being marked as opened

I'm using zend mail extended with zend_mail_storage_imap and I built an application that looks for keywords in user's emails.
The problem is that it opens up each email and keeps it marked as read. Is there a way to check the body of emails and not mark each mail checked as read?
Here's current working code. It's part of an ajax query that automatically looks through someone's inbox. In this current form, it will mark each mail starting with a user's most current mail as read (in gmail). Would it be possible to check the body text, but not mark the email as read. Alternatively, will I need to check if each mail is read or unread before looking it up, and then restore it to that state as a workaround?
if (strpos(htmlentities($storage->getMessage($i)),$searchterm))
{
$fromaddress = str_replace("'","",$storage->getMessage($i)->from);
$fromaddress = str_replace('"','',$fromaddress);
$sql = "SELECT `senderemail`,`subscribed` FROM email_spam WHERE `useremail` = '$_SESSION[email_address]' AND `senderemail` = '$fromaddress'";
$result = mysql_query($sql) or die (mysql_error());
$num = mysql_num_rows($result);
if($num == 0)
{
$emailmessage = mysql_escape_string($storage->getMessage($i)->getContent());
$sql_insert = "INSERT into `email_spam` (`message`,`useremail`,`senderemail`,`datetime`,`subscribed`) VALUES ('$emailmessage','$_SESSION[email_address]','$fromaddress',now(),1)";
mysql_query($sql_insert,$link) or die("Insertion Failed:" . mysql_error());
$sql = "SELECT `emailid`,`datetime` FROM email_spam WHERE `useremail` = '$_SESSION[email_address]' ORDER BY `datetime` desc";
$getid = mysql_query($sql) or die (mysql_error());
$num = mysql_num_rows($getid);
}
}
EDIT - here's the final code for those interested
$storage = new Zend_Mail_Storage_Imap($imap);
$flags = $storage->getMessage($i)->getFlags();
$newflag = $flags[Zend_Mail_Storage::FLAG_RECENT];
$oldflag = $flags['\Seen'];
if(!empty($flags['\Seen']))
{
$read=1;
}
else
{
$read=0;
}
The entire code is looped, so here, I perform my entire searching/sorting algorithm for each individual email.
if ($read==0)
{
$storage->setFlags($i, array(Zend_Mail_Storage::FLAG_RECENT)); //marks as new
}
Here, I go and mark the emails that were not read (before the implementations) as unread. I think this is the most efficient way (that I could find) of performing this operation. I welcome any other codes or comments.
After reading a message, you could unset the seen flag. See also the imap implementation of the setFlags method. Api documentation
To unset the "seen" flag:
$flags = $msg->getFlags();
unset($flags[Zend_Mail_Storage::FLAG_SEEN]);
$storage->setFlags($i, $flags);
Setting the "recent" flag does not necessarily do what you want it to! On gmail, it will mark emails as "important".
When reading mails with the IMAP Storage in Zend Framework you have access to a method called setFlags in Zend_Mail_Storage_Imap
I don't think it's documented in the ZF manual but you might want to look into the API docs (see link above) to set the status/flag on a message.
You could also just use empty array to reset any flags
$mailstorage->setFlags($messageID, array());
Flag change seem to be done via getContent() method after fetching the message in zend-mail 2. Below is an example to read content and keep initial flags :
$imap = [
'host' => $connection['mailhost'],
'user' => $connection['username'],
'password' => $password,
];
$storage = new \Zend\Mail\Storage\Imap($imap);
$lastMsgIndex = $storage->countMessages();
$msg = $storage->getMessage($lastMsgIndex);
$msgFlags = $msg->getFlags();
// Line below will mark email as seen if getContent is called
$content = $msg->isMultipart() ? 'Multipart Email' : $msg->getContent();
$storage->setFlags($lastMsgIndex, $msgFlags);

Categories