turahe/mailclient

A comprehensive Laravel mail client package for managing email accounts, messages, and folders

v1.2.1 2025-09-05 04:04 UTC

This package is auto-updated.

Last update: 2025-09-05 04:06:10 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads License PHP Version Require Test Coverage

A comprehensive Laravel mail client package for managing email accounts, messages, and folders with support for IMAP, SMTP, Gmail, Outlook, and various email providers.

๐Ÿ“‹ Table of Contents

โœจ Features

  • ๐Ÿ” Multi-Provider Support - IMAP, SMTP, Gmail API, Outlook/Exchange
  • ๐Ÿ“ง Complete Email Management - Send, receive, organize, and track emails
  • ๐Ÿ“‚ Folder Hierarchy - Nested folder structures with full CRUD operations
  • ๐Ÿ“‹ Email Templates - Predefined and reusable email templates
  • โฐ Scheduled Emails - Queue and schedule emails for future delivery
  • ๐Ÿ“Š Link Tracking - Track email link clicks and analytics
  • ๐Ÿ”„ Sync Management - Intelligent email synchronization
  • ๐Ÿ†” ULID Support - Modern, sortable unique identifiers
  • ๐Ÿงช 100% Test Coverage - 173 tests, 566 assertions, rock-solid reliability

๐Ÿš€ Requirements

Component Version
PHP 8.4+
Laravel 12.0+
Database MySQL 8.0+ / PostgreSQL 13+ / SQLite 3.35+

โšก Quick Start

1. Install Package

composer require turahe/mailclient

2. Publish & Migrate

php artisan vendor:publish --provider="Turahe\MailClient\MailClientServiceProvider"
php artisan migrate

3. Create Your First Email Account

use Turahe\MailClient\Models\EmailAccount;
use Turahe\MailClient\Enums\ConnectionType;

$account = EmailAccount::create([
    'email' => 'user@example.com',
    'password' => 'your_password',
    'connection_type' => ConnectionType::IMAP,
    'imap_server' => 'imap.example.com',
    'imap_port' => 993,
    'smtp_server' => 'smtp.example.com',
    'smtp_port' => 587,
]);

4. Send Your First Email

$client = $account->createClient();

$message = $client->compose()
    ->to('recipient@example.com')
    ->subject('Hello World!')
    ->html('<h1>Hello from Laravel Mail Client!</h1>')
    ->send();

โš™๏ธ Configuration

Environment Setup

# Gmail OAuth
GMAIL_CLIENT_ID=your_gmail_client_id
GMAIL_CLIENT_SECRET=your_gmail_client_secret
GMAIL_REDIRECT_URL=your_callback_url

# Outlook OAuth  
OUTLOOK_CLIENT_ID=your_outlook_client_id
OUTLOOK_CLIENT_SECRET=your_outlook_client_secret
OUTLOOK_REDIRECT_URL=your_callback_url

Package Configuration

// config/mail-client.php
return [
    'default_connection_type' => 'imap',
    'sync_batch_size' => 50,
    'max_attachment_size' => 25 * 1024 * 1024, // 25MB
    'allowed_attachment_types' => ['pdf', 'doc', 'docx', 'jpg', 'png'],
];

๐Ÿ“ง Basic Usage

๐Ÿ“ฅ Email Account Management

Creating Different Account Types

IMAP/SMTP Account

$account = EmailAccount::create([
    'email' => 'user@example.com',
    'password' => 'secure_password',
    'connection_type' => ConnectionType::IMAP,
    'imap_server' => 'imap.example.com',
    'imap_port' => 993,
    'imap_encryption' => 'ssl',
    'smtp_server' => 'smtp.example.com',
    'smtp_port' => 587,
    'smtp_encryption' => 'tls',
]);

Gmail Account

$gmailAccount = EmailAccount::create([
    'email' => 'user@gmail.com',
    'connection_type' => ConnectionType::GMAIL,
    'access_token' => $accessToken,
    'refresh_token' => $refreshToken,
]);

Outlook Account

$outlookAccount = EmailAccount::create([
    'email' => 'user@outlook.com', 
    'connection_type' => ConnectionType::OUTLOOK,
    'access_token' => $accessToken,
    'refresh_token' => $refreshToken,
]);

Account Operations

// Test connection
if ($account->testConnection()) {
    echo "โœ… Connection successful!";
}

// Sync management
$account->enableSync();
$account->disableSync();

// Get statistics
$stats = $account->getStats();
echo "๐Ÿ“ง Total: {$stats['total_messages']}";
echo "๐Ÿ”ต Unread: {$stats['unread_messages']}";
๐Ÿ“‚ Folder Management

Creating and Organizing Folders

// Create main folder
$folder = EmailAccountFolder::create([
    'email_account_id' => $account->id,
    'name' => 'Important',
    'display_name' => 'Important Messages',
    'syncable' => true,
]);

// Create subfolder
$subFolder = EmailAccountFolder::create([
    'email_account_id' => $account->id,
    'parent_id' => $folder->id,
    'name' => 'Urgent',
    'display_name' => 'Urgent Items',
]);

// Browse hierarchy
$rootFolders = $account->folders()->whereNull('parent_id')->get();
foreach ($rootFolders as $folder) {
    echo "๐Ÿ“ {$folder->name}\n";
    foreach ($folder->children as $child) {
        echo "   โ””โ”€ ๐Ÿ“ {$child->name}\n";
    }
}
๐Ÿ“จ Sending Emails

Basic Email Composition

$client = $account->createClient();

// Simple email
$message = $client->compose()
    ->to('user@example.com')
    ->subject('Meeting Tomorrow')
    ->text('Don\'t forget our meeting at 2 PM tomorrow.')
    ->send();

// Rich HTML email
$message = $client->compose()
    ->to('user@example.com')
    ->cc('manager@example.com')
    ->bcc('archive@example.com')
    ->subject('Project Update')
    ->html('
        <h2>Project Status Update</h2>
        <p>The project is <strong>on track</strong> for completion.</p>
        <ul>
            <li>โœ… Phase 1: Complete</li>
            <li>๐Ÿ”„ Phase 2: In Progress</li>
            <li>โณ Phase 3: Planned</li>
        </ul>
    ')
    ->attach('/path/to/report.pdf')
    ->send();

Using Templates

$template = PredefinedMailTemplate::find(1);
$message = $client->compose()
    ->to('customer@example.com')
    ->fromTemplate($template)
    ->variables([
        'customer_name' => 'John Doe',
        'order_number' => 'ORD-12345',
        'delivery_date' => '2025-01-15'
    ])
    ->send();
๐Ÿ“ฌ Managing Messages

Reading Messages

// Get recent unread messages
$messages = $account->messages()
    ->unread()
    ->orderBy('date', 'desc')
    ->take(10)
    ->get();

foreach ($messages as $message) {
    echo "๐Ÿ“ง {$message->subject}\n";
    echo "๐Ÿ‘ค From: {$message->from_address}\n";
    echo "๐Ÿ“… Date: {$message->date}\n\n";
}

Message Operations

$message = EmailAccountMessage::find($messageId);

// Status operations
$message->markAsRead();
$message->markAsUnread();

// Organization
$message->moveToFolder($importantFolder);
$message->addToFolders([$folder1, $folder2]);

// Lifecycle management
$message->archive();
$message->trash();
$message->restore();
$message->purge(); // Permanent delete

Working with Content

// Get message content
$htmlBody = $message->getHtmlBody();
$textBody = $message->getTextBody();

// Handle attachments
foreach ($message->attachments as $attachment) {
    echo "๐Ÿ“Ž {$attachment->name} ({$attachment->size} bytes)\n";
    
    // Download attachment
    $content = $attachment->getContent();
    file_put_contents("/downloads/{$attachment->name}", $content);
}

๐Ÿš€ Advanced Features

๐Ÿ“‹ Email Templates

Creating Templates

$template = PredefinedMailTemplate::create([
    'name' => 'Order Confirmation',
    'subject' => 'Order {{order_number}} Confirmed',
    'html_body' => '
        <h1>Order Confirmed! ๐ŸŽ‰</h1>
        <p>Hello {{customer_name}},</p>
        <p>Your order <strong>#{{order_number}}</strong> has been confirmed.</p>
        <p>Expected delivery: {{delivery_date}}</p>
    ',
    'text_body' => 'Hello {{customer_name}}, your order #{{order_number}} is confirmed. Delivery: {{delivery_date}}',
    'is_shared' => true,
]);

Using Template Variables

$processedTemplate = $template->process([
    'customer_name' => 'Sarah Johnson',
    'order_number' => 'ORD-789',
    'delivery_date' => 'January 20, 2025'
]);

// Result:
// Subject: "Order ORD-789 Confirmed"
// Body: "Hello Sarah Johnson, your order #ORD-789 is confirmed..."
โฐ Scheduled Emails

Scheduling Emails

$scheduledEmail = ScheduledEmail::create([
    'email_account_id' => $account->id,
    'to' => 'customer@example.com',
    'subject' => 'Weekly Newsletter',
    'html_body' => '<h1>This Week in Tech</h1>...',
    'scheduled_at' => Carbon::now()->addWeek(),
    'data' => ['newsletter_id' => 456],
]);

Processing Scheduled Emails

// In your scheduled job (e.g., daily)
$dueEmails = ScheduledEmail::dueForSend()->get();

foreach ($dueEmails as $email) {
    try {
        $email->send();
        echo "โœ… Sent: {$email->subject}\n";
    } catch (Exception $e) {
        echo "โŒ Failed: {$e->getMessage()}\n";
    }
}
๐Ÿ“Š Link Tracking

Automatic Link Tracking

// Links in emails are automatically tracked
$message = $client->compose()
    ->to('user@example.com')
    ->subject('Check out our new features!')
    ->html('
        <p>Visit our <a href="https://example.com/features">new features page</a></p>
        <p>Read the <a href="https://example.com/blog/update">latest blog post</a></p>
    ')
    ->send();

Analyzing Click Data

$message = EmailAccountMessage::find($messageId);

// Get all clicks
$clicks = $message->linkClicks;

foreach ($clicks as $click) {
    echo "๐Ÿ”— URL: {$click->url}\n";
    echo "๐Ÿ“… Clicked: {$click->clicked_at}\n";
    echo "๐ŸŒ IP: {$click->ip_address}\n";
    echo "๐Ÿ’ป Browser: {$click->user_agent}\n\n";
}

// Statistics
$totalClicks = $message->linkClicks()->count();
$uniqueClicks = $message->linkClicks()->distinct('ip_address')->count();
echo "๐Ÿ“Š Total clicks: {$totalClicks} | Unique: {$uniqueClicks}";
๐Ÿ”„ Bulk Operations

Mass Message Management

// Get messages to process
$messages = $account->messages()
    ->where('subject', 'like', '%newsletter%')
    ->get();

// Bulk operations
$account->moveMessagesToFolder($messages, $newsletterFolder);
$account->markMessagesAsRead($messages);
$account->deleteMessages($messages);

Sync Management

use Turahe\MailClient\Services\EmailAccountMessageSyncService;

$syncService = app(EmailAccountMessageSyncService::class);

// Full account sync
$syncService->syncAccount($account);

// Incremental sync (faster)
$lastSync = $account->last_synced_at;
$syncService->syncAccountIncremental($account, $lastSync);

// Sync specific folder only
$syncService->syncFolder($folder);

๐Ÿ—๏ธ Models & Architecture

Core Models Overview

Model Purpose Key Features
EmailAccount Email account management Multi-provider support, OAuth, sync settings
EmailAccountFolder Folder organization Hierarchical structure, sync control
EmailAccountMessage Message storage Rich content, attachments, metadata
EmailAccountMessageAddress Email addresses From, To, CC, BCC tracking
EmailAccountMessageHeader Email headers Technical metadata storage
PredefinedMailTemplate Email templates Variable substitution, sharing
ScheduledEmail Email scheduling Queue management, retry logic
MessageLinksClick Link analytics Click tracking, user behavior

Key Relationships

// EmailAccount (1:N)
$account->folders;           // All folders
$account->messages;          // All messages  
$account->scheduledEmails;   // Scheduled emails

// EmailAccountMessage (N:M)
$message->folders;           // Associated folders
$message->addresses;         // Email addresses
$message->headers;           // Technical headers
$message->linkClicks;        // Click analytics

// EmailAccountFolder (Tree)
$folder->parent;             // Parent folder
$folder->children;           // Child folders
$folder->messages;           // Folder messages

๐Ÿงช Testing

Running Tests

# All tests (173 tests, 566 assertions)
vendor/bin/phpunit

# Specific test suites
vendor/bin/phpunit --testsuite=Unit     # Unit tests only
vendor/bin/phpunit --testsuite=Feature  # Feature tests only

# With coverage report
vendor/bin/phpunit --coverage-html coverage

Using Test Factories

use Turahe\MailClient\Tests\Factories\EmailAccountFactory;

// Create test account
$account = EmailAccountFactory::new()->create([
    'email' => 'test@example.com'
]);

// Create account with related data
$account = EmailAccountFactory::new()
    ->withMessages(10)      // 10 messages
    ->withFolders(5)        // 5 folders
    ->create();

// Create specific message
$message = EmailAccountMessageFactory::new()
    ->forAccount($account)
    ->create([
        'subject' => 'Test Message',
        'from_address' => 'sender@example.com'
    ]);

๐Ÿ“– API Reference

EmailAccount Methods
// Connection management
$account->testConnection(): bool
$account->createClient(): Client

// Sync control
$account->enableSync(): void
$account->disableSync(): void
$account->isSyncDisabled(): bool

// Statistics
$account->getStats(): array
$account->getUnreadCount(): int

// Token management (OAuth accounts)
$account->refreshAccessToken(): void
$account->isTokenExpired(): bool
EmailAccountMessage Methods
// Status management
$message->markAsRead(): void
$message->markAsUnread(): void
$message->isRead(): bool

// Organization
$message->moveToFolder(EmailAccountFolder $folder): void
$message->addToFolders(array $folders): void
$message->removeFromFolder(EmailAccountFolder $folder): void

// Lifecycle
$message->archive(): void
$message->trash(): void
$message->restore(): void
$message->purge(): void

// Content access
$message->getHtmlBody(): string
$message->getTextBody(): string
$message->hasAttachments(): bool
PredefinedMailTemplate Methods
// Template processing
$template->process(array $variables): array
$template->getProcessedSubject(array $variables): string
$template->getProcessedBody(array $variables): string

// Sharing
$template->makeShared(): void
$template->makePrivate(): void
$template->isShared(): bool

๐Ÿ› Troubleshooting

Connection Issues

Problem: Connection timeout errors

// Solution: Increase timeout settings
'imap_timeout' => 60,  // seconds
'smtp_timeout' => 30,  // seconds

Problem: SSL certificate errors

// Solution: Disable SSL verification (development only)
'imap_options' => [
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false,
    ]
]
Memory Issues

Problem: Memory exhaustion with large attachments

// Solution 1: Increase memory limit
ini_set('memory_limit', '512M');

// Solution 2: Use streaming
$attachment->streamToFile('/path/to/destination');

// Solution 3: Process in chunks
$account->messages()->chunk(50, function ($messages) {
    // Process 50 messages at a time
});
OAuth Token Issues

Problem: Expired access tokens

// Solution: Automatic token refresh
if ($account->isTokenExpired()) {
    $account->refreshAccessToken();
}

// Or handle in exception
try {
    $client->getMessages();
} catch (UnauthorizedException $e) {
    $account->refreshAccessToken();
    $client->getMessages(); // Retry
}

๐Ÿ› ๏ธ Contributing

We welcome contributions! Here's how to get started:

Development Setup

# Clone and setup
git clone https://github.com/turahe/mail-client.git
cd mail-client
composer install

# Prepare testing
cp phpunit.xml.dist phpunit.xml
vendor/bin/phpunit

# Start coding!

Contribution Process

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (vendor/bin/phpunit)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Code Standards

  • โœ… PHP 8.4+ type declarations
  • โœ… PSR-12 coding standards
  • โœ… 100% test coverage for new features
  • โœ… PHPStan level 8 compliance
  • โœ… Clear documentation for public methods

๐Ÿ“ž Support

๐Ÿ“„ License

This package is open-sourced software licensed under the MIT license.

๐Ÿ“ˆ Changelog

See CHANGELOG.md for version history and updates.

Built with โค๏ธ for the Laravel community

โญ Star us on GitHub โ€ข ๐Ÿ“ฆ View on Packagist