magento2: Magento 2.2.4 not sending from sales sender

Preconditions

  1. Magento 2.2.4
  2. PhP 7.1
  3. Apache

Steps to reproduce

  1. Set general store email addresses
  2. Set store specific email senders in Sales Emails
  3. Send order/shipment/creditnota/invoice mail to customer

Expected result

Email is sent from store email address

Actual result

It sends from the mail server default mailadress

Why

In vendor \magento\module-sales\Model\Order\Email\SenderBuilder.php the configureEmailTemplate() function as been changed.

You can see that $this->transportBuilder->setFrom($this->identityContainer->getEmailIdentity()); has been changed to

        $this->transportBuilderByStore->setFromByStore(
            $this->identityContainer->getEmailIdentity(),
            $this->identityContainer->getStore()->getId()
        );

With further inspection it on first glance it returns the same result .

Eventually the from gets formatted within the _formatAddress function within Zend/Mail.php and used within the same class at setFrom function which has $this->_storeHeader('From', $this->_formatAddress($email, $name), true);

The ‘From’ header can have something like Test Mail test@mail.com or just test@mail.com. But the function itself returns just Test Mail with no email.

And that is because the sprintf function appearently seems to have issues with <> signs. Note sure why.

So i changed

            $encodedName = $this->_encodeHeader($name);
            if ($encodedName === $name  &&  strcspn($name, '()<>[]:;@\\,.') != strlen($name)) {
                $format = '"%s" <%s>';
            } else {
                $format = '%s <%s>';
            }
            return sprintf($format, $encodedName, $email);

to

            $encodedName = $this->_encodeHeader($name);
            if ($encodedName === $name  &&  strcspn($name, '()<>[]:;@\\,.') != strlen($name)) {
                $format = '"%1$s" %3$s%2$s%4$s';
            } else {
                $format = '%1$s %3$s%2$s%4$s';
            }
            return sprintf($format, $encodedName, $email , '<' , '>');

and now it does return Test Mail test@mail.com. So that is fixed;

And now i am stuck.

this->transportBuilder->setFrom($this->identityContainer->getEmailIdentity());

–>sends what i need.

      $this->transportBuilderByStore->setFromByStore(
            $this->identityContainer->getEmailIdentity(),
            $this->identityContainer->getStore()->getId()
        );

–>sends from my SMTP servers default emailaddress.

It seems like the headers are reset somewhere.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 2
  • Comments: 19 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I will keep my solution in place. On update i hope Magento found a way to remove all the bugs with this but for those who run into this problem i can comfirm that this solution is working great on a live website with multistore.

i also do not get why transportBuilderByStore as been created. I see this just as bad coding tbh. We are back to creating new classes for simple adjustments.

Fix: vendor/magento/module-sales/Model/Order/Email/SenderBuilder.php

replace

        $this->transportBuilderByStore->setFromByStore(
            $this->identityContainer->getEmailIdentity(),
            $this->identityContainer->getStore()->getId()
        );

with

$this->transportBuilder->setFrom($this->identityContainer->getEmailIdentity(), $this->identityContainer->getStore()->getId()); vendor/magento/framework/Mail/Template/TransportBuilder.php replace

    /**
     * Set mail from address
     *
     * @param string|array $from
     * @return $this
     */
    public function setFrom($from)
    {
        $result = $this->_senderResolver->resolve($from);
        $this->message->setFrom($result['email'], $result['name']);
        return $this;
    }

with

    /**
     * Set mail from address
     *
     * @param string|array $from
     * @return $this
     */
    public function setFrom($from, $store = null)
    {
        $result = $this->_senderResolver->resolve($from, $store);
        $this->message->setFrom($result['email'], $result['name']);
        return $this;
    }

and just like that we do not need the TransportBuilderByStore anymore and it works as expected.

Hi @CompactCodeEU, Releases in 2.3.x and 2.2.x lines are going together, so this fix should be included in upcoming 2.3.1 and 2.2.9 releases, as @magento-engcom-team said

@magento-engcom-team You already said that this would be fixed in 2.3. I do not think that there is an upcoming 2.2.9 release anymore. That version has already been released. Do you mean there is a patch for 2.2.9? We still changed it in 2.3.0 though for our customers since the fix was not implemented.

@versdivers Your comment above should have been the right solution in my opinion. But was turned down on review as it meant making a change to a class marked as an API.

Instead we have the bodged solution that is currently in place, which still has bugs, e.g you can no longer send multiple emails at the same time, only the first will succeed, the rest will exception and fail.

@versdivers this issue same as #16231. The bug cause by amazon payment module. It disable Magento\Framework\Mail\MessageInterface as singleton object. And the make TransportBuilderByStore create a new MessageInterface which different from the on create by TransportBuilder. open this file vendor/amzn/amazon-pay-and-login-magento-2-module/src/Payment/etc/di.xml find this line #63 <type name="Magento\Framework\Mail\MessageInterface" shared="false" /> remove the shared string <type name="Magento\Framework\Mail\MessageInterface" /> save it. after that, remove generated data and compile the di again. this should fix the bug.