Skip to content

Commit 240c45f

Browse files
committed
• Release v1.0.3: Socket mode stabilized, docs updated for PHP 8.4 transition
Major improvements: - Stable default socket connector without ext-imap dependency - Fixed multipart body extraction (textBody/htmlBody empty regression) - Fixed seen/answered flag persistence in fetch/demo workflows - Updated benchmarks with ext-imap vs socket-mode comparison - Updated README, SECURITY, CHANGELOG, and release notes for v1.0.3 All changes are backward-compatible. 🤖 Generated with [Codex] Co-Authored-By: Codex <codex@openai.com>
1 parent f5a5a73 commit 240c45f

36 files changed

+5831
-215
lines changed

.gitignore

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ coverage/
1010
phpstan.cache
1111
*.log
1212
composer.lock
13-
TASK_LIST.md
14-
RELEASE_NOTES_v1.0.2.md
15-
RELEASE_CHECKLIST_v1.0.2.md
16-
GITHUB_RELEASE_v1.0.2.md
13+
RELEASE_NOTES.md
14+
debug_fetch.php
15+
.claude
16+
.DEV.md

AI-REVIEWS.md

Lines changed: 0 additions & 124 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.0.3] - 2026-02-15
9+
10+
### Added
11+
- **Socket connector hardening for PHP 8.4+ migration**
12+
- Stable default connector path without relying on `ext-imap`
13+
- Improved low-level fetch handling for mixed server responses
14+
15+
### Fixed
16+
- **Body parsing regression in socket mode**
17+
- Fixed MIME body extraction when `BODY.PEEK[...]` responses are wrapped as nested arrays
18+
- Restored `textBody`/`htmlBody` population for multipart messages that previously returned empty payloads
19+
- **Message flag persistence in demo/workflows**
20+
- Ensured `seen` and `answered` states are loaded from message overview metadata and stay in sync after updates
21+
- **Search criteria reliability**
22+
- Corrected quoted search token handling in socket searches for better provider compatibility
23+
24+
### Changed
25+
- `ext-imap` is now optional at package level (`suggest`), not a hard Composer requirement
26+
- Documentation now reflects socket-first runtime with optional `ExtImapConnection` fallback
27+
- README benchmarks now document both connector modes (`ext-imap` reference vs default socket mode), including IONOS mailbox-size limits
28+
29+
[1.0.3]: https://github.com/yaijs/php-ymap/releases/tag/v1.0.3
30+
831
## [1.0.2] - 2025-12-19
932

1033
### Added

LICENSE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ MIT License
22

33
Copyright (c) 2025 Engin Ypsilon
44

5+
Portions of this software are derived from third-party MIT-licensed projects:
6+
7+
- Webklex/php-imap — Copyright (c) 2016-2024 Webklex
8+
- ddeboer/imap — Copyright (c) 2012-2024 David de Boer
9+
510
Permission is hereby granted, free of charge, to any person obtaining a copy
611
of this software and associated documentation files (the "Software"), to deal
712
in the Software without restriction, including without limitation the rights

README.md

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ A lightweight fluent IMAP client for PHP 8.1+. Decode bodies, attachments, and h
3131
[![Packagist Version](https://img.shields.io/packagist/v/yaijs/php-ymap.svg)](https://packagist.org/packages/yaijs/php-ymap)
3232
[![PHP Version Require](https://img.shields.io/packagist/php-v/yaijs/php-ymap.svg)](https://packagist.org/packages/yaijs/php-ymap)
3333
[![PHPStan](https://img.shields.io/badge/PHPStan-level%208-brightgreen.svg?style=flat)](https://phpstan.org/)
34-
[![AI Approved](https://img.shields.io/badge/AI%20Council-5%2F5%20Approved-success.svg?style=flat)](RELEASE_NOTES_v1.0.2.md)
34+
[![AI Approved](https://img.shields.io/badge/AI%20Council-5%2F5%20Approved-success.svg?style=flat)](v1.0.3.md)
3535

36-
> **🏆 v1.0.2 - The AI Council Approved Edition!** First IMAP library with unanimous approval from 5+ AI models (Grok 10/10, Gemini 3 Pro, Codex, DeepSeek, Claude). Now with connection abstraction layer (PHP 8.4 ready), memory-safe attachment streaming, and production benchmarks. [See what's new →](CHANGELOG.md#102---2025-12-19)
36+
> **🏆 v1.0.3 - Socket Mode Stabilized!** php-ymap now runs reliably without `ext-imap`, including restored multipart body parsing and persisted read/answered flags in real inbox workflows. [See what's new →](CHANGELOG.md#103---2026-02-15)
3737
3838
## Features
3939

@@ -52,8 +52,9 @@ A lightweight fluent IMAP client for PHP 8.1+. Decode bodies, attachments, and h
5252
## Requirements
5353

5454
- PHP 8.1+
55-
- Extensions: IMAP, mbstring, iconv, JSON
56-
- Enable IMAP on Ubuntu/Debian: `sudo apt install php8.2-imap && sudo phpenmod imap`
55+
- Required extensions: mbstring, iconv, JSON
56+
- Optional extension: `ext-imap` (for explicit `ExtImapConnection` usage)
57+
- Default runtime connector: pure PHP sockets (`SocketsImapConnection`)
5758

5859
---
5960

@@ -145,15 +146,15 @@ $messages = $imap->getMessages();
145146

146147
### Connection Options
147148

148-
`ImapService::connect()` (and the `connection` config section) accept the same parameters that PHP’s `imap_open()` does:
149+
`ImapService::connect()` (and the `connection` config section) keep `imap_open()`-compatible parameters so existing configs continue to work in both connector modes:
149150

150151
| Option | Description |
151152
|--------|-------------|
152153
| `mailbox` | IMAP path, e.g. `{imap.gmail.com:993/imap/ssl}INBOX` |
153154
| `username`, `password` | Credentials or app password |
154-
| `options` | Bitmask passed to `imap_open()` |
155-
| `retries` | Retry count for `imap_open()` |
156-
| `parameters` | Associative array passed to `imap_open()` (set TLS context, disable authenticators, etc.) |
155+
| `options` | `imap_open()` bitmask compatibility field |
156+
| `retries` | Retry count compatibility field |
157+
| `parameters` | Optional connector parameters (TLS/auth behavior where supported) |
157158
| `encoding` | Target encoding for decoded bodies (default `UTF-8`) |
158159

159160
Need a lightweight “Test Credentials” button? Call the static helper:
@@ -236,16 +237,30 @@ php-ymap has been tested in production environments and optimized for enterprise
236237

237238
### Real-World Benchmarks
238239

239-
Performance tested across three production IMAP servers:
240+
Performance tested across three production IMAP servers in both connector modes.
240241

241-
| Provider | 10 msgs | 25 msgs | 50 msgs | 100 msgs | Avg/msg |
242-
|----------|---------|---------|---------|----------|---------|
243-
| **ok.de** | 1.05s | 2.25s | 4.65s | 7.79s | ~105ms |
244-
| **IONOS** | 2.30s | 5.83s | 12.57s | - | ~230ms |
245-
| **Gmail** | 3.43s | 6.12s | 11.86s | 22.62s | ~226ms |
242+
**ext-imap mode (reference):**
243+
244+
| Provider | 10 msgs | 25 msgs | 50 msgs | 100 msgs | Avg/msg |
245+
|-----------|---------|---------|---------|----------|---------|
246+
| **ok.de** | 1.05s | 2.25s | 4.65s | 7.79s | ~105ms |
247+
| **IONOS** | 2.30s | 5.83s | 12.57s | - | ~230ms |
248+
| **Gmail** | 3.43s | 6.12s | 11.86s | 22.62s | ~226ms |
249+
250+
**Socket mode (default in v1.0.3):**
251+
252+
| Provider | 10 msgs | 25 msgs | 50 msgs | 100 msgs | Avg/msg |
253+
|-----------|---------|----------|----------|----------|---------|
254+
| **ok.de** | 1.4282s | 3.0770s | 5.8331s | 11.3149s | ~113ms |
255+
| **IONOS** | 3.5413s | 5.8178s | 16.9986s | - | ~340ms |
256+
| **Gmail** | 5.7557s | 13.0100s | 22.1389s | 37.4546s | ~375ms |
257+
258+
_Note: IONOS mailbox had 61 messages, so no 100-message run in either mode._
246259

247260
**Key Takeaways:**
248-
- Linear scaling up to 100 messages
261+
- Socket mode remains stable without `ext-imap` across tested providers
262+
- Throughput is lower in socket mode (expected in pure PHP transport)
263+
- Linear scaling up to 100 messages where mailbox size allows it
249264
- Handles 18MB+ datasets efficiently
250265
- Suitable for scheduled tasks and background processing
251266
- Memory-safe with proper `FetchOptions` configuration
@@ -422,23 +437,24 @@ $service = ImapService::create()
422437

423438
You can also call `withClientFactory()` to inject a factory that builds clients per connection config.
424439

425-
#### Future-Proof for PHP 8.4+
440+
#### Connector Selection (PHP 8.4+ Ready)
426441

427-
The `ImapConnectionInterface` abstraction prepares php-ymap for PHP 8.4, when `ext-imap` moves to PECL:
442+
The `ImapConnectionInterface` abstraction keeps php-ymap portable across environments with and without `ext-imap`:
428443

429444
```php
430-
use Yai\Ymap\Connection\ExtImapConnection; // Current: wraps ext-imap
431-
use Yai\Ymap\Connection\SocketImapConnection; // Future: pure PHP (v2.0)
445+
use Yai\Ymap\Connection\ExtImapConnection; // Optional: wraps ext-imap
446+
use Yai\Ymap\Connection\SocketsImapConnection; // Default: pure PHP socket connector
432447

433-
// v1.x: Uses ext-imap by default
434-
$client = new ImapClient($config); // Uses ExtImapConnection
448+
// Default in v1.0.3+: socket connector
449+
$client = new ImapClient($config); // Uses SocketsImapConnection
435450

436-
// v2.0: Auto-detect or manual override
437-
$client = new ImapClient($config, connection: new SocketImapConnection());
451+
// Optional override to native extension connector
452+
$client = new ImapClient($config, connection: new ExtImapConnection());
438453
```
439454

440455
**Current implementations:**
441-
- `ExtImapConnection` - Wraps native PHP `imap_*` functions (default)
456+
- `SocketsImapConnection` - Pure PHP socket implementation (default)
457+
- `ExtImapConnection` - Wraps native PHP `imap_*` functions (optional)
442458
- Custom implementations welcome via `ImapConnectionInterface`
443459

444460
---
@@ -573,14 +589,14 @@ For security vulnerabilities, please see our [Security Policy](SECURITY.md) inst
573589

574590
| Issue | Hint |
575591
|-------|------|
576-
| “Can't connect to mailbox” | Double-check mailbox path, host firewall, and that the IMAP extension is enabled |
592+
| “Can't connect to mailbox” | Double-check mailbox path, host firewall, TLS flags, and credentials |
577593
| Gmail authentication fails | Use an [App Password](https://support.google.com/accounts/answer/185833); basic auth is blocked |
578594
| Empty `textBody` | Some emails are HTML-only – read `htmlBody` or strip tags yourself (see example app) |
579595
| Self-signed certs | Provide stream context via `parameters` (e.g. `['DISABLE_AUTHENTICATOR' => 'PLAIN']`, or TLS context) |
580-
| Extension missing | `sudo apt install php8.2-imap && sudo phpenmod imap` |
596+
| Need ext-imap anyway | `sudo apt install php8.2-imap && sudo phpenmod imap` (optional, not required for default socket mode) |
581597

582598
---
583599

584600
## License
585601

586-
MIT
602+
MIT. Portions of the IMAP protocol implementation and message helpers are derived from the MIT-licensed `Webklex/php-imap` and `ddeboer/imap` projects; see `THIRD_PARTY_LICENSES.md` for the preserved upstream notices you must include when redistributing this library or products that bundle it.

0 commit comments

Comments
 (0)