Search code examples
phputf-8zend-framework2imaprfc2822

Invalid header value detected: imap mail reception with header having utf-8 french accents


I'm working on a project with Zend Framework 2.4.13, and I have to retrieve mails from an imap mailbox. For this purpose I use \Zend\Mail\Storage\Imap:

foreach ($this->imap as $index => $message) {
    // ...
}

It's working well, except for a particular mail which fails to parse. The From header is invalid because it contains raw UTF-8 characters (french accents):

From: "Stéph" <[email protected]>

Then I get the following Zend error:

An error occurred during execution; please try again later.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Informations complémentaires:

Zend\Mail\Header\Exception\InvalidArgumentException

Fichier:

    /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Header/GenericHeader.php:61

Message:

    Invalid header value detected

Pile d'exécution:

    #0 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Header/GenericHeader.php(35): Zend\Mail\Header\GenericHeader::splitHeaderLine('From: "St\xC3\xA9ph" ...')
    #1 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Headers.php(230): Zend\Mail\Header\GenericHeader::fromString('From: "St\xC3\xA9ph" ...')
    #2 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Headers.php(95): Zend\Mail\Headers->addHeaderLine('From: "St\xC3\xA9ph" ...')
    #3 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mime/Decode.php(141): Zend\Mail\Headers::fromString('MIME-Version: 1...', '\n')
    #4 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Storage/Part.php(106): Zend\Mime\Decode::splitMessage('MIME-Version: 1...', 'MIME-Version: 1...', '')
    #5 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Storage/Message.php(54): Zend\Mail\Storage\Part->__construct(Array)
    #6 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Storage/Imap.php(118): Zend\Mail\Storage\Message->__construct(Array)
    #7 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mail/Storage/AbstractStorage.php(267): Zend\Mail\Storage\Imap->getMessage(1)
    #8 /var/www/project/module/Application/src/Application/Helpers/LeadParser/Mail/Inbox.php(52): Zend\Mail\Storage\AbstractStorage->current()
    #9 /var/www/project/module/Application/src/Application/Helpers/LeadParser/InboxProcessor.php(81): Application\Helpers\LeadParser\Mail\Inbox->getMails()
    #10 /var/www/project/module/Application/src/WebService/Controller/LeadParserController.php(52): Application\Helpers\LeadParser\InboxProcessor->process()
    #11 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php(82): WebService\Controller\LeadParserController->indexAction()
    #12 [internal function]: Zend\Mvc\Controller\AbstractActionController->onDispatch(Object(Zend\Mvc\MvcEvent))
    #13 /var/www/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(444): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
    #14 /var/www/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(205): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #15 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php(118): Zend\EventManager\EventManager->trigger('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #16 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mvc/DispatchListener.php(93): Zend\Mvc\Controller\AbstractController->dispatch(Object(Zend\Http\PhpEnvironment\Request), Object(Zend\Http\PhpEnvironment\Response))
    #17 [internal function]: Zend\Mvc\DispatchListener->onDispatch(Object(Zend\Mvc\MvcEvent))
    #18 /var/www/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(444): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
    #19 /var/www/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(205): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #20 /var/www/project/vendor/zendframework/zendframework/library/Zend/Mvc/Application.php(314): Zend\EventManager\EventManager->trigger('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #21 /var/www/project/public/index.php(69): Zend\Mvc\Application->run()
    #22 {main}

I guess the problems deals about RFC. Accordingly to the RFC-2822 this header is not valid because of the UTF-8 characters, and Zend complains about it when the header is validated.

I saw many issues around this on the web, but most of them talk about email creation, not reception.

I also saw the RFC-6532 which deals about Internationalized Email Headers, but the mail doesn't seem to respect this standard (there is no message/global part).

Actual workaround

The only solution I found for the moment is to use barbushin/php-imap, a wrapper around native php imap functions. This package seems to be more tolerant/updated, and retrieves the mail correctly.

Question

I need to find a solution to make the mail reception process more tolerant, in order to accept such mail headers. But I'm not convinced with my workaround, which adds vendor dependencies for something already implemented in the framework.

Is it possible to solve this issue directly via the ZF2 framework?


Solution

  • Although RFC 6532 isn't strictly relevant to the problem, implementing reading support for it in ZF2 is probably the simplest way to solve your problem.

    This is because 6532 extends the message format to support addresses such as sté[email protected], and it does so in a way that resembles common behaviour up through the years. People do a lot of inappropriate just-send-8, and the authors of 6532 chose to match the most common type of observed user behaviour. The message you want to read uses just the kind of inappropriate just-send-8 that 6532 codifies and allows.

    Adding support for reading 6532-compliant messages should be as simple as editing various syntax checks and letting through more code points. I have some test messages on github; if ZF2 can parse those you'll be able to read and act on the EAI messages real users send.

    Acting on messages sent by mailer-daemon requires 6533 support as well, and replying may require more 6532-relevant work. That bit is complex. But reading mail is a useful ability in itself.