A PHP IMAP library to read and process e-mails over IMAP protocol, built with robust Object-Oriented architecture.
This library requires PHP >= 8.3 with IMAP, iconv and Multibyte String extensions installed.
The recommended way to install the IMAP library is through Composer:
$ composer require ddeboer/imap
This command requires you to have Composer installed globally, as explained in the installation chapter of the Composer documentation.
use DdeboerImapServer;$server = new Server('imap.gmail.com');// $connection is instance of DdeboerImapConnection$connection = $server->authenticate('my_username', 'my_password');
You can specify port, flags and parameters to the server:
$server = new Server($hostname, // required$port, // defaults to '993'$flags, // defaults to '/imap/ssl/validate-cert'$parameters);
Retrieve mailboxes (also known as mail folders) from the mail server and iterate over them:
$mailboxes = $connection->getMailboxes();foreach ($mailboxes as $mailbox) {// Skip container-only mailboxes// @see https://secure.php.net/manual/en/function.imap-getmailboxes.phpif ($mailbox->getAttributes() & LATT_NOSELECT) {continue; }// $mailbox is instance of DdeboerImapMailboxprintf('Mailbox "%s" has %s messages', $mailbox->getName(), $mailbox->count()); }
Or retrieve a specific mailbox:
$mailbox = $connection->getMailbox('INBOX');
Delete a mailbox:
$connection->deleteMailbox($mailbox);
You can bulk set, or clear, any flag of mailbox messages (by UIDs):
$mailbox->setFlag('Seen Flagged', ['1:5', '7', '9']);$mailbox->setFlag('Seen', '1,3,5,6:8');$mailbox->clearFlag('Flagged', '1,3');
WARNING You must retrieve new Message instances in case of bulk modify flags to refresh the single Messages flags.
Retrieve messages (e-mails) from a mailbox and iterate over them:
$messages = $mailbox->getMessages();foreach ($messages as $message) {// $message is instance of DdeboerImapMessage}
To insert a new message (that just has been sent) into the Sent mailbox and flag it as seen:
$mailbox = $connection->getMailbox('Sent');$mailbox->addMessage($messageMIME, 'Seen');
Note that the message should be a string at MIME format (as described in the RFC2045).
use DdeboerImapSearchExpression;use DdeboerImapSearchEmailTo;use DdeboerImapSearchTextBody;$search = new SearchExpression();$search->addCondition(new To('[email protected]'));$search->addCondition(new Body('contents'));$messages = $mailbox->getMessages($search);
WARNING We are currently unable to have both spaces and double-quotes
escaped together. Only spaces are currently escaped correctly.
You can use DdeboerImapSearchRawExpression
to write the complete search
condition by yourself.
Messages can also be retrieved sorted as per imap_sort function:
$today = new DateTimeImmutable();$thirtyDaysAgo = $today->sub(new DateInterval('P30D'));$messages = $mailbox->getMessages(new DdeboerImapSearchDateSince($thirtyDaysAgo),SORTDATE, // Sort criteriatrue // Descending order);
Note that PHP imap library relies on the c-client
library available at https://www.washington.edu/imap/
which doesn't fully support some IMAP4 search criteria like OR
. If you want those unsupported criteria,
you need to manually patch the latest version (imap-2007f
of 23-Jul-2011 at the time of this commit)
and recompile PHP onto your patched c-client
library.
By the way most of the common search criteria are available and functioning, browse them in ./src/Search
.
References:
https://stackoverflow.com/questions/36356715/imap-search-unknown-search-criterion-or
imap-2007f.tar.gz: ./src/c-client/mail.c
and ./docs/internal.txt
Get message number and unique message id in the form <...>:
$message->getNumber();$message->getId();
Get other message properties:
$message->getSubject();$message->getFrom(); // MessageEmailAddress$message->getTo(); // array of MessageEmailAddress$message->getDate(); // DateTimeImmutable$message->isAnswered();$message->isDeleted();$message->isDraft();$message->isSeen();
Get message headers as a DdeboerImapMessageHeaders object:
$message->getHeaders();
Get message body as HTML or plain text (only first part):
$message->getBodyHtml(); // Content of text/html part, if present$message->getBodyText(); // Content of text/plain part, if present
Get complete body (all parts):
$body = $message->getCompleteBodyHtml(); // Content of text/html part, if presentif ($body === null) { // If body is null, there are no HTML parts, so let's try getting the text body$body = $message->getCompleteBodyText(); // Content of text/plain part, if present}
Reading the message body keeps the message as unseen. If you want to mark the message as seen:
$message->markAsSeen();
Or you can set, or clear, any flag:
$message->setFlag('Seen Flagged');$message->clearFlag('Flagged');
Move a message to another mailbox:
$mailbox = $connection->getMailbox('another-mailbox');$message->move($mailbox);
Deleting messages:
$mailbox->getMessage(1)->delete();$mailbox->getMessage(2)->delete();$connection->expunge();
Get message attachments (both inline and attached) and iterate over them:
$attachments = $message->getAttachments();foreach ($attachments as $attachment) {// $attachment is instance of DdeboerImapMessageAttachment}
Download a message attachment to a local file:
// getDecodedContent() decodes the attachment’s contents automatically:file_put_contents('/my/local/dir/' . $attachment->getFilename(),$attachment->getDecodedContent() );
Check if attachment is embedded message and get it:
$attachments = $message->getAttachments();foreach ($attachments as $attachment) {if ($attachment->isEmbeddedMessage()) {$embeddedMessage = $attachment->getEmbeddedMessage();// $embeddedMessage is instance of DdeboerImapMessageEmbeddedMessage} }
An EmbeddedMessage has the same API as a normal Message, apart from flags and operations like copy, move or delete.
The IMAP extension provides the imap_timeout function to adjust the timeout seconds for various operations.
However the extension's implementation doesn't link the functionality to a
specific context or connection, instead they are global. So in order to not
affect functionalities outside this library, we had to choose whether wrap
every imap_*
call around an optional user-provided timeout or leave this
task to the user.
Because of the heterogeneous world of IMAP servers and the high complexity burden cost for such a little gain of the former, we chose the latter.
Mockability is granted by interfaces present for each API. Dig into MockabilityTest for an example of a mocked workflow.
Docker is needed to run the build on your computer.
First command you need to run is make start-imap-server
, which starts an IMAP server locally.
Then the local build can be triggered with a bare make
.
When you finish the development, stop the local IMAP server with make stop-imap-server
.