Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a085b42
Extend unit tests and fix decoding bug
Sebbo94BY May 10, 2026
31cfdf0
Merge pull request #742 from barbushin/Extend-Unit-Tests
Sebbo94BY May 10, 2026
d41b448
Add note regarding unbundled ext-imap for PHP 8.4.x and newer
Sebbo94BY May 10, 2026
9345d9c
Merge pull request #743 from barbushin/Issue-727-Add-note-regarding-e…
Sebbo94BY May 10, 2026
4800cb6
Fix implicit nullability deprecation
Sebbo94BY May 10, 2026
db7b829
Merge pull request #744 from barbushin/Fix-implicit-nullability-depre…
Sebbo94BY May 10, 2026
fc8047f
Fix wrong German Umlauts conversion
Sebbo94BY May 10, 2026
3f82c2b
Merge pull request #745 from barbushin/Issue-730-Fix-wrong-German-Uml…
Sebbo94BY May 10, 2026
b35711f
Add fallback for SEEN SINCE searches and document IMAP behavior
Sebbo94BY May 10, 2026
0e9b28b
Merge pull request #746 from barbushin/Issue-720-Fix-incorrect-SEEN-h…
Sebbo94BY May 10, 2026
753f357
Issue 691: Expose missing Message-ID reference headers
Sebbo94BY May 10, 2026
4d62abb
Merge pull request #747 from barbushin/Issue-691-Add-missing-messageI…
Sebbo94BY May 10, 2026
90396e6
Fix broken decodeStringFromUtf7ImapToUtf8() function
Sebbo94BY May 10, 2026
2d790d9
Merge pull request #748 from barbushin/Fix-broken-decodeStringFromUtf…
Sebbo94BY May 10, 2026
e3f9c9d
Fix flattenParts() for PARTY_TYPE_TWO
Sebbo94BY May 10, 2026
5d26eee
Merge pull request #749 from barbushin/Fix-flattenParts-for-PARTY_TYP…
Sebbo94BY May 10, 2026
e25c160
Deduplicate and fix disposition checks
Sebbo94BY May 10, 2026
5a1a683
Merge pull request #750 from barbushin/Deduplicate-and-fix-dispositio…
Sebbo94BY May 10, 2026
0ac8c44
Preserve original attachment filenames
Sebbo94BY May 10, 2026
be7d10a
Merge pull request #751 from barbushin/Preserve-original-attachment-f…
Sebbo94BY May 10, 2026
58bfd43
Refactor php-cs-fixer config and apply changes
Sebbo94BY May 10, 2026
51bc2f0
Fix failing PHPUnit tests
Sebbo94BY May 10, 2026
c139a6e
Merge pull request #752 from barbushin/Refactor-php-cs-fixer-config
Sebbo94BY May 10, 2026
0410683
Add support for keep original attachment filenames
Sebbo94BY May 10, 2026
620cd06
Merge pull request #753 from barbushin/Add-support-for-keep-original-…
Sebbo94BY May 10, 2026
329d631
Fix incorrect IMAP-style sequence-set element handling
Sebbo94BY May 10, 2026
ec2f73c
Merge pull request #754 from barbushin/Fix-incorrect-IMAP-sequence-ha…
Sebbo94BY May 10, 2026
b5a8680
Fix boolean received error in getFileInfo()
Sebbo94BY May 10, 2026
3c580e1
Merge pull request #755 from barbushin/Fix-boolean-received-error-in-…
Sebbo94BY May 10, 2026
c8c57d6
Issue #700: Automatically expose all custom headers
Sebbo94BY May 10, 2026
f16c7a4
Merge pull request #756 from barbushin/Automatically-expose-all-custo…
Sebbo94BY May 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/php_code_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: imap
coverage: xdebug

- uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/php_static_analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: imap
coverage: none

- uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/php_unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: imap
coverage: none

- uses: actions/checkout@v4
Expand Down
21 changes: 16 additions & 5 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
<?php

declare(strict_types=1);

/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.0.0-rc.1|configurator
* you can change this configuration by importing this file.
* Keep the fixer config narrow and static-analysis-friendly.
* In particular, do not enable phpdoc_to_comment:
* Psalm/PHPStan assertions rely on docblocks staying docblocks.
*/
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHP71Migration' => true, // @PHP72Migration does not exist
'@PHP71Migration:risky' => true, // @PHP72Migration:risky does not exist
'array_syntax' => ['syntax' => 'short'],
'declare_strict_types' => true,
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => true,
'import_functions' => false,
],
'include' => true,
'native_constant_invocation' => true,
'native_function_invocation' => [
'strict' => false,
'include' => ['@compiler_optimized'],
],
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_superfluous_phpdoc_tags' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_method_casing' => true,
'php_unit_test_case_static_method_calls' => ['call_type' => 'this'],
'phpdoc_inline_tag_normalizer' => true,
'phpdoc_no_access' => true,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_to_comment' => false,
'phpdoc_var_without_name' => true,
'void_return' => true,
])
->setFinder(PhpCsFixer\Finder::create()
Expand Down
34 changes: 25 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
[![Test Coverage](https://api.codeclimate.com/v1/badges/02f72a4fd695cb7e2976/test_coverage)](https://codeclimate.com/github/barbushin/php-imap/test_coverage)
[![Type Coverage](https://shepherd.dev/github/barbushin/php-imap/coverage.svg)](https://shepherd.dev/github/barbushin/php-imap)

Initially released in December 2012, the PHP IMAP Mailbox is a powerful and open source library to connect to a mailbox by POP3, IMAP and NNTP using the PHP IMAP extension. This library allows you to fetch emails from your email server. Extend the functionality or create powerful web applications to handle your incoming emails.
Initially released in December 2012, the PHP IMAP Mailbox is a powerful and open source library to connect to a mailbox by POP3, IMAP and NNTP using the PHP IMAP extension (`ext-imap`). This library allows you to fetch emails from your email server. Extend the functionality or create powerful web applications to handle your incoming emails.

### Features

* Connect to mailbox by POP3/IMAP/NNTP, using [PHP IMAP extension](http://php.net/manual/book.imap.php)
* Connect to mailbox by POP3/IMAP/NNTP, using [PHP IMAP extension](https://www.php.net/manual/book.imap.php)
* Get emails with attachments and inline images
* Get emails filtered or sorted by custom criteria
* Mark emails as seen/unseen
Expand All @@ -43,14 +43,17 @@ Initially released in December 2012, the PHP IMAP Mailbox is a powerful and open

The next major release raises the minimum supported PHP version to PHP 8.2 and is tested on PHP 8.2 through PHP 8.5.

* PHP `fileinfo` extension must be present; so make sure this line is active in your php.ini: `extension=php_fileinfo.dll`
* PHP `iconv` extension must be present; so make sure this line is active in your php.ini: `extension=php_iconv.dll`
* PHP `imap` extension must be present; so make sure this line is active in your php.ini: `extension=php_imap.dll`
* PHP `mbstring` extension must be present; so make sure this line is active in your php.ini: `extension=php_mbstring.dll`
* PHP `json` extension must be present; so make sure this line is active in your php.ini: `extension=json.dll`
* PHP `fileinfo`, `iconv`, `mbstring`, and `json` extensions must be present.
* PHP `ext-imap` must be present.
* On PHP `8.2` and `8.3`, install or enable the IMAP extension provided by your PHP distribution. On Windows, this can still mean enabling `extension=php_imap.dll` in `php.ini`.
* On PHP `8.4` and newer, install IMAP from PECL and enable it for your CLI and web SAPIs.
* When building IMAP from source, you may also need `c-client`, OpenSSL, and Kerberos development libraries.
* `ext-imap` is not thread-safe and should not be used with ZTS builds.

### Installation by Composer

Before running `composer require` or `composer install`, make sure `ext-imap` is installed for the PHP version you are using.

Install the [latest available release](https://github.com/barbushin/php-imap/releases):

$ composer require php-imap/php-imap
Expand All @@ -61,7 +64,7 @@ Install the latest available and stable source code from `master`, which is may

### Run Tests

Before you can run the any tests you may need to run `composer install` to install all (development) dependencies.
Before you can run any tests you need a working `ext-imap` installation and you may need to run `composer install` to install all development dependencies.

#### Run all tests

Expand All @@ -79,7 +82,7 @@ You can run all PHPUnit tests by running the following command (inside of the in

Below, you'll find an example code how you can use this library. For further information and other examples, you may take a look at the [wiki](https://github.com/barbushin/php-imap/wiki).

By default, this library uses random filenames for attachments as identical file names from other emails would overwrite other attachments. If you want to keep the original file name, you can set the attachment filename mode to ``true``, but then you also need to ensure, that those files don't get overwritten by other emails for example.
By default, this library uses random filenames for attachments as identical file names from other emails would overwrite other attachments. If you want to keep the original file name, you can set the attachment filename mode to `true`. For backward compatibility, this still overwrites an existing file with the same name. If you want to keep the original file name and automatically suffix duplicates with ` (1)`, ` (2)`, and so on, set the attachment filename collision mode to `PhpImap\Mailbox::ATTACHMENT_FILENAME_COLLISION_SUFFIX`.

```php
// Create PhpImap\Mailbox instance for all further actions
Expand All @@ -93,6 +96,10 @@ $mailbox = new PhpImap\Mailbox(
false // Attachment filename mode (optional; false = random filename; true = original filename)
);

$mailbox->setAttachmentFilenameCollisionMode(
PhpImap\Mailbox::ATTACHMENT_FILENAME_COLLISION_SUFFIX
);

// set some connection arguments (if appropriate)
$mailbox->setConnectionArgs(
CL_EXPUNGE // expunge deleted mails upon mailbox close
Expand All @@ -118,6 +125,9 @@ if(!$mailsIds) {
die('Mailbox is empty');
}

// If you want to inspect a message without changing its seen state,
// use getMail($id, false) or getRawMail($id, false).

// Get the first message
// If '__DIR__' was defined in the first line, it will automatically
// save all attachments to the specified directory
Expand All @@ -134,11 +144,17 @@ if($mail->hasAttachments()) {
// Print all information of $mail
print_r($mail);

// Access arbitrary headers without adding custom properties to the library
$originMessageId = $mail->getHeader('Origin-MessageID');
$receivedHeaders = $mail->getHeaders('Received');

// Print all attachements of $mail
echo "\n\nAttachments:\n";
print_r($mail->getAttachments());
```

`searchMailbox()` delegates criteria evaluation to PHP's IMAP extension and the IMAP server behind it. This library includes a fallback for simple `SEEN ... SINCE ...` searches because some `ext-imap` / server combinations do not immediately return messages marked as seen earlier on the same day. More complex `imap_search()` behavior still depends on the underlying IMAP implementation.

Method `imap()` allows to call any [PHP IMAP function](https://www.php.net/manual/ref.imap.php) in a context of the instance. Example:

```php
Expand Down
118 changes: 59 additions & 59 deletions examples/get_and_parse_all_emails_with_matching_subject.php
Original file line number Diff line number Diff line change
@@ -1,74 +1,74 @@
<?php

/**
* Example: Get and parse all emails which match the subject "part of the subject" with saving their attachments.
*
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
declare(strict_types=1);
/**
* Example: Get and parse all emails which match the subject "part of the subject" with saving their attachments.
*
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
declare(strict_types=1);

require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/../vendor/autoload.php';

use PhpImap\Exceptions\ConnectionException;
use PhpImap\Mailbox;
use PhpImap\Exceptions\ConnectionException;
use PhpImap\Mailbox;

$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********', // Password for the before configured username
__DIR__, // Directory, where attachments will be saved (optional)
'US-ASCII' // Server encoding (optional)
);
$mailbox = new Mailbox(
'{imap.gmail.com:993/imap/ssl}INBOX', // IMAP server and mailbox folder
'some@gmail.com', // Username for the before configured mailbox
'*********', // Password for the before configured username
__DIR__, // Directory, where attachments will be saved (optional)
'US-ASCII' // Server encoding (optional)
);

try {
$mail_ids = $mailbox->searchMailbox('SUBJECT "part of the subject"');
} catch (ConnectionException $ex) {
exit('IMAP connection failed: '.$ex->getMessage());
} catch (Exception $ex) {
exit('An error occured: '.$ex->getMessage());
}
try {
$mail_ids = $mailbox->searchMailbox('SUBJECT "part of the subject"');
} catch (ConnectionException $ex) {
exit('IMAP connection failed: '.$ex->getMessage());
} catch (Exception $ex) {
exit('An error occured: '.$ex->getMessage());
}

foreach ($mail_ids as $mail_id) {
echo "+------ P A R S I N G ------+\n";
foreach ($mail_ids as $mail_id) {
echo "+------ P A R S I N G ------+\n";

$email = $mailbox->getMail(
$mail_id, // ID of the email, you want to get
false // Do NOT mark emails as seen (optional)
);
$email = $mailbox->getMail(
$mail_id, // ID of the email, you want to get
false // Do NOT mark emails as seen (optional)
);

echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n";
echo 'from-email: '.(string) $email->fromAddress."\n";
echo 'to: '.(string) $email->toString."\n";
echo 'subject: '.(string) $email->subject."\n";
echo 'message_id: '.(string) $email->messageId."\n";
echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n";
echo 'from-email: '.(string) $email->fromAddress."\n";
echo 'to: '.(string) $email->toString."\n";
echo 'subject: '.(string) $email->subject."\n";
echo 'message_id: '.(string) $email->messageId."\n";

echo 'mail has attachments? ';
if ($email->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}
echo 'mail has attachments? ';
if ($email->hasAttachments()) {
echo "Yes\n";
} else {
echo "No\n";
}

if (!empty($email->getAttachments())) {
echo \count($email->getAttachments())." attachements\n";
}
if ($email->textHtml) {
echo "Message HTML:\n".$email->textHtml;
} else {
echo "Message Plain:\n".$email->textPlain;
}
if (!empty($email->getAttachments())) {
echo \count($email->getAttachments())." attachements\n";
}
if ($email->textHtml) {
echo "Message HTML:\n".$email->textHtml;
} else {
echo "Message Plain:\n".$email->textPlain;
}

if (!empty($email->autoSubmitted)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Auto-Reply ------+\n";
}
if (!empty($email->autoSubmitted)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Auto-Reply ------+\n";
}

if (!empty($email_content->precedence)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Non-Delivery Report/Receipt ------+\n";
}
if (!empty($email_content->precedence)) {
// Mark email as "read" / "seen"
$mailbox->markMailAsRead($mail_id);
echo "+------ IGNORING: Non-Delivery Report/Receipt ------+\n";
}
}

$mailbox->disconnect();
$mailbox->disconnect();
Loading
Loading