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 Parser Laravel Package

opcodesio/mail-parser

Simple, fast PHP 8+ email/MIME parser with a clean API—no mailparse extension required. Parse .eml strings/files, read headers (From/To/Subject/Date/size), and extract HTML/text bodies, parts, and attachments.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Installation: Add the package via Composer:
    composer require opcodesio/mail-parser
    
  2. First use case: Parse an email from a string or file:
    use Opcodes\MailParser\Message;
    
    // Parse from string
    $message = Message::fromString($rawEmailString);
    
    // Parse from file
    $message = Message::fromFile(storage_path('emails/example.eml'));
    
  3. Key methods to explore:
    • $message->getHeaders(): Retrieve all headers.
    • $message->getHtmlPart(): Extract HTML content.
    • $message->getAttachments(): List attachments.
  4. Laravel integration: No service provider or facade is required—use the package directly in controllers, commands, or jobs.

Implementation Patterns

1. Parsing Inbound Emails

  • Use case: Process emails received via webhooks (e.g., Mailgun, SendGrid) or uploaded by users.
  • Workflow:
    public function handleUpload(Request $request)
    {
        $rawEmail = $request->file('email')->get();
        $message = Message::fromString($rawEmail);
    
        // Extract structured data
        $data = [
            'subject' => $message->getSubject(),
            'from' => $message->getFrom(),
            'to' => $message->getTo(),
            'body_html' => $message->getHtmlPart()->getContent(),
            'attachments' => collect($message->getAttachments())
                ->map(fn($part) => [
                    'name' => $part->getFilename(),
                    'size' => $part->getSize(),
                ]),
        ];
    
        // Store or process further
        Email::create($data);
    }
    

2. Batch Processing

  • Use case: Parse multiple .eml files from a directory (e.g., for archiving or analysis).
  • Workflow:
    $files = Storage::disk('emails')->files('inbox/');
    foreach ($files as $file) {
        $message = Message::fromFile($file);
        processEmail($message); // Custom logic
        Storage::disk('emails')->move($file, "processed/{$message->getMessageId()}");
    }
    

3. Extracting Attachments

  • Use case: Save attachments to disk or forward them via another service.
  • Workflow:
    foreach ($message->getAttachments() as $attachment) {
        $path = storage_path("attachments/{$attachment->getFilename()}");
        file_put_contents($path, $attachment->getContent());
    
        // Optional: Log metadata
        logger()->info("Saved attachment", [
            'filename' => $attachment->getFilename(),
            'size' => $attachment->getSize(),
        ]);
    }
    

4. Laravel Job Integration

  • Use case: Parse emails asynchronously (e.g., for long-running tasks like virus scanning).
  • Workflow:
    use Opcodes\MailParser\Message;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    
    class ParseEmailJob implements ShouldQueue
    {
        use Queueable;
    
        public function handle()
        {
            $message = Message::fromString($this->rawEmail);
            // Process and store results
        }
    }
    

5. Custom Message Handling

  • Use case: Extend the Message class to add domain-specific logic.
  • Workflow:
    class CustomEmailMessage extends Message
    {
        public function isSupportTicket()
        {
            return str_contains($this->getSubject(), ['support', 'help']);
        }
    
        public function getSupportCategory()
        {
            // Custom logic to categorize tickets
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Nested Multipart Messages:

    • The package handles nested parts (fixed in v0.2.3), but deeply nested structures may still cause issues. Test with complex .eml files.
    • Debug tip: Use $message->getParts() recursively to inspect structure.
  2. Header Encoding:

    • Non-UTF-8 headers (e.g., iso-8859-1) may appear garbled. Use $message->getRawHeaders() to inspect raw values if needed.
  3. Boundary Delimiters:

    • Malformed boundaries in multipart emails can break parsing. Validate input emails with tools like MailTester.
  4. Large Attachments:

    • The package loads entire email content into memory. For very large files, stream processing (e.g., fopen) may be needed.
  5. RFC Compliance:

    • The package is not fully RFC 5322 compliant. Edge cases (e.g., quoted-printable encoded headers) may fail silently.

Debugging Tips

  • Log Raw Input: If parsing fails, log the raw email string to identify issues:
    logger()->debug('Raw email:', ['content' => $rawEmail]);
    
  • Inspect Parts: Use dd($message->getParts()) to debug multipart structures.
  • Check Headers: Verify critical headers manually:
    $contentType = $message->getHeader('Content-Type');
    logger()->debug('Content-Type:', [$contentType]);
    

Performance Tips

  • Reuse Parser Instances: Avoid instantiating Message repeatedly in loops.
  • Lazy Loading: For large emails, extract only needed parts (e.g., $message->getHtmlPart()) instead of loading all parts.

Extension Points

  1. Custom Message Classes: Extend Opcodes\MailParser\Message to add domain-specific methods:

    class AppEmail extends Message
    {
        public function getSenderDomain()
        {
            return explode('@', $this->getFrom())[1];
        }
    }
    
  2. Override Parsing Logic: Extend the parser to handle custom content types:

    class CustomParser extends \Opcodes\MailParser\Parser
    {
        protected function parseContent($content, $contentType)
        {
            if (str_contains($contentType, 'application/vnd.ms-outlook')) {
                return $this->handleOutlookSpecific($content);
            }
            return parent::parseContent($content, $contentType);
        }
    }
    
  3. Laravel Macros: Add helper methods to the Message class using Laravel’s macroable support:

    \Opcodes\MailParser\Message::macro('isSpam', function () {
        return str_contains(strtolower($this->getSubject()), ['free', 'win']);
    });
    

Testing Strategies

  • Test Fixtures: Use real-world .eml files (including edge cases like empty attachments, malformed boundaries).
  • Assertions:
    $message = Message::fromString($rawEmail);
    $this->assertEquals('Test Subject', $message->getSubject());
    $this->assertCount(1, $message->getAttachments());
    
  • Mocking: For unit tests, mock the Message class to return predictable data:
    $mockMessage = Mockery::mock(Message::class);
    $mockMessage->shouldReceive('getSubject')->andReturn('Mock Subject');
    
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.
symfony/ai-symfony-mate-extension
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata