processing IMAP folder on a regular basis

When you need to check a mailbox on a regular basis and process messages that has arrived since your last check you may find that some messages were somehow skipped.

It can be caused by (among other things) one of these two reasons:

  • you ignore time zones
  • you use message’s sent date instead of delivery date

Here’s a piece of code that could put you on a right track:

  1. $mailBox = imap_open("{server.com:143}INBOX", $userName, $password);
  2. // SSL alternative:
  3. // $mailBox = imap_open("{server.com:993/imap/ssl/novalidate-cert}INBOX", $userName, $password);
  4. $lastCheckDate = date("d-M-Y", ($lastCheckTimestamp60*60*24));
  5. $messageUIDsArray = imap_search($mailBox, ‘SINCE "$lastCheckDate"’, SE_UID);
  6. foreach ($messageUIDsArray as $messageUID) {
  7.  
  8. $message = imap_headerinfo($mailBox, imap_msgno($mailBox, $messageUID));
  9. // imap_headerinfo() knows no UIDs so you have to convert UID to message sequence number
  10.  
  11. echo "This is delivery date: ".$message->MailDate." and this is sent date: ".$message->date;
  12.  
  13. $messageTimestamp = strtotime($message->MailDate);
  14. if ($lastCheckTimestamp <= $messageTimestamp)
  15. doYourMagic($message);
  16. }

I could deal with time zones better (finding out what time zone the IMAP server is in and build $lastCheckDate from $lastCheckTimestamp in that time zone). I’m lazy though so I simply deduct 24 hours. That deals with messages delivered around midnight if you’re not in GMT.

Using a sent timestamp instead of a delivery timestamp is a common pitfall. As far as I know, all PHP functions that return message date return sent date (i.e. information from header Date:) and no delivery date. A message can travel for a long time before getting to you. If you check the mailbox once in an hour it can easily happen that you skip a message that was held in a queue somewhere on its way for more than an hour. Also sender’s computer time can be set wrongly. Remember that the information entered into Date: can be anything. It’s the sender’s e-mail client who decides about it.

How to debug

The last issue I had to deal with was what date format the IMAP server expects in your SEARCH SINCE command. 11-Apr-2008 worked for me (both 01-Apr-2008 and 1-Apr-2008 are fine) but if you’re getting no results you might want to take a peek under the hood. Here’s how to telnet to the IMAP server and ask yourself:

  1. telnet server.com 143

Enter this into the telnet window to talk to the IMAP server:

  1. 10 LOGIN yourUserName yourPassword
  2. 40 SELECT INBOX
  3. 50 UID SEARCH SINCE "11-Apr-2008"

These are just commands that you say, I don’t include responses. Please note that you have to start each of your commands with an increasing number. It doesn’t have to be a regular row of numbers, the next number just has to be bigger than the previous one.The search command returns a list of message UIDs that meet your criteria. To see header of each message try this:

  1. 60 UID FETCH messageUIDnumber ALL

One Response to “processing IMAP folder on a regular basis”

  1. T.J. Crowder says:

    Very good point about the sent date vs. the delivered date!

    Regarding date formats, I wonder if many/most IMAP servers support the unambiguous ISO 8601 date format? (http://en.wikipedia.org/wiki/ISO_8601) To my mind, anyone creating software that has even a remote possibility of having to deal with multiple formats (and I’d say IMAP server software qualifies!) should always support ISO 8601 and use it internally… Sadly, though, to the extent it’s even covered by the RFC (http://www.faqs.org/rfcs/rfc3501.html) — and why do we keep making the mistake of not defining these things?! — it looks like they’ve done exactly the wrong thing and require DD-MM-YYYY (at least, that’s how it looks to me in the Formal Syntax section, but I’m not an expert at ABNF)…

    — T.J. :-)

Leave a Reply