monkeyscloud/monkeyslegion-mail

Mail integration package for the MonkeysLegion framework.

Maintainers

Package info

github.com/MonkeysCloud/MonkeysLegion-Mail

pkg:composer/monkeyscloud/monkeyslegion-mail

Statistics

Installs: 1 687

Dependents: 2

Suggesters: 0

Stars: 1

Open Issues: 0


README

A premium, high-performance mail engine for the MonkeysLegion PHP framework. Features PSR-14 events, DKIM signing, rate limiting, and a beautiful fluent API. Our codebase is rigorously tested with 288 unit and integration tests ensuring 82.88% code coverage.

PHP Version License Tests Coverage

🚀 Quick Start: From Zero to "Sent"

1. Installation

Install the package via composer:

composer require monkeyscloud/monkeyslegion-mail:^2.0

Initialize the mail configuration and scaffold resources:

php ml mail:install

2. Configuration

Configure your sending credentials in your .env file. By default, the package uses the Null Driver for safe development.

# Choose your driver (monkeys_mail, smtp, mailgun, sendmail, null)
MAIL_DRIVER=smtp

# SMTP Settings
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=587
MAIL_ENCRYPTION=tls
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password

# Global Identity
MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="Monkeys Legion App"

3. Manual Construction (DI)

If you are not using the full MonkeysLegion framework auto-wiring, here is how to manually construct the Mailer and its dependencies:

use MonkeysLegion\Mail\Mailer;
use MonkeysLegion\Mail\Transport\SmtpTransport;
use MonkeysLegion\Mail\RateLimiter\RateLimiter;

$transport = new SmtpTransport([
    'host' => 'smtp.example.com',
    'port' => 587,
    'username' => 'user',
    'password' => 'secret'
]);

$rateLimiter = new RateLimiter('my_mail_app', 100, 60);

$mailer = new Mailer(
    $transport,
    $rateLimiter,
    $queueDispatcher, // MonkyesLegion-Queue (optional)
    $logger,          // PSR-3 or MonkeysLogger (optional)
    [],               // Raw configuration array for run time driver selection
    $eventDispatcher  // PSR-14 global dispatcher (optional)
);

4. Basic Sending (Direct)

Get the Mailer instance from the container and send an email immediately:

use MonkeysLegion\Mail\Mailer;

// Resolve the mailer
$mailer = $container->get(Mailer::class);

$mailer->send(
    'recipient@example.com',
    'Hello from v2!',
    '<h1>Success!</h1><p>The MonkeysLegion mail engine is operational.</p>',
    'text/html'
);

5. Advanced: Using Mailables

Generate a new Mailable class:

php ml make:mail WelcomeMail

Configure your logic and templates in src/Mail/WelcomeMail.php:

public function build(): self
{
    return $this->view('emails.welcome')
                ->subject('Welcome!')
                ->withData(['name' => $this->user->name]);
}

Then send or queue it fluently:

(new WelcomeMail($user))
    ->setTo('user@example.com')
    ->send(); // or ->queue() for background processing

With Metadata (Mailables)

When using Mailables with metadata-aware transports, set metadata in your build() method:

public function build(): self
{
    return $this->view('emails.welcome')
                ->subject('Welcome!')
                ->withTags(['onboarding', 'transactional'])
                ->withMetadata(['user_id' => $this->user->id, 'source' => 'signup'])
                ->withVariables(['activation_url' => $url, 'name' => $this->user->name])
                ->replyTo('support@example.com');
}

📨 Advanced Email Metadata (MonkeysMailTransport & MailgunTransport)

The MonkeysMailTransport and MailgunTransport support rich email metadata through the SupportsAdvancedMetadata interface. This allows you to send tags, custom metadata, template variables, and reply-to addresses. Metadata is preserved when sending via Mailer or Mailable classes.

Using Metadata in Mailables

(new WelcomeMail($user))
    ->setTo('user@example.com')
    ->withTags(['onboarding', 'transactional'])                          // Categorization tags
    ->withMetadata(['user_id' => $user->id, 'source' => 'signup'])      // Custom key-value data
    ->withVariables(['activation_url' => $url, 'name' => $user->name])  // Template substitutions
    ->replyTo('support@example.com')                                     // Reply-To address
    ->send();

Using Metadata via Mailer (Direct Messages)

use MonkeysLegion\Mail\Message;

$mailer = $container->get(Mailer::class);

$message = new Message('user@example.com', 'Hello!', '<h1>Welcome</h1>');
$message->setTags(['onboarding', 'promotion']);
$message->setMetadata(['campaign_id' => '12345', 'segment' => 'premium']);
$message->setVariables(['first_name' => 'John', 'discount' => '20%']);
$message->setReplyTo('support@example.com');

// Send with metadata preserved
$mailer->sendMessage($message);

// Or queue with metadata preserved
$mailer->queueMessage($message, 'high-priority');

Using Metadata Directly with Message & Transport

$message = new Message('user@example.com', 'Hello!', '<h1>Welcome</h1>');
$message->setTags(['onboarding', 'promotion']);
$message->setMetadata(['campaign_id' => '12345', 'segment' => 'premium']);
$message->setVariables(['first_name' => 'John', 'discount' => '20%']);
$message->setReplyTo('support@example.com');

$transport->send($message);

Metadata Field Details

Field Type Purpose Example
tags array<string> Categorize emails for tracking/analytics ['onboarding', 'transactional', 'marketing']
metadata array<string, mixed> Custom key-value pairs ['user_id' => 123, 'campaign' => 'summer2025']
variables array<string, mixed> Template variable substitutions ['first_name' => 'John', 'code' => 'ABC123']
replyTo ?string Reply-To email address 'support@example.com'

Supported Transports

  • MonkeysMailTransport - Full support for all metadata fields
  • SmtpTransport - Ignores metadata (standard SMTP limitation)
  • SendmailTransport - Ignores metadata
  • MailgunTransport - Supports tags (max 3), variables, metadata (v:metadata JSON), reply-to
  • NullTransport - Ignores metadata

Note: Transports that don't support metadata simply ignore these fields without error. This ensures backward compatibility.

🏗️ Transport Interface: SupportsAdvancedMetadata

To add metadata support to a custom transport, implement the marker interface:

use MonkeysLegion\Mail\TransportInterface;
use MonkeysLegion\Mail\SupportsAdvancedMetadata;

class MyCustomTransport implements TransportInterface, SupportsAdvancedMetadata
{
    public function send(Message $message): void
    {
        // Extract metadata from the message
        $tags = $message->getTags();           // array<string>
        $metadata = $message->getMetadata();   // array<string, mixed>
        $variables = $message->getVariables(); // array<string, mixed>
        $replyTo = $message->getReplyTo();     // ?string
        
        // Use these fields in your API payload or business logic
    }

    public function getName(): string
    {
        return 'my-custom-transport';
    }
}

🔔 Events & Hooks (New in v2)

Listen to successful sends or failures globally via PSR-14, or locally on the instances.

$mailer->onSent(function ($event) {
    echo "Message " . $event->getMessageId() . " sent successfully!";
});

$mailer->onFailed(function ($event) {
    Log::error("Failed to send: " . $event->getException()->getMessage());
});

See the Events Documentation for details on the PSR-14 implementation.

📖 Complete Documentation

Explore each feature in detail:

✨ Why MonkeysLegion Mail?

  • PSR-14 Native: Full event-driven architecture.
  • DKIM Built-in: Modern security standards out-of-the-box.
  • Rate Limited: Protect your reputation and costs automatically.
  • Mobile-First Templates: Optimized for standard email clients.
  • High Performance: Zero-overhead queueing and batching.

🤝 Contributing & Security

We welcome contributions! Please see our CONTRIBUTING.md for guidelines on how to get started.

If you discover a security vulnerability, please review our SECURITY.md for our reporting process.

⚖️ License

Distributed under the MIT License. © 2026 MonkeysCloud Team