Magento 2 Laminas邮件“无效的标题值”错误时,电子邮件名称包含德语字符

uemypmqf  于 2023-01-26  发布在  其他
关注(0)|答案(2)|浏览(227)

当我尝试从管理员订单发送邮件时,如果客户名称有特殊的德语/丹麦语字符,电子邮件不会发送。为其他客户发送完美。我发现的错误是Invalid header value
我跟踪错误到文件vendor/laminas/laminas-http/src/Header/HeaderValue.php

/**
     * Assert a header value is valid.
     *
     * @param string $value
     * @throws Exception\RuntimeException For invalid values.
     * @return void
     */
    public static function assertValid($value)
    {
        if (! self::isValid($value)) {
            throw new Exception\InvalidArgumentException('Invalid header value');
        }
    }

此函数是从vendor/laminas/laminas-mail/src/Header/AbstractAddressList.php调用的

public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        $emails   = [];
        $encoding = $this->getEncoding();

        foreach ($this->getAddressList() as $address) {
            $email = $address->getEmail();
            $name  = $address->getName();

            // quote $name if value requires so
            if (! empty($name) && (false !== strpos($name, ',') || false !== strpos($name, ';'))) {
                // FIXME: what if name contains double quote?
                $name = sprintf('"%s"', $name);
            }

            if ($format === HeaderInterface::FORMAT_ENCODED
                && 'ASCII' !== $encoding
            ) {
                if (! empty($name)) {
                    $name = HeaderWrap::mimeEncodeValue($name, $encoding);
                }

                if (preg_match('/^(.+)@([^@]+)$/', $email, $matches)) {
                    $localPart = $matches[1];
                    $hostname  = $this->idnToAscii($matches[2]);
                    $email = sprintf('%s@%s', $localPart, $hostname);
                }
            }

            if (empty($name)) {
                $emails[] = $email;
            } else {
                $emails[] = sprintf('%s <%s>', $name, $email);
            }
        }

        // Ensure the values are valid before sending them.
        if ($format !== HeaderInterface::FORMAT_RAW) {
            foreach ($emails as $email) {
                HeaderValue::assertValid($email);
            }
        }

        return implode(',' . Headers::FOLDING, $emails);
    }

我发现了一个类Magento\Framework\Filter\RemoveAccents,它可以用可用的字符替换特殊字符,但由于function assertValid是final类中的静态函数,而function getFieldValue是抽象类中的函数,所以我无法替换字符。

xriantvc

xriantvc1#

在这些情况下,(当你想修改的文件位于vendor内部,但在vendor/mgento外部时),你最好在堆栈跟踪中寻找另一个地方来进行修改。例如,你可以为\Magento\Framework\Mail\EmailMessage::convertAddressArrayToAddressList创建一个Preference,并在那里擦除数据。或者,你可以更进一步,为\Magento\Framework\Mail\Message::addTo创建一个插件,等等。

ep6jt1vc

ep6jt1vc2#

我按照泰勒的指示返回堆栈跟踪得到了解决方案,让我解释一下。
Laminas\Mail\Header\AbstractAddressList::getFieldValue使用以下代码获取客户名称和电子邮件

foreach ($this->getAddressList() as $address) {
        $email = $address->getEmail();
        $name  = $address->getName();

这里$this->getAddressList()来自

/**
 * Get address list managed by this header
 *
 * @return AddressList
 */
public function getAddressList()
{
    if (null === $this->addressList) {
        $this->setAddressList(new AddressList());
    }
    return $this->addressList;
}

其中$this->addressList被分配给

/**
 * Set address list for this header
 *
 * @param  AddressList $addressList
 */
public function setAddressList(AddressList $addressList)
{
    $this->addressList = $addressList;
}

它使用的是Laminas\Mail\AddressList类。所以

/**
 * Create an address object
 *
 * @param  string $email
 * @param  string|null $name
 * @return Address
 */
protected function createAddress($email, $name)
{
    return new Address($email, $name);
}

是用来设置名字和电子邮件的。这里它创建了Laminas\Mail\Address类的对象。所以在这里,我发现

/**
 * Retrieve name, if any
 *
 * @return null|string
 */
public function getName()
{
    return $this->name;
}

修改这个返回值就是解决我的问题,所以我创建了一个插件。

public function afterGetName(\Laminas\Mail\Address $subject,$result)
{
    $removeAccent = new \Magento\Framework\Filter\RemoveAccents(true);
    return $removeAccent->filter($result);
}

相关问题