laminas / laminas-mail

Provides generalized functionality to compose and send both text and MIME-compliant multipart e-mail messages
https://docs.laminas.dev/laminas-mail/
BSD 3-Clause "New" or "Revised" License
95 stars 64 forks source link

message cloning and headers #28

Open weierophinney opened 4 years ago

weierophinney commented 4 years ago

I have a service that has an injected default message. It has some default fields, such as encoding, from_name, from which are equal for any mail sent.

Internally it will create a clone from the default message and then it will add the actual rendered content, to subject. etc. It also adds Content-Type and an X-Header.

However at some point I noticed messages were having duplicate Content-Type and X-Header headers and some servers will deny those messages. Every time a message is sent and additional header is added. (this is a long running process)

Code to reproduce the issue

        $defaultMessage = new \Zend\Mail\Message();
        $defaultMessage->setFrom('its@me.com');

        $message1 = clone $defaultMessage;
        $message1->getHeaders()->addHeaderLine('X-Something', 1);

        $message2 = clone $defaultMessage;
        $message2->getHeaders()->addHeaderLine('X-Something', 2);

        print $message1->toString();
        print $message2->toString();

Expected results

Headers should be unique due to the clone of the default message

Date: Thu, 14 Jun 2018 08:53:20 +0000
From: its@me.com
X-Something: 1

Date: Thu, 14 Jun 2018 08:53:20 +0000
From: its@me.com
X-Something: 2

Actual results

Date: Thu, 14 Jun 2018 08:53:20 +0000
From: its@me.com
X-Something: 1
X-Something: 2

Date: Thu, 14 Jun 2018 08:53:20 +0000
From: its@me.com
X-Something: 1
X-Something: 2

I'm aware normally one should create a new Message for each Message you attempt to sent. I have changed my code to do this, but I still think this should simply work. I'm wondering why clone doesn't really clone...


Originally posted by @basz at https://github.com/zendframework/zend-mail/issues/214

weierophinney commented 4 years ago

ps. I'm on php72 and am using 2.10.0 of zend-mail (2.9 also had this)


Originally posted by @basz at https://github.com/zendframework/zend-mail/issues/214#issuecomment-397224117

weierophinney commented 4 years ago

i've added in my project wrapper which implements __clone:

https://github.com/eventum/eventum/blob/v3.5.1/src/Mail/MailMessage.php#L651-L659

however it still doesn't work, so more deeper __clone() methods needed: https://github.com/eventum/eventum/pull/364

probably need deeper clone in AddressList type headers, which have the address values as objects.

however, doing it properly would mean add __clone() in all objects themselves, not doing top level cloning.


Originally posted by @glensc at https://github.com/zendframework/zend-mail/issues/214#issuecomment-397240156

weierophinney commented 4 years ago

I am under the impression that if you do not specify a __clone method a deep clone was performed by default?


Originally posted by @basz at https://github.com/zendframework/zend-mail/issues/214#issuecomment-397240669

weierophinney commented 4 years ago

rather opposite:

http://php.net/manual/en/language.oop5.cloning.php

When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. Any properties that are references to other variables will remain references.

and as objects are always references in php5+, the result is that cloned subobjects remain shared.


Originally posted by @glensc at https://github.com/zendframework/zend-mail/issues/214#issuecomment-397312781