My solution so far is now this:
I'm using themsaid/laravel-mail-preview to get an .eml file of sent emails. Only in my phpunit.xml I set:
<env name="MAIL_DRIVER" value="preview"/>
I don't fake the Mail facade, so it uses this mail driver only during the test. One hurdle I came across was, to get the .eml in a faked storage. In the config/mailpreview.php is the path to save the file set to storage_path('email-preview'). This is using app('path.storage') and not as I thought Storage::path(''). Running the test would save the preview file permanently to app/storage/email-preview then. So at runtime I set:
Storage::fake('local');
config(['mailpreview.path' => Storage::path('email-previews')]);
For my artisan command test I do accept now an option, which is optional. So for the tests I use the option, for production I use the pipe mechanism. For parsing the mail, I'm using php-mime-mail-parser as already mentioned.
The interesting parts of my artisan command is now:
protected $signature = 'email:parse {--f|file= : .eml file to parse, optional, can also be piped}';
public function handle()
{
$option = $this->option('file');
$parser = new Parser();
$file = $option ?: 'php://stdin';
$parser->setStream(fopen($file, 'r'));
// code
}
And my test is calling the command like this:
$files = Storage::files('email-previews');
$emlfiles = array_filter($files, function($array) {
return preg_match("/.eml$/i", $array);
});
$this->assertCount(1, $emlfiles);
$emlfile = Storage::path('') . array_values($emlfiles)[0];
$this->artisan('email:parse', ['-f' => $emlfile]);
Any ideas to improve this are appreciated, as using the option is just a workaround. I still couldn't figure out how to test the pipe mechanism. e.g. cat mail.eml | php artisan email:parse.