tedivm/fetch
Fetch is a PHP library for reading email and attachments via IMAP and POP. Connect to a mail server, authenticate, list messages, and access subjects, bodies, and attachments with a simple API (requires the PHP IMAP extension).
Installation
composer require tedivm/fetch
Add to composer.json if using a custom namespace:
"autoload": {
"psr-4": {
"App\\": "app/",
"Fetch\\": "vendor/tedivm/fetch/src/"
}
}
Run composer dump-autoload.
First Use Case: Connecting to IMAP
use Fetch\IMAP\Client;
use Fetch\IMAP\Connection;
$connection = new Connection('imap.example.com', 993, true);
$client = new Client($connection, 'username', 'password');
$client->connect();
Key Files to Explore
src/IMAP/Client.php – Core client logic.src/IMAP/Connection.php – Connection handling.src/IMAP/Message.php – Message parsing and manipulation.src/IMAP/Exception/ – Error handling.// Fetch all messages in the inbox
$messages = $client->getMessages('INBOX');
// Fetch a specific message
$message = $client->getMessage('INBOX', 1);
// Search for unread emails
$unread = $client->search('INBOX', 'UNSEEN');
// Search with multiple criteria
$results = $client->search('INBOX', 'FROM "sender@example.com" SUBJECT "Hello"');
$message = $client->getMessage('INBOX', 1);
foreach ($message->getAttachments() as $attachment) {
$attachment->saveTo('/path/to/save/' . $attachment->getName());
}
$message = $client->getMessage('INBOX', 1);
$message->streamBody(function ($chunk) {
// Process chunk (e.g., log, save to file)
file_put_contents('large_email.txt', $chunk, FILE_APPEND);
});
// config/imap.php
return [
'host' => env('IMAP_HOST'),
'port' => env('IMAP_PORT', 993),
'ssl' => env('IMAP_SSL', true),
'username' => env('IMAP_USERNAME'),
'password' => env('IMAP_PASSWORD'),
];
// app/Providers/IMAPServiceProvider.php
public function register()
{
$this->app->singleton('imap.client', function ($app) {
$config = $app['config']['imap'];
$connection = new Connection($config['host'], $config['port'], $config['ssl']);
return new Client($connection, $config['username'], $config['password']);
});
}
$messages = $client->getMessages('INBOX', ['UNSEEN', 'SINCE 01-Jan-2023']);
foreach ($messages as $message) {
// Process each message (e.g., parse, store in DB)
$this->processMessage($message);
}
Use tedivm/fetch alongside Laravel’s Mail facade for hybrid email handling:
// Send a mail via Laravel
Mail::to('user@example.com')->send(new WelcomeMail());
// Fetch sent emails via IMAP
$sent = $client->search('Sent', 'FROM "me@example.com"');
Wrap IMAP operations in Laravel events for observability:
// In a service class
event(new EmailFetched($message));
// In EventServiceProvider
protected $listen = [
EmailFetched::class => [
EmailLogger::class,
EmailProcessor::class,
],
];
Cache frequent IMAP queries (e.g., unread count) to reduce API calls:
$unreadCount = Cache::remember('imap.unread.count', now()->addMinutes(5), function () {
return $client->search('INBOX', 'UNSEEN')->count();
});
$connection = new Connection('imap.example.com', 993, true, 30); // 30s timeout
$message->streamBody(...); // Avoid loading entire email into memory
$connection = new Connection('imap.example.com', 993, true);
stream_context_set_option($connection->getStream(), 'ssl', [
'verify_peer' => false, // Disable for testing (not recommended for production)
'verify_peer_name' => false,
]);
$body = mb_convert_encoding($message->getBody(), 'UTF-8', 'ISO-8859-1');
sleep(60); // Wait 60s between checks
$client->setDebug(true); // Logs raw IMAP commands/responses
Check logs for malformed queries or server errors.
Wrap IMAP calls in try-catch blocks:
try {
$messages = $client->getMessages('INBOX');
} catch (Fetch\IMAP\Exception\ConnectionException $e) {
Log::error('IMAP connection failed', ['error' => $e->getMessage()]);
// Retry or notify admin
}
Fetch\IMAP\Exception\ConnectionException: Connection issues (host, credentials, timeout).Fetch\IMAP\Exception\LoginException: Invalid username/password.Fetch\IMAP\Exception\SearchException: Invalid search query.Avoid naming conflicts by aliasing the package:
use Fetch\IMAP\Client as IMAPClient;
Store IMAP credentials in .env:
IMAP_HOST=imap.example.com
IMAP_PORT=993
IMAP_SSL=true
IMAP_USERNAME=user@example.com
IMAP_PASSWORD=securepassword
Add custom methods to Fetch\IMAP\Message for domain-specific logic:
namespace App\Extensions;
use Fetch\IMAP\Message as BaseMessage;
class Message extends BaseMessage
{
public function isPromotional()
{
return stripos($this->getSubject(), 'promo') !== false;
}
}
Use Mockery or Laravel’s MockFacade to test IMAP interactions:
$mockClient = Mockery::mock('overload:Fetch\IMAP\Client');
$mockClient->shouldReceive('getMessages')->andReturn([$mockMessage]);
BODY.PEEK[HEADER] for headers only).getMessageIds() instead of getMessages() for large mailboxes:
$ids = $client->getMessageIds('INBOX');
foreach ($ids as $id) {
$client->getMessage('INBOX', $id, ['BODY.PEEK[HEADER]']);
}
Fetch\IMAP\OAuth2 for authentication:
$client = new Client($connection, 'user@example.com', null, [
'oauth' => true,
'oauth_user_token' => 'ya29.a0Ae...',
]);
How can I help you explore Laravel packages today?