Zend Mail has problems with multiple BCC recipients

Reason and Workaround

In a project, we've discovered some strange behavior of Zend\Mail while trying to send a single message to multiple bcc recipients. If addressed multiple bcc (or even cc) recipients, only the first one would get the message delivered by the mail server. It took us quite a long time to figure it out and found a solution.

What Zend\Mail does

Well, to understand what Zend-Mail does in background let's assume a simple Message object, like this:

use Zend\Mail;

$mail = new Mail\Message();
$mail->setFrom('test@example.com', 'Sender\'s name');
$mail->addTo('daniel@example.com', 'Name of recipient');
$mail->setSubject('Test Subject');
$mail->setBody('This is the text of the email.');

$mail->setBcc([
    'bcc_recipient_one@example.com',
    'bcc_recipient_two@example.com',
    'bcc_recipient_three@example.com',
]);

$transport = new Mail\Transport\Sendmail();
$transport->send($mail);

Zend will create a Message object and build the Headers by the provided information. If you would print them by $mail->getHeaders()->toString(), the result would look somehow like this:

Date: Wed, 17 Jan 2018 14:04:14 +0100
From: Sender's Name <test@example.com>
To: daniel@example.com
Subject: Test Subject
Bcc: bcc_recipient_one@example.com,
 bcc_recipient_two@example.com,
 bcc_recipient_three@example.com

The problem is, that each bcc recipient stands in a separate line. This is the reason why our mail servers only addressed the first recipient of the list and ignored all others. We've tested this behavior with a Microsoft Exchange and two Linux servers. Each has ignored the additional recipients.

A Workaround

So, to solve this issue, it's needed to generate a proper mail header by Zend\Mail. The real problem is, that Zend uses an abstract class for the generation of this and there is no way to change the generation of the header while build. It's hard-coded in there, at least until version 2.4.13. The only way (for now) is to create an own header class, used for bcc representation, passed to the Massage object later.

For this, I've created a new Header\Bcc class in my modules src folder and extended it by the original \Zend\Mail\Header\Bcc class. Inside of the Zend\Mail\Header\AbstractAddressList class there is a function, called getFieldValue. This function is used to generate the header value as a string. It would be possible to copy the whole function and change only the wrong part there. But as the function uses the Headers::FOLDING constant to build the header, it's even possibile to use this for remove of the line-breaks from the result. This causes less code and this solution would even work on changes by updates in the future.

namespace MyModule\Header;

use Zend\Mail\Header\Bcc as BccHeader;
use Zend\Mail\Header\HeaderInterface;
use Zend\Mail\Headers;

class Bcc extends BccHeader
{
    /**
     * get compatible bcc header
     * @param bool $format
     * @return string
     */
    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        $value = parent::getFieldValue($format);
        return str_replace(Headers::FOLDING, ' ', $value);
    }
}

The only thing to be changed from now on, is the way the bcc recipients will be added to the Message object. Instead of using setBcc or addBcc functions, your new Bcc class will be used and passed to the headers manually.

$bccHeader = new \MyModule\Header\Bcc();
$bccHeader->getAddressList()->addMany([
    'bcc_recipient_one@example.com',
    'bcc_recipient_two@example.com',
    'bcc_recipient_three@example.com',
]);
$mail->getHeaders()->addHeader($bccHeader);

Once done, the headers will be correct and all recipients will get a copy of the mail. The same thing could be done with cc recipients, which have the same problem by default.

Caution: If you use $mail->setBcc() somewhere later in your project, the Bcc class will be removed from the Headers object and replaced by the original implementation. This causes the problem to stay there as before. Just remove all such function calls and use your own class!

Share:

Einen Kommentar verfassen

Ihre E-Mail-Adresse wird nicht veröffentlicht, sie dient nur der Identifikation! Für die Profilbilder wird Gravatar verwendet und reCAPTCHA, um Spam zu vermeiden.

Kommentare 0

Es sind noch keine Kommentare für diesen Beitrag vorhanden.