monkeyscloud / monkeyslegion-mail
Mail integration package for the MonkeysLegion framework.
Requires
- php: ^8.4
- league/commonmark: ^2.7
- monkeyscloud/monkeyslegion-cli: ^1.0
- monkeyscloud/monkeyslegion-core: ^1.0
- monkeyscloud/monkeyslegion-di: ^1.0
- monkeyscloud/monkeyslegion-template: ^1.0
- psr/log: ^3.0
- vlucas/phpdotenv: ^5.6
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.2
README
A powerful, feature-rich mail package for the MonkeysLegion PHP framework, providing robust email functionality with DKIM signing, queue support, rate limiting, and elegant template rendering.
📋 What's Inside
This comprehensive mail package includes everything you need for professional email handling:
🚀 Getting Started
- Quick Installation: Automated setup with scaffolding
- Configuration: Environment variables and driver setup
- First Email: Send your first email in minutes
📧 Core Email Features
- Multiple Transports: SMTP, Sendmail, Mailgun, and Null drivers
- Direct Sending: Immediate email delivery
- Queue System: Background email processing with Redis
- Rate Limiting: Prevent spam and control sending limits
🛡️ Security & Authentication
- DKIM Signing: Digital signatures for email authentication
- SPF/DMARC Ready: Compatible with modern email security
- Raw Key Support: Simplified DKIM key management
🎨 Template System
- Mailable Classes: Object-oriented email composition
- ML View Engine: Powerful template rendering
- Email Components: Reusable UI components
- Dynamic Content: Data binding and conditional rendering
⚡ Advanced Features
- CLI Commands: Command-line email management
- Queue Management: Job retry, failure handling
- Logging: Comprehensive PSR-3 compatible logging
- Events: Email lifecycle tracking
🔧 Developer Tools
- Make Commands: Generate mail classes instantly
- Testing Tools: Test email sending without queues
- Debug Mode: Detailed logging and error reporting
🚀 Quick Start
Installation
# Install Monkeys Legion App composer create-project --stability=dev \ monkeyscloud/monkeyslegion-skeleton my-app "dev-main" # Publish configuration and scaffolding php vendor/bin/ml mail:install
Basic Configuration
Add these variables to your .env
file:
# Basic SMTP Configuration MAIL_DRIVER=smtp MAIL_HOST=smtp.gmail.com MAIL_PORT=587 MAIL_USERNAME=your-email@gmail.com MAIL_PASSWORD=your-app-password MAIL_ENCRYPTION=tls # OR Mailgun Configuration MAILGUN_API_KEY=YOUR_MAILGUN_API_KEY MAILGUN_DOMAIN=YOUR_MAILGUN_DOMAIN # DKIM Configuration (Optional but Recommended) MAIL_DKIM_PRIVATE_KEY=your-raw-private-key-without-headers MAIL_DKIM_SELECTOR=default MAIL_DKIM_DOMAIN=yourdomain.com # Queue Configuration (Optional but required in queueing) REDIS_HOST=127.0.0.1 REDIS_PORT=6379 QUEUE_DEFAULT=emails # A Global Configuration MAIL_FROM_ADDRESS=your-email@gmail.com MAIL_FROM_NAME="Your App Name"
You can always check the mail.php config file to see all the available options you can set in your .env
Test Your Setup
# Test email sending
php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:test your-email@example.com
📧 Sending Emails
Direct Sending
use MonkeysLegion\Mail\Mailer; // Get mailer instance /** @var Mailer */ $mailer = ML_CONTAINER->get(Mailer::class); // Send immediately $mailer->send( 'user@example.com', 'Welcome to Our App', '<h1>Welcome!</h1><p>Thanks for joining us.</p>', 'text/html' );
Queue-Based Sending
// Queue for background processing (required env redis vars) $jobId = $mailer->queue( 'user@example.com', 'Welcome to Our App', '<h1>Welcome!</h1><p>Thanks for joining us.</p>', 'text/html' ); echo "Email queued with job ID: $jobId";
Using Mailable Classes
// Generate a new mailable class php vendor/bin/ml make:mail WelcomeMail // Use the generated class use App\Mail\WelcomeMail; $mail = new WelcomeMail(); $mail->setTo('user@example.com') ->setViewData(['name' => 'John Doe']) ->send(); // or ->queue()
🎨 Mailable Classes
Mailable classes provide an elegant, object-oriented way to compose emails with templates, data binding, and fluent configuration.
Creating a Mailable
# Generate a new mailable class
php vendor/bin/ml make:mail OrderConfirmation
Example Mailable Class
<?php namespace App\Mail; use MonkeysLegion\Mail\Mail\Mailable; class OrderConfirmationMail extends Mailable { public function __construct( private array $order, private array $customer ) { parent::__construct(); } public function build(): self { return $this->view('emails.order-confirmation') ->subject('Order Confirmation #' . $this->order['id']) ->withData([ 'order' => $this->order, 'customer' => $this->customer, 'total' => $this->order['total'] ]) ->attach('/path/to/invoice.pdf'); } }
Using Mailable Classes
// Create and send $order = ['id' => 12345, 'total' => 99.99]; $customer = ['name' => 'John Doe', 'email' => 'john@example.com']; $mail = new OrderConfirmationMail($order, $customer); // Send immediately $mail->setTo('john@example.com')->send(); // Or queue for background processing $jobId = $mail->setTo('john@example.com')->queue(); // Configure dynamically $mail->setTo('john@example.com') ->setSubject('Custom Subject') ->onQueue('high-priority') ->send();
Mailable Features
Template Binding
public function build(): self { // emails.welcome => root/resources/views/emails/welcome.ml.php return $this->view('emails.welcome', [ 'user' => $this->user, 'loginUrl' => 'https://app.com/login' ]); }
Overridable Properties
Child classes can override these properties to set defaults:
class OrderConfirmationMail extends Mailable { // Queue configuration protected ?string $queue = 'orders'; protected ?int $timeout = 120; protected ?int $maxTries = 5; // Content settings protected string $contentType = 'text/html'; // Runtime methods also available public function build(): self { return $this->view('emails.order') ->setTimeout(180) // Override timeout ->setMaxTries(3) // Override max tries ->setContentType('text/html') // Override content type ->addAttachment('/path/to/invoice.pdf'); } }
Available Configuration Methods
Method | Description | Example |
---|---|---|
setTimeout(int $timeout) |
Set job timeout in seconds | ->setTimeout(120) |
setMaxTries(int $tries) |
Set maximum retry attempts | ->setMaxTries(5) |
setContentType(string $type) |
Set content type | ->setContentType('text/plain') |
addAttachment(string $path, ?string $name, ?string $mime) |
Add file attachment | ->addAttachment('/path/file.pdf', 'Invoice.pdf') |
setAttachments(array $attachments) |
Set all attachments | ->setAttachments($fileArray) |
Attachments
public function build(): self { return $this->view('emails.newsletter') ->addAttachment('/path/to/file.pdf', 'Newsletter.pdf') ->setAttachments([ '/path/to/direct-file.pdf', // simple string path or URL 'https://example.com/file.pdf', // URL as string ['path' => '/path/file1.pdf', 'name' => 'File1.pdf'], ['path' => '/path/file2.pdf', 'mime_type' => 'application/pdf'], ['path' => 'https://example.com/file3.pdf', 'name' => 'File3.pdf', 'mime_type' => 'application/pdf'] ]); }
Conditional Logic
public function build(): self { return $this->view('emails.notification') ->when($this->user->isPremium(), function($mail) { $mail->addAttachment('/path/to/premium-guide.pdf'); }) ->unless($this->user->hasSeenWelcome(), function($mail) { $mail->withData(['showWelcome' => true]); }); }
📊 Queue System
The queue system allows you to send emails in the background, improving application performance and providing retry capabilities.
How It Works
- Queue Email: Email is serialized and stored in Redis
- Worker Processing: Background worker picks up jobs
- Retry Logic: Failed jobs are automatically retried
- Failure Handling: Permanently failed jobs are moved to failed queue
Queue Benefits
- Performance: Non-blocking email sending
- Reliability: Automatic retries for failed sends
- Scalability: Multiple workers can process jobs
- Monitoring: Track job status and failures
Example Queue Workflow
// In your application $jobId = $mailer->queue( 'user@example.com', 'Newsletter', $htmlContent, 'text/html', [], // attachments 'newsletters' // specific queue ); // Start worker (separate process) // php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:work newsletters
Queue Monitoring
# Monitor queue status php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:list # Check for failed jobs php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:failed # Get queue statistics redis-cli llen queue:emails # Pending jobs redis-cli llen queue:failed # Failed jobs
🔧 CLI Commands
The mail package includes powerful CLI commands for testing, queue management, and maintenance.
Email Testing
# Test email sending (bypasses queue)
php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:test user@example.com
DKIM Key Generation
# Generate DKIM private and public key files in the specified directory php vendor/bin/ml make:dkim-pkey <directory>
- This will create
dkim_private.key
anddkim_public.key
in the given directory. - Add the public key to your DNS as a TXT record for DKIM.
Queue Management
# Start processing queued emails php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:work # Work on specific queue php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:work high-priority # List pending jobs php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:list # List failed jobs php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:failed # Retry specific failed job php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:retry job_12345 # Retry all failed jobs php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:retry --all # Clear pending jobs php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:clear # Delete all failed jobs php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:flush # Delete ALL jobs (pending + failed) php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:purge
Queue Worker Configuration
Configure worker behavior in config/redis.php
:
'queue' => [ 'worker' => [ 'sleep' => 3, // Seconds between job checks 'max_tries' => 3, // Maximum retry attempts 'memory' => 128, // Memory limit (MB) 'timeout' => 60, // Job timeout (seconds) ], ],
🛡️ DKIM Email Signing
DKIM (DomainKeys Identified Mail) adds digital signatures to your emails, improving deliverability and preventing spoofing.
Why DKIM Matters
- Improved Deliverability: Emails are more likely to reach the inbox
- Authentication: Proves emails actually came from your domain
- Reputation Protection: Prevents others from spoofing your domain
- Compliance: Required by many enterprise email systems
Setting Up DKIM
1. Generate DKIM Keys
use MonkeysLegion\Mail\Security\DkimSigner; // Generate a new key pair $keys = DkimSigner::generateKeys(2048); echo "Private Key:\n" . $keys['private'] . "\n\n"; echo "Public Key:\n" . $keys['public'];
2. Configure Environment
# Use raw private key without BEGIN/END headers MAIL_DKIM_PRIVATE_KEY=MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMODcNBCB7... MAIL_DKIM_SELECTOR=default MAIL_DKIM_DOMAIN=yourdomain.com
3. Add DNS Record
Create a TXT record in your DNS:
Name: default._domainkey.yourdomain.com
Value: v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA4...
4. Verify DKIM
# Test DKIM signing
php vendor/monkeyscloud/monkeyslegion-mail/bin/ml-mail.php mail:test test@gmail.com
DKIM Features
- Automatic Signing: All emails are automatically signed when configured
- Raw Key Support: No need for PEM headers - just paste the key data
- Transport Compatibility: Works with SMTP, Mailgun, and other transports
- Queue Preservation: DKIM signatures are preserved through queue processing
⚙️ Configuration
Driver Configuration
SMTP Driver
'smtp' => [ 'host' => $_ENV['MAIL_HOST'] ?? 'smtp.mailtrap.io', 'port' => $_ENV['MAIL_PORT'] ?? 587, 'encryption' => $_ENV['MAIL_ENCRYPTION'] ?? 'tls', // tls / ssl / null 'username' => $_ENV['MAIL_USERNAME'] ?? '', 'password' => $_ENV['MAIL_PASSWORD'] ?? '', 'timeout' => $_ENV['MAIL_TIMEOUT'] ?? 30, 'from' => [ 'address' => $_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@yourapp.com', 'name' => $_ENV['MAIL_FROM_NAME'] ?? 'My App' ], 'dkim_private_key' => $_ENV['MAIL_DKIM_PRIVATE_KEY'] ?? '', 'dkim_selector' => $_ENV['MAIL_DKIM_SELECTOR'] ?? 'default', 'dkim_domain' => $_ENV['MAIL_DKIM_DOMAIN'] ?? '', ],
Mailgun Driver
'mailgun' => [ 'api_key' => $_ENV['MAILGUN_API_KEY'] ?? '', 'domain' => $_ENV['MAILGUN_DOMAIN'] ?? '', 'from' => [ 'address' => $_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@yourdomain.com', 'name' => $_ENV['MAIL_FROM_NAME'] ?? 'Your App', ], // Optional tracking options (used by addOptionalParameters) 'tracking' => [ 'clicks' => filter_var($_ENV['MAILGUN_TRACK_CLICKS'] ?? true, FILTER_VALIDATE_BOOLEAN), 'opens' => filter_var($_ENV['MAILGUN_TRACK_OPENS'] ?? true, FILTER_VALIDATE_BOOLEAN), ], // Optional delivery time in RFC2822 or ISO 8601 format 'delivery_time' => $_ENV['MAILGUN_DELIVERY_TIME'] ?? null, // Optional array of tags (Mailgun supports up to 3 tags per message) 'tags' => explode(',', $_ENV['MAILGUN_TAGS'] ?? ''), // e.g. "welcome,new-user" // Optional custom variables to include with the message 'variables' => [ // Dynamically assign or leave empty if not used ], // Mailgun region (us or eu) 'region' => $_ENV['MAILGUN_REGION'] ?? 'us', // Optional timeouts 'timeout' => ($_ENV['MAILGUN_TIMEOUT'] ?? 30), 'connect_timeout' => ($_ENV['MAILGUN_CONNECT_TIMEOUT'] ?? 10), // DKIM signing as SMTP configuration ],
Null Driver
'null' => [ 'from' => [ 'address' => $_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@yourdomain.com', 'name' => $_ENV['MAIL_FROM_NAME'] ?? 'Your App' ] ]
Sendmail Driver
'sendmail' => [ 'path' => $_ENV['MAIL_SENDMAIL_PATH'] ?? '/usr/sbin/sendmail', 'from' => [ 'address' => $_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@yourdomain.com', 'name' => $_ENV['MAIL_FROM_NAME'] ?? 'Your App' ], // DKIM signing as SMTP configuration ],
Rate Limiting
Configure rate limiting in config/rate_limiter.php
:
return [ 'key' => 'mail', // Unique identifier 'limit' => 100, // Max emails per window 'seconds' => 60, // Time window (seconds) 'storage_path' => '/mail', // Storage location ];
🎯 Rate Limiting
Prevent spam and control email sending rates with built-in rate limiting.
Configuration
Rate limiting is configured in the config/rate_limiter.php
file:
return [ 'key' => 'mail', // Unique identifier 'limit' => 100, // Max emails per window 'seconds' => 60, // Time window (seconds) 'storage_path' => '/mail', // Storage location ];
Available Methods
use MonkeysLegion\Mail\RateLimiter\RateLimiter; // Create rate limiter with config values $rateLimiter = new RateLimiter('user_123', 100, 3600); // Check remaining quota $remaining = $rateLimiter->remaining(); // e.g., 85 // Get reset time $resetTime = $rateLimiter->resetTime(); // seconds until reset // Get configuration $config = $rateLimiter->getConfig(); // Reset limit (admin function) $rateLimiter->reset(); // Clean old records (scheduled task) $stats = RateLimiter::cleanupAll('/tmp');
Scheduled Cleanup
Add to your cron jobs:
# Clean up old rate limit records every hour 0 * * * * php /path/to/cleanup-rate-limits.php
<?php // cleanup-rate-limits.php use MonkeysLegion\Mail\RateLimiter\RateLimiter; $results = RateLimiter::cleanupAll('/tmp'); echo "Cleaned up " . $results['cleaned'] . " files\n";
🎨 Template System
Create beautiful, reusable email templates with the ML View engine.
For complete template documentation, see: MonkeysLegion Template Engine
Email Components
The package includes pre-built email components
📝 Logging
Comprehensive logging helps you monitor email delivery and debug issues. Logging behavior is controlled by your application mode in the .env
file.
Configuration
Logging is automatically configured based on your application environment:
# Application Mode (controls logging behavior) APP_ENV=production # production, development, testing # Debug Mode (enables detailed SMTP/DKIM logging) MAIL_DEBUG=false # Set to true for debugging
Log Levels by Environment
Production Mode (APP_ENV=prod
)
- INFO: Successful operations, performance metrics
- WARNING: Rate limits, retry attempts
- ERROR: Failed operations, configuration issues
- CRITICAL: System failures requiring immediate attention
Development Mode (APP_ENV=dev
)
- DEBUG: Detailed SMTP communication, DKIM signing process
- INFO: All successful operations with timing data
- WARNING: Non-critical issues and suggestions
- ERROR: Failed operations with full stack traces
Testing Mode (APP_ENV=test
)
- ERROR: Only failures and critical issues
- INFO: Test-specific events and assertions
Log Examples
// Successful send (Production) [Log TimeStamp] app.INFO Email sent successfully { "to": "user@example.com", "subject": "Welcome", "duration_ms": 1250, "driver": "SmtpTransport" } // DKIM signing (Development) [Log TimeStamp] app.DEBUG DKIM signature generated { "domain": "yourdomain.com", "selector": "default", "signature_length": 344, "headers_signed": ["From", "To", "Subject", "Date", "Message-ID"] } // Queue processing (All modes) [Log TimeStamp] app.INFO Job processed successfully { "job_id": "job_64f8a2b1c3d4e", "duration_ms": 890, "memory_usage_mb": 15.2, "queue": "emails" } // Rate limiting (Production) [Log TimeStamp] app.WARNING Rate limit exceeded { "key": "user_123", "limit": 100, "window": 3600, "remaining_reset_time": 1845 } // SMTP Debug (Development only) [Log TimeStamp] app.DEBUG SMTP command sent { "command": "MAIL FROM:<sender@example.com>", "response_code": 250, "response": "2.1.0 Ok" }
Log File Locations
Logs are stored in different locations based on your environment:
var/log/app.log
Custom Logging
use MonkeysLegion\Mail\Logger\Logger; $logger = ML_CONTAINER->get(Logger::class); // Log custom events $logger->log("Custom email campaign started", [ 'campaign_id' => 'summer2024', 'recipient_count' => 1000, 'estimated_duration' => '5 minutes' ]);
🚀 Advanced Usage
Multiple Drivers
// Switch drivers at runtime $mailer->useSmtp(['host' => 'smtp.mailgun.org']); $mailer->send($to, $subject, $content); $mailer->useSendmail(); $mailer->send($to, $subject, $content); $mailer->useNull(); $mailer->send($to, $subject, $content);
Bulk Email Processing
// Queue multiple emails efficiently $recipients = ['user1@example.com', 'user2@example.com', 'user3@example.com']; foreach ($recipients as $recipient) { $mail = new NewsletterMail($content); $mail->setTo($recipient) ->onQueue('newsletters') ->queue(); } // Process with dedicated worker // php bin/ml-mail.php mail:work newsletters
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository git clone https://github.com/MonkeysCloud/MonkeysLegion-Mail.git # Install dependencies composer install
📄 License
This package is open-sourced software licensed under the MIT license.
🆘 Support
- Documentation: MonkeysLegion Mail Package
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: to add later ...
Made with ❤️ by the MonkeysLegion Team