I'm trying to write a PHP program that uses the IMAP PHP extension to run through a very large inbox (greater than 70,000 emails), and move all emails that fall within a specified date range into a folder. I keep running into problems trying to get the mail that falls within the desired range.
First I tried using the SINCE and BEFORE criteria in imap_search() to place all of the desired ID numbers into an array, and then created a string listing these ID numbers to feed into imap_mail_move(). But the problem I keep running into is that imap_search() never actually returns all of the emails within the specified range. For instance, I ran the following code:
echo "Beginning search. \n";
$mail = imap_search($this->mbox,
'SINCE "$startDate" BEFORE "$endDate"');
echo "Search complete. \n";
if (!$mail){echo "The inbox is empty. \n"; die();}
$count = 0;
foreach($mail as $i)
{
$count = $count + 1;
}
echo "Found $count emails. \n";
while specifying a date range that I know to hold 600ish emails, and imap_search() only listed 259 of them. When I expanded the range to encompass the entire inbox of about 75,000 emails, imap_search() only returned 25,112 of them.
When this didn't work, I tried a different, slower way to get all emails within the desired date range. I used imap_search() to collect ALL emails in the inbox, then I iterated through each email, compared the date contained in the emails header to the dates definining my interval, and added the ID to a string if it was in range. I ran the following code:
// Get all mail in the INBOX
$mail = imap_search($this->mbox, "ALL");
if (!$mail){echo "The inbox is empty. \n"; die();}
// Create a string list of all message IDs
//that fall in the specified range
$processed = 0;
$IDsequence = '';
foreach($mail as $messageID)
{
$date = imap_headerinfo($this->mbox, $messageID)->date;
try {$dateObject = new DateTime($date);}
catch (Exception $e) {echo $e->getMessage(); echo "\n";}
$dateObject->setTimezone($TimeZone);
if ($dateObject <= $IntervalEndDate && $dateObject >=
$IntervalStartDate)
{
$IDsequence = $IDsequence . "," . strval($messageID);
}
$processed = $processed + 1;
if ($processed % 100 == 0)
{ echo "Processed $processed emails. \n"; }
}
// If we got at least one message, cut off the first comma.
if (strlen($IDsequence) > 1){
$IDsequence = substr($IDsequence, 1, strlen($IDsequence)-1);
}
else
{
echo "No e-mail to move. \n";
die();
}
echo "Beginning copy. \n";
imap_mail_copy($this->mbox, $IDsequence, $TargetFolder);
echo "Copy complete. \n";
//imap_expunge($this->mbox);
imap_close($this->mbox);
After iterating through just over 25,000 emails, it began to print the error message 'object does not exist' referencing the line of code where I collect the date from the email header. I notice here that the breakdown still occurs somewhere around 25,000 emails, so perhaps both methods break for the same reason. I suspect that I am doing something wrong with the message IDs (for instance, I am assuming that the message IDs for the 75,000 emails are '1' through '75,000').
What is going wrong? Is there a way to collect a large number of emails that fall within a date range and move them?
Perhaps there are only 25,112 messages in the mailbox, and the other ~50,000 are in another mailbox. I know GMail, for example, may report a rough total for the Inbox, but a good percentage of those messages are actually archived.
You might want to do a sanity check at this point. :)
Related
When creating a message with the MessageDispositionType:
$request->MessageDisposition = MessageDispositionType::SEND_AND_SAVE_COPY;
And then setting the FlagStatus to "Flagged"
$message = new MessageType();
$message->Subject = 'EWS Inline Image';
$StartDate = new DateTime('tomorrow 3:00pm');
$DueDate = new DateTime('tomorrow 4:30pm');
$message->Flag->FlagStatus = 'Flagged';
$message->Flag->StartDate = $StartDate->format('c');
$message->Flag->DueDate = $DueDate->format('c');
.....
I get two flagged items, one in the Inbox, and the other in Sent Items.
Only the Sent Items message has the correct assigned dates. The Inbox message flag does not accept the dates (displays as NONE)
If I use MessageDispositionType::SEND_ONLY;, the Inbox message dates are still not set.
Is there any way to only set the FlagStatus to the Inbox item instead of both; and why, if I am able to assign the flag start/due/complete dates to the message, would they only take affect on the Sent Items message and not the Inbox message?
Hi all I have a question. I have an array that is dynamically populated. In the array there are 2 main types of items. Item with file name that equals 27 characters and the rest are either more or less. I am able to separate the 2 two types. The second list is added to a new array called $usedArray. Those items are then iterated through and the file name is substringed from character 0,6 to be used to compare the enduser's input on the page.
if the item is found in that array it will fire a function to send them a text and a email of the the full file name. my problem is if the item is not found until x iterations, it would fire the not found function x amount of times, and if it's not found at all it does the same thing. If I have 99 items that do not match it fire 99 times. to stop from firing I left the not found to just printing not found on the screen. I thought of calling the notfound function outside the loop but do not want it to fire if an items is found
This is my code I have so far
do{
if (substr($val,0,6) == $studentID)
{
$codeFound = substr($val,22,19);
print_r($studentID . ' is found <br /> Their code is ' . $codeFound);
//sendText($phoneNum,$codeFound,$messageMonth);
//sendEmail($emailInfo,$messageMonth,$codeFound);
break 1;
}
else
{
print_r($studentID . " was not found <br />");
}
} while(list(, $val) = each($usedArray));
This is my output
166003 was not found
166003 was not found
166003 was not found
166003 is found
Their code is xxxxxxxxxx
I think you should add a flag to track if you have found something or not:
$item_found = false;
do{
if (substr($val,0,6) == $studentID)
{
$codeFound = substr($val,22,19);
print_r($studentID . ' is found <br /> Their code is ' . $codeFound);
//sendText($phoneNum,$codeFound,$messageMonth);
//sendEmail($emailInfo,$messageMonth,$codeFound);
// item found!
$item_found = true;
break 1;
}
} while(list(, $val) = each($usedArray));
// now check - if `$item_found` is false
// then you can send your NotFoundEmail
if (!$item_found) {
sendNotFoundEmail();
}
I want to compare the time between sent messages, so that i know how quick someone would respond.
message_sent is the unix timestamp when a message has been sent.
ID: 0000000005 is the start, ID: 0000000006 is a response on the message of ID: 0000000005.
With this data: 0000000006 sent a message on 1483021773. The original question was asked in 0000000005 on 1483021687. So the reaction time is 1483021773 - 1483021687. How should i approach this so i get an average response time?
The data
Assuming that a response time is defined by the time it takes for a user to respond to the last message of another user:
$response_times = array(); // array of response times
// let's define a variable to keep track of the person
// to which another person will respond. initially, variable will hold
// the first message
$initiator = array_shift($messages);
// now iterator through messages
foreach ($messages as $message) {
// if this message belongs to the initiator, just update the timestamp
if ($message['from_user_id'] == $initiator['from_user_id']) {
$initiator['message_sent'] = $message['message_sent'];
continue; // and go to the next message
}
// otherwise, calculate the time difference and put it in response times
array_push($response_times, $message['message_sent'] - $initiator['message_sent']);
// and update the initiator
$initiator = $message;
}
// finally, calculate average of response time
$avg_response_time = array_sum($response_times) / count($response_times);
Since i don't know the exact code here is some sudo code with an example:
$total_items = count($array_of_items);
$starting_time_total = "0";
// Some code here to do your message_sent - message_sent = $some_value;
// Do the following for every single item for the $total_items in array
$starting_time_total = $starting_time_total + $some_value;
//Now to get the average we do this
$average = $starting_time_total / $total_items;
So if you have 4 items in the array, with response times of 423, 395, 283, 583 respectively, you are left with an average response time of 421 which you can then convert to seconds of minutes or whatever.
I'm trying to parse an email that is partially written in English and partially written in Japanese using PHP. Here's the code I have so far:
if ($mbox = imap_open($mailbox, $username, $password)) {
$inbox = imap_check($mbox);
$total = (int) $inbox->Nmsgs;
$min = max(1, $total - 10);
// fetch 10 most recent emails
if ($total > 0 && ($emails = imap_fetch_overview($mbox, "{$min}:{$total}"))) {
foreach ($emails as $email) {
$body = imap_body($mbox, $email->uid, FT_UID);
// for testing purposes
echo $body;
// parsing logic here
}
}
}
So as you can see I'm just echoing out the plaintext body of the email, just to test things, and here's part of the echoed response I get when I run this script:
Your Japanese word of the day is: ç”·ã®å
However, the following is what I should see in place of that, based on what's actually in the email:
Your Japanese word of the day is: 男の子
So clearly something's being lost in translation (pun intended). I'm using some simple string manipulation to try and parse the Japanese characters, and then insert them into a MySQL database. However, it's currently inserting those gobbledygook characters instead. What am I missing?
Edit: I'm using PHP version 5.4.45
So I'm not really sure how to get this working in PHP 5. I decided to try upgrading my server to PHP 7 and suddenly all of the code just started working.
I have an array of email addresses I am sending emails to.
I would like to sort them by alternating domain names, so if I have 30 #gmail.com, 30 #yahoo.com and 30 #aol.com, the sort would result in a #gmail.com, then #yahoo.com, then #aol.com, then #gmail.com again, etc.
The sort would alternate as much as possible so that there would be as few identical domain names in a row.
Why: To prevent being considered as a source of spam, its best to "throttle" email sending, or sleep between each send so mail servers are not hit quickly many times in a short time spam. Instead, I would like to do that above to create a lag between times an email provider is hit by me, but without stopping my script and causing a delay to my end user.
I may do it like this:
$organized_emails = array();
$needle_key = 0;
$needle_search = array('gmail', 'yahoo', 'aol', 'others');
while(true) {
$current_value = array_shift($emails);
if(strpos($current_value, $needle_search[$needle_key]) !== false) {
$organized_emails[] = $current_value;
$needle_key++;
if($needle_key > 3) {
$needle_key = 0;
}
} else {
array_push($emails, $current_value);
}
if(empty($emails)) {
break;
}
}
PHP Fiddle sample