phpdot/imap

Enterprise-grade IMAP4rev1/IMAP4rev2 protocol library for PHP

Maintainers

Package info

github.com/phpdot/imap

pkg:composer/phpdot/imap

Statistics

Installs: 9

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v2.2.0 2026-03-27 00:15 UTC

This package is auto-updated.

Last update: 2026-03-27 00:16:40 UTC


README

IMAP4rev1/IMAP4rev2 protocol library for PHP. Client and server.

Install

composer require phpdot/imap

Requires PHP 8.2+.

Client

use PHPdot\IMAP\ImapClient;

$client = new ImapClient('imap.gmail.com', 993, 'ssl');
$client->connect();
$client->login('user@gmail.com', 'app-password');

$inbox = $client->select('INBOX');
echo $inbox->exists . " messages\n";

$messages = $client->fetch('1:10', ['FLAGS', 'ENVELOPE']);
foreach ($messages as $msg) {
    echo $msg->envelope->subject . "\n";
}

$unseen = $client->search('UNSEEN');
$client->store('1:3', '+FLAGS', ['\\Seen']);

$folders = $client->listMailboxes();
$status = $client->status('INBOX', ['MESSAGES', 'UNSEEN']);

$client->idle(function ($notification) {
    if ($notification->isNewMessage()) {
        echo "New mail! " . $notification->number . " messages\n";
    }
    return true; // keep listening, return false to stop
});

$client->logout();

Custom transport

use PHPdot\IMAP\ImapClient;

// Default: StreamTransport (PHP stream_socket_client)
$client = new ImapClient('host', 993, 'ssl');

// Custom: Swoole, ReactPHP, or anything implementing ClientTransportInterface
$client = new ImapClient('host', 993, 'ssl', new SwooleTransport());

Server

use PHPdot\IMAP\ImapHandler;
use PHPdot\IMAP\Connection\ServerConnection;
use PHPdot\IMAP\Connection\ConnectionContext;
use PHPdot\IMAP\Result\SelectResult;

$handler = new ImapHandler();

$handler->onLogin(function (string $user, string $pass, ConnectionContext $ctx): bool {
    return $user === 'omar' && $pass === 'secret';
});

$handler->onSelect(function (string $mailbox, ConnectionContext $ctx): SelectResult {
    return new SelectResult(exists: 172, uidValidity: 38505, uidNext: 4392);
});

$handler->onFetch(function ($fetchCommand, ConnectionContext $ctx): array {
    // query your storage, return list<FetchResult>
    return [];
});

Wire to any runtime

// Swoole
$swoole->on('connect', function ($srv, $fd) use ($handler) {
    $conn = new ServerConnection($handler);
    $connections[$fd] = $conn;
    $srv->send($fd, $conn->greeting());
});

$swoole->on('receive', function ($srv, $fd, $r, $data) use (&$connections) {
    foreach ($connections[$fd]->onData($data) as $response) {
        $srv->send($fd, $response);
    }
});

// Workerman, ReactPHP, Amp — same pattern

What's Covered

Every command and response from RFC 9051 (IMAP4rev2) and RFC 3501 (IMAP4rev1):

  • 35+ commands: LOGIN, AUTHENTICATE, SELECT, FETCH, SEARCH, STORE, COPY, MOVE, APPEND, EXPUNGE, LIST, STATUS, IDLE, ENABLE, NAMESPACE, ID, COMPRESS, QUOTA, all UID variants
  • All data types: atoms, quoted strings, literals, literal8, NIL, lists, sequence sets, sections, partials
  • All responses: ENVELOPE, BODYSTRUCTURE, FETCH, ESEARCH, BINARY, APPENDUID, COPYUID, FLAGS, CAPABILITY, 37 response codes
  • Extensions: CONDSTORE, COMPRESS, QUOTA, ID, SPECIAL-USE, XLIST

Quality

  • declare(strict_types=1) on every file
  • PHPStan max level, zero errors, no ignores
  • 446 tests, 1156 assertions
  • Zero runtime dependencies
  • Transport agnostic (works with Swoole, ReactPHP, Workerman, Amp, plain PHP)

License

MIT