Thu 19 Apr 2007
5:00PM
compton

Reading Email with PHP and IMAP/POP3

Sending email is very simple in PHP, thanks to the mail() function. So what about receiving it? Obviously this would be useful for webmail, but my intention is to allow remote control of a PHP app, which is restricted to specific IPs.

The idea is this:
  1. Check at set intervals for email from a specific sender containing a specific phrase
  2. Send an email to that sender containing a unique code and asking for confirmation by reply (this is to guard against emails with false sender info)
  3. Check for a reply from that sender containing the unique code
  4. Allow the user remote access
This back-and-forth palava is overkill for most operations but for my situation it provides sufficient security to prevent a reasonably determined hacker exploiting it to gain remote access (even if they did manage to fool it, they would still need the user's loginname and password to get in).

Receiving email in PHP is possible with the IMAP set of functions. For non-Windows installations of PHP, a helper library is required. Windows PHP installs however appear to have all that's required by default.

Although the functions are referred to as the IMAP functions, and they all begin with imap_, they can also connect to POP3 mailboxes. However, not all functionality is available for POP3.

Connect to a POP3 Mailbox

Use the following function to connect to the inbox of a specific account:
$stream = imap_open("{qualified-computername:110/pop3}INBOX", 'username', 'password')
This returns an IMAP stream, which is a PHP resource you can use for further operations on the mailbox.

Check a POP3 Mailbox

The following function returns an object with several properties which provide information about the current mailbox:
$emailinfo = imap_check($stream)
One of the properties of the returned object will tell you how many messages are in the current mailbox:
$emailinfo->Nmsgs
There are other properties which will tell you:
  • Date - current date/time on mail server
  • Driver - driver used to connect (IMAP, POP3 or NNTP)
  • Mailbox - currently selected mailbox, fully qualified
  • Recent - how many recent messages in the mailbox
This last item, Recent, seems to always return the total number of messages in a POP3 mailbox; it does not return how many are unread. I suspect this is simply one of the functionalities that is only supported for IMAP mailboxes. Curiously, the check function marks all messages as read for POP3 mailboxes. There is a related function, imap_status(), which offers a couple of extra properties, including an Unseen property, which should tell you how many unread messages there are. However, it also does not work for POP3.

Reading an Email

The imap_body() function returns a string containing the body (ie message content) of a specified email in the current mailbox:
$message = imap_body(imap stream, message number)
The message number is an integer from 1 to N, where N is the total number of messages in the current mailbox. Note that this ordering is first to last, ie more recent messages have greater numbers.

Putting all this together, the following simple script will check if the most recent message in a mailbox contains a 'trigger' word:
if (($emailbox = imap_open("{computername:110/pop3}INBOX", 'username', 'password')) !== false) { $emailinfo = imap_check($emailbox); if (stripos(imap_body($emailbox, $emailinfo->Nmsgs), 'trigger phrase') !== false) { // Trigger detected } imap_close($emailbox); }
The IMAP functions give you access to the email headers, which is pretty essential really, as these are how you get information such as the sender, the email date, and even the subject.

The imap_headerinfo() function returns an object which exposes all the header fields as properties:
$headers = imap_headerinfo(imap stream, message number);
You can then get a specific header using the appropriate property. For instance, $headers->udate returns the UNIX time of the message. There are other properties to get the date in human-readable format too.

A couple of header properties are themselves actually implemented as objects, such as the from property indicating the sender of the message. The following code shows how you could iterate through such headers:
foreach ($headers->from as $id=>$object) foreach ($object as $key=>$value) echo $key.' = '.$value.', ';

Guest

7:17 am, Tuesday, 11 November 08

Good
 

Guest

9:29 pm, Monday, 16 March 09

HiBob
 

Guest

12:48 pm, Tuesday, 8 September 09

Thanks, it was very helpful
 

Andy Fletcher

6:46 pm, Tuesday, 12 April 11

Hi - I am definitely delighted to find this. great job!
 

JLE

9:19 am, Monday, 7 May 12

Thanks a bunch! :)
 

/xkcd/ Phase Change