Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mail Mime Parser Laravel Package

zbateson/mail-mime-parser

PSR-compliant, testable MIME email parser for PHP 8.1+ as an alternative to imap* and PEAR. Parses RFC 822/2822/5322 messages from strings, resources, or PSR-7 streams; standards-compliant yet forgiving, with a cleaned-up 4.x API.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require zbateson/mail-mime-parser
    

    Requires PHP 8.1+.

  2. Basic Parsing Parse a raw email string or file:

    use ZBateson\MailMimeParser\Message;
    
    $rawEmail = file_get_contents('email.eml');
    $message = Message::from($rawEmail);
    
  3. Access Key Data

    echo $message->getSubject(); // Subject line
    echo $message->getHeaderValue('From'); // Sender email
    echo $message->getTextContent(); // Plaintext body
    

First Use Case

Process incoming emails in a Laravel queue job:

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\Job;
use ZBateson\MailMimeParser\Message;

class ProcessEmailJob implements ShouldQueue
{
    use Queueable, SerializesModels;

    public function handle(Job $job, string $rawEmail)
    {
        $message = Message::from($rawEmail);

        // Extract and process data
        $subject = $message->getSubject();
        $attachments = $message->getAttachments();

        // Save to database or trigger actions
    }
}

Implementation Patterns

Core Workflows

1. Parsing Emails from Different Sources

// From a file
$message = Message::from('path/to/email.eml');

// From a stream (e.g., HTTP request body)
$stream = fopen('php://temp', 'r+');
fwrite($stream, $rawEmailData);
rewind($stream);
$message = $messageParser->parse($stream, true); // Auto-closes stream

// From a PSR-7 request (Laravel HTTP requests)
$message = Message::from($request->getContent());

2. Extracting Structured Data

// Headers
$from = $message->getHeader('From')->getAddresses()[0]->getEmail();
$to = $message->getHeader('To')->getAddresses();

// Body content
$textBody = $message->getTextContent();
$htmlBody = $message->getHtmlContent();

// Attachments
foreach ($message->getAttachments() as $attachment) {
    $content = $attachment->getContent();
    $filename = $attachment->getHeaderValue('Content-Disposition') ?? 'attachment.bin';
    $attachment->saveContent(storage_path("app/attachments/{$filename}"));
}

3. Handling Multipart Emails

// Check if multipart
if ($message->isMultipart()) {
    foreach ($message->getParts() as $part) {
        if ($part->isText()) {
            echo $part->getTextContent();
        } elseif ($part->isAttachment()) {
            $part->saveContent(storage_path("app/attachments/{$part->getFilename()}"));
        }
    }
}

4. Integration with Laravel Mail

Parse incoming emails (e.g., from a mail server or API):

use Illuminate\Support\Facades\Http;

$response = Http::get('https://api.example.com/emails/latest');
$rawEmail = $response->body();
$message = Message::from($rawEmail);

// Process and store
Email::create([
    'subject' => $message->getSubject(),
    'body' => $message->getTextContent(),
    // ...
]);

Generate outgoing emails with attachments:

use ZBateson\MailMimeParser\MessageBuilder;

$builder = new MessageBuilder();
$builder->from('sender@example.com')
        ->to('recipient@example.com')
        ->subject('Hello')
        ->text('Plaintext body');

$attachment = $builder->createAttachment(
    file_get_contents('document.pdf'),
    'document.pdf',
    'application/pdf'
);
$builder->embed($attachment);

$rawEmail = $builder->getMessage()->toString();
Mail::raw($rawEmail)->send();

Laravel-Specific Patterns

1. Service Provider Integration

Register the parser as a singleton in AppServiceProvider:

public function register()
{
    $this->app->singleton(MailMimeParser::class, function ($app) {
        return new MailMimeParser();
    });
}

2. Middleware for Parsing Incoming Requests

Create middleware to parse raw email payloads:

namespace App\Http\Middleware;

use Closure;
use ZBateson\MailMimeParser\Message;

class ParseEmailMiddleware
{
    public function handle($request, Closure $next)
    {
        if ($request->is('api/emails')) {
            $request->merge([
                'parsed_email' => Message::from($request->getContent())
            ]);
        }
        return $next($request);
    }
}

3. Artisan Command for Processing Emails

namespace App\Console\Commands;

use Illuminate\Console\Command;
use ZBateson\MailMimeParser\Message;
use Illuminate\Support\Facades\Storage;

class ProcessEmailsCommand extends Command
{
    protected $signature = 'emails:process {directory}';
    protected $description = 'Process emails in a directory';

    public function handle()
    {
        foreach (Storage::files($this->argument('directory')) as $file) {
            $message = Message::from(Storage::get($file));
            // Process and store
        }
    }
}

4. Event Listeners for Email Processing

namespace App\Listeners;

use ZBateson\MailMimeParser\Message;
use App\Events\EmailReceived;

class ProcessIncomingEmail
{
    public function handle(EmailReceived $event)
    {
        $message = Message::from($event->rawEmail);
        // Extract and store data
    }
}

Gotchas and Tips

Pitfalls

1. Resource Handling

  • Issue: Forgetting to close file handles passed to parse() when using streams.
  • Fix: Pass true as the second argument to auto-close:
    $handle = fopen('email.eml', 'r');
    $message = $mailParser->parse($handle, true); // Auto-closes
    

2. Encoding Issues

  • Issue: Non-ASCII characters in headers or bodies may not render correctly.
  • Fix: Use getHeaderValue() or getTextContent() with proper encoding:
    $subject = mb_convert_encoding(
        $message->getSubject(),
        'UTF-8',
        'auto'
    );
    

3. Multipart Edge Cases

  • Issue: Complex multipart emails (e.g., nested related types) may not parse as expected.
  • Fix: Use getParts() and recursively check each part:
    $this->parsePart($message);
    private function parsePart($part) {
        if ($part->isMultipart()) {
            foreach ($part->getParts() as $subPart) {
                $this->parsePart($subPart);
            }
        }
    }
    

4. Memory Usage

  • Issue: Large attachments or emails can consume significant memory.
  • Fix: Stream attachments directly to storage:
    $attachment = $message->getAttachmentPart(0);
    $attachment->saveContent(storage_path('app/attachments/large_file.bin'));
    

5. Header Parsing Quirks

  • Issue: Custom headers (e.g., X-*) may not parse as expected.
  • Fix: Use getHeader() and handle manually:
    $customHeader = $message->getHeader('X-Custom-Header');
    if ($customHeader) {
        $value = $customHeader->getValue();
    }
    

Debugging Tips

1. Enable Logging

Pass a Psr\Log\LoggerInterface to the parser:

use Psr\Log\LoggerInterface;

$logger = \Log::getMonolog();
$parser = new MailMimeParser($logger);

2. Inspect Raw Headers

Dump raw headers for debugging:

$rawHeaders = $message->getRawHeaders();
dump($rawHeaders);

3. Validate Email Structure

Check for parsing errors:

if ($message->hasErrors()) {
    foreach ($message->getErrors() as $error) {
        \Log::error($error);
    }
}

4. Handle Undefined Headers Gracefully

$header = $message->getHeader('Non-Existent-Header');
if (!$header) {
    // Fallback logic
}

Extension Points

1. Custom Parsers

Extend ZBateson\MailMimeParser\Parser\AbstractParserService to handle custom MIME types:

namespace App\Services;

use ZBateson\MailMimeParser\Parser\AbstractParserService;
use ZBateson\MailMimeParser\Part\PartBuilder;

class CustomParserService extends AbstractParserService
{
    public function canParse(PartBuilder $part): bool
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport