zbateson/mail-mime-parser
PSR-compliant, testable MIME email parser for PHP (RFC 822/2822/5322). A standards-based but forgiving alternative to imap* and Pear for reading and inspecting messages, headers, parts, and attachments. Requires PHP 8.1+.
Installation:
composer require zbateson/mail-mime-parser
Requires PHP 8.1+.
Basic Parsing: Parse a raw email string or file handle:
use ZBateson\MailMimeParser\MailMimeParser;
$parser = new MailMimeParser();
$message = $parser->parse(file_get_contents('email.eml'));
First Use Case: Extract core metadata (subject, sender, body):
echo $message->getSubject();
echo $message->getHeaderValue(\ZBateson\MailMimeParser\Header\HeaderConsts::FROM);
echo $message->getTextContent();
HeaderConsts class for standardized header keysDependency Injection:
// Laravel Service Provider
public function register()
{
$this->app->singleton(MailMimeParser::class, function ($app) {
return new MailMimeParser($app->make(LoggerInterface::class));
});
}
Message Processing Pipeline:
// In a Laravel Job/Command
public function handle()
{
$parser = app(MailMimeParser::class);
$message = $parser->parse($rawEmail);
// Process headers
$this->processHeaders($message);
// Handle attachments
$this->processAttachments($message);
// Extract body
$this->storeContent($message);
}
Attachment Handling:
// Save all attachments
foreach ($message->getAttachmentParts() as $attachment) {
$attachment->saveContent(storage_path("app/attachments/{$attachment->getFileName()}"));
}
Laravel Mail Parsing:
// Parse incoming mail (e.g., from a queue)
$mail = Mail::getRawMessage();
$message = app(MailMimeParser::class)->parse($mail);
PSR-7 Stream Support:
$stream = new GuzzleHttp\Psr7\Stream(fopen('email.eml', 'r'));
$message = $parser->parse($stream);
Custom Header Parsing:
$customHeader = $message->getHeader('X-Custom-Header');
if ($customHeader) {
$value = $customHeader->getValue();
}
Error Handling:
try {
$message = $parser->parse($rawEmail);
} catch (\ZBateson\MailMimeParser\Exception\ParseException $e) {
Log::error("Failed to parse email: " . $e->getMessage());
}
Resource Leaks:
false to parse():
$handle = fopen('email.eml', 'r');
$message = $parser->parse($handle, false); // Won't auto-close
fclose($handle); // Required!
Encoding Issues:
getTextContent() or getHtmlContent() for decoded content. Raw content may contain encoded characters.Attachment Indexing:
getAttachmentPart(0) returns the first attachment (index starts at 0). Use getAttachmentParts() for all attachments.Header Case Sensitivity:
HeaderConsts provides standardized keys (e.g., HeaderConsts::FROM instead of 'From').Multipart Messages:
foreach ($message->getParts() as $part) {
if ($part->isMultipart()) {
$nestedMessage = $parser->parse($part->getContent());
}
}
Enable Logging:
$parser = new MailMimeParser(new Monolog\Logger('mail_parser', [...]));
Inspect Errors:
if ($message->getErrors()) {
foreach ($message->getErrors() as $error) {
Log::debug("Parse error: " . $error->getMessage());
}
}
Validate Headers:
$fromHeader = $message->getHeader(HeaderConsts::FROM);
if (!$fromHeader || $fromHeader->getErrors()) {
// Handle invalid/missing headers
}
Custom Parsers:
IParserService for specialized MIME types:
class CustomParserService implements IParserService {
public function canParse(PartBuilder $partBuilder) { ... }
public function parse(PartBuilder $partBuilder) { ... }
}
Override Default Parsers:
$parser = new MailMimeParser([
'parsers' => [
'custom' => CustomParserService::class,
]
]);
Extending Headers:
AbstractHeader:
class CustomHeader extends AbstractHeader {
public function getCustomValue() { ... }
}
PSR-7 Integration:
MessageInterface:
use ZBateson\MailMimeParser\Message\Message;
use GuzzleHttp\Psr7\Message as Psr7Message;
$psr7Message = new Psr7Message(
$message->getHeaders(),
$message->getBody()
);
PHP 8.1+ Required: Older versions will fail.
Memory Usage: Large attachments may consume significant memory. Stream attachments directly when possible:
$attachment->getContentStream()->rewind();
file_put_contents('large-file.ext', $attachment->getContentStream());
Timezone Handling: Date headers use the system timezone. Override via:
$parser = new MailMimeParser([
'timezone' => 'UTC',
]);
How can I help you explore Laravel packages today?