magepal / magento2-gmail-smtp-app

Configure Magento 2 to send email using Google App, Gmail, Amazon Simple Email Service (SES), Microsoft Office365 and many other SMTP (Simple Mail Transfer Protocol) servers
https://www.magepal.com
319 stars 148 forks source link

Not working on Magento 2.3.5 #168

Closed apedicdev closed 2 years ago

apedicdev commented 4 years ago

Magento version #:

2.3.5

Edition (EE, CE, OS, etc):

EE

Expected behavior:

when placing orders, email confirmations are sent

Actual behavior:

Fatal Error: 'Cannot declare class Zend_Mail_Transport_Smtp, because the name is already in use'

Steps to reproduce:

Place order via FE or admin

Preconditions

Magento 2.3.5 has Zend Framework replaced by Laminas

srenon commented 4 years ago

@apedicdev ... I'm using the GitHub dev version of 2.3.5 but I'm not able to reproduce any issues. So can you provide more info

image

KarlComSe commented 4 years ago

Getting the same error-message. Worked well with 2.3.4 upgrade yesterday. Not sure yet if it is my installation or a general issue. Magento version #: 2.3.5

Edition (EE, CE, OS, etc): CE on a BITNAMI image, running DEBIAN 9, APACHE.

Expected behavior: emails to be sent through SMTP provider

Actual behavior: On sending test emails through admin: PHP Fatal error: Cannot declare class Zend_Mime_Part, because the name is already in use in /opt/bitnami/apps/magento/htdocs/vendor/magento/zendframework1/library/Zend/Mime/Part.php on line 35', referer: ... On sending contact emails through contact form: PHP Fatal error: Cannot declare class Zend_Mail_Transport_Smtp, because the name is already in use in /opt/bitnami/apps/magento/htdocs/vendor/magento/zendframework1/library/Zend/Mail/Transport/Smtp.php on line 0', referer: ...

Steps to reproduce: Send test email through admin Send contact form email through frontend

srenon commented 4 years ago

@KarlComSe ... what version of our extension are you using?

Can you provide me with the entire error log because our extension does not reference Zend_Mime_Part class

KarlComSe commented 4 years ago

Here you go @srenon

Again, I have not yet confirmed on a clean install, but found the issue reported by @apedicdev's prior to investigating further. It might be so that I haven't managed to properly uninstall a previous, very old, version of the MagePal SMTP extension.

Module manager reports version 2.8.1.

image

apache2/logs/error_log :

[Sat May 02 17:10:48.785681 2020] [proxy_fcgi:error] [pid 19988:tid 139640585479936] [client 127.0.0.1:41316] AH01071: Got error 'PHP message: PHP Fatal error:  Cannot declare class Zend_Mail_Transport_Smtp, because the name is already in use in /opt/bitnami/apps/magento/htdocs/vendor/magento/zendframework1/library/Zend/Mail/Transport/Smtp.php on line 0', referer: http://example.com/contact/
[Sat May 02 17:11:45.803137 2020] [proxy_fcgi:error] [pid 19988:tid 139640652621568] [client 127.0.0.1:41358] AH01071: Got error 'PHP message: PHP Fatal error:  Cannot declare class Zend_Mail_Transport_Smtp, because the name is already in use in /opt/bitnami/apps/magento/htdocs/vendor/magento/zendframework1/library/Zend/Mail/Transport/Smtp.php on line 0', referer: http://example.com/contact/
[Sat May 02 17:12:24.910331 2020] [proxy_fcgi:error] [pid 19988:tid 139640409233152] [client 127.0.0.1:41388] AH01071: Got error 'PHP message: PHP Fatal error:  Cannot declare class Zend_Mail_Transport_Smtp, because the name is already in use in /opt/bitnami/apps/magento/htdocs/vendor/magento/zendframework1/library/Zend/Mail/Transport/Smtp.php on line 0', referer: http://example.com/contact/
[Sat May 02 17:18:55.876469 2020] [proxy_fcgi:error] [pid 19988:tid 139640635836160] [client 127.0.0.1:41544] AH01071: Got error 'PHP message: PHP Fatal error:  Cannot declare class Zend_Mime_Part, because the name is already in use in /opt/bitnami/apps/magento/htdocs/vendor/magento/zendframework1/library/Zend/Mime/Part.php on line 35', referer: http://example.com/admin/admin/system_config/edit/section/system/key/xxxxx

Last line, with reference to Zend_Mime_Part, refers to error when I was testing to send email through admin-panel.

The error Magento admin reports is "A technical problem with the server created an error. Try again to continue what you were doing. If the problem persists, try again later.". Despite this, the email is sent (and received).

KarlComSe commented 4 years ago

I'm not able to reproduce on a clean install. Will redo my upgrade later today, and take more care when removing the old MagePal-module and confirm it is working after that.

apedicdev commented 4 years ago

@apedicdev ... I'm using the GitHub dev version of 2.3.5 but I'm not able to reproduce any issues. So can you provide more info

image

@srenon I'm going to test on a clean install but, given magento 2.3.5 has replaced Zend with Laminas, would not be the case to replace references to those libraries?

srenon commented 4 years ago

@apedicdev ... rename the class will remove backward compatibility of our extension with older versions Magento. Our goal is to remove it once 2.4.0 is released because we will have better control over the composer version number requirements.

if you take a look at https://github.com/magento/magento2/blob/2.3/composer.lock#L2268 you will notice that they are using composer replace which provide backward compatibility for Zend Namespace image

apedicdev commented 4 years ago

Thank Renon. As a workaround I've fixed it overriding the transport plugin so it will instantiate a new SMTP class from Laminas. I think there will be a official fix soon. Mageplaza SMTP has same issue On 4 May 2020, 16:00 +0100, Renon Stewart notifications@github.com, wrote:

@apedicdev ... rename the class will remove backward compatibility of our extension with older versions Magento. Our goal is to remove it once 2.4.0 is released because we will have better control over the composer version number requirements. if you take a look at https://github.com/magento/magento2/blob/2.3/composer.lock#L2268 you will notice that they are using composer replace which provide backward compatibility for Zend Namespace — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

ci2014 commented 4 years ago

@apedicdev Could you please share your workaround? I have the same problem.

srenon commented 4 years ago

@ci2014 ... are you doing a fresh install or upgrade from a previous version?

ci2014 commented 4 years ago

@srenon Upgrade from 2.1

srenon commented 4 years ago

@apedicdev ... All the debugging info posted on this issue seem to be related to issue in Zend Framework 1 and not 2 which was rename to Laminas.

Could you double-check your composer autoload files in vendor/composer by doing a search for zendframework1

See below a screenshot of my dev environment that has zero issues image

srenon commented 4 years ago

@apedicdev ... are you doing a fresh install or upgrade from a previous version?

apedicdev commented 4 years ago

@srenon I'm doing upgrade from magento 2.2.11. will check the composer files as you said @ci2014 cannot share source code but fix looks like: di.xml

<type name="\Magento\Framework\Mail\TransportInterface">
        <plugin sortOrder="100" name="magePalGmailSmtpAppTransportInterface" type="....\...\Plugin\Mail\TransportPlugin"/>
    </type>

TransportPlugin.php

<?php

namespace ....\....\Plugin\Mail;

use Closure;
use Magento\Framework\Exception\MailException;
use Magento\Framework\Mail\Message;
use Magento\Framework\Mail\TransportInterface;
use MagePal\GmailSmtpApp\Model\ZendMailOne\Smtp as ZendMailOneSmtp;
use ....\....\Model\ZendMailTwo\Smtp as ZendMailTwoSmtp;
use Zend_Mail;
use Zend_Mail_Exception;
use \Magento\Framework\Mail\EmailMessageInterface;

class TransportPlugin extends \MagePal\GmailSmtpApp\Plugin\Mail\TransportPlugin
{

    /**
     * @param TransportInterface $subject
     * @param Closure $proceed
     * @throws MailException
     * @throws Zend_Mail_Exception
     */
    public function aroundSendMessage(
        TransportInterface $subject,
        Closure $proceed
    ) {
        if ($this->dataHelper->isActive()) {
            if (method_exists($subject, 'getStoreId')) {
                $this->storeModel->setStoreId($subject->getStoreId());
            }

            $message = $subject->getMessage();

            //ZendMail1 - Magento <= 2.2.7
            //ZendMail2 - Magento >= 2.2.8
            if ($message instanceof Zend_Mail) {
                $smtp = new ZendMailOneSmtp($this->dataHelper, $this->storeModel);
                $smtp->sendSmtpMessage($message);
            } elseif ($message instanceof Message || $message instanceof EmailMessageInterface) {
                $smtp = new ZendMailTwoSmtp($this->dataHelper, $this->storeModel);
                $smtp->sendSmtpMessage($message);
            } else {
                $proceed();
            }
        } else {
            $proceed();
        }
    }
}

\....\....\Model\ZendMailTwo\Smtp.php

<?php

namespace ....\....\Model\ZendMailTwo;

use Exception;
use Magento\Framework\Exception\MailException;
use Magento\Framework\Mail\MessageInterface;
use Magento\Framework\Phrase;
use MagePal\GmailSmtpApp\Helper\Data;
use MagePal\GmailSmtpApp\Model\Store;
use Laminas\Mail\AddressList;
use Laminas\Mail\Message;
use Laminas\Mail\Transport\Smtp as SmtpTransport;
use Laminas\Mail\Transport\SmtpOptions;
use Magento\Framework\Mail\EmailMessageInterface;

/**
 * Class Smtp
 * For Magento > 2.2.7
 */

class Smtp extends \MagePal\GmailSmtpApp\Model\ZendMailTwo\Smtp
{
    /**
     * @param MessageInterface | EmailMessageInterface $message
     * @throws MailException
     */
    public function sendSmtpMessage(
        $message
    ) {
        $dataHelper = $this->dataHelper;
        $dataHelper->setStoreId($this->storeModel->getStoreId());

        $message = $this->convertMessage($message);

        //Set reply-to path
        switch ($dataHelper->getConfigSetReturnPath()) {
            case 1:
                $returnPathEmail = $message->getFrom()->count() ? $message->getFrom() : $this->getFromEmailAddress();
                break;
            case 2:
                $returnPathEmail = $dataHelper->getConfigReturnPathEmail();
                break;
            default:
                $returnPathEmail = null;
                break;
        }

        if (!$message->getReplyTo()->count() && $dataHelper->getConfigSetReplyTo()) {
            if (is_string($returnPathEmail)) {
                $name = $this->getFromName();
                $message->setReplyTo(trim($returnPathEmail), $name);
            } elseif ($returnPathEmail instanceof AddressList) {
                foreach ($returnPathEmail as $address) {
                    $message->setReplyTo($address);
                }
            }
        }

        //Set from address
        switch ($dataHelper->getConfigSetFrom()) {
            case 1:
                $setFromEmail = $message->getFrom()->count() ? $message->getFrom() : $this->getFromEmailAddress();
                break;
            case 2:
                $setFromEmail = $dataHelper->getConfigCustomFromEmail();
                break;
            default:
                $setFromEmail = null;
                break;
        }

        if ($setFromEmail !== null && $dataHelper->getConfigSetFrom()) {
            if (is_string($setFromEmail)) {
                $name = $this->getFromName();
                $message->setFrom(trim($setFromEmail), $name);
                $message->setSender(trim($setFromEmail), $name);
            } elseif ($setFromEmail instanceof AddressList) {
                foreach ($setFromEmail as $address) {
                    $message->setFrom($address);
                    $message->setSender($address);
                }
            }
        }

        if (!$message->getFrom()->count()) {
            $result = $this->storeModel->getFrom();
            $message->setFrom($result['email'], $result['name']);
        }

        //set config
        $options   = new SmtpOptions([
            'name' => $dataHelper->getConfigName(),
            'host' => $dataHelper->getConfigSmtpHost(),
            'port' => $dataHelper->getConfigSmtpPort(),
        ]);

        $connectionConfig = [];

        $auth = strtolower($dataHelper->getConfigAuth());
        if ($auth != 'none') {
            $options->setConnectionClass($auth);

            $connectionConfig = [
                'username' => $dataHelper->getConfigUsername(),
                'password' => $dataHelper->getConfigPassword()
            ];
        }

        $ssl = $dataHelper->getConfigSsl();
        if ($ssl != 'none') {
            $connectionConfig['ssl'] = $ssl;
        }

        if (!empty($connectionConfig)) {
            $options->setConnectionConfig($connectionConfig);
        }

        foreach ($message->getHeaders()->toArray() as $headerKey => $headerValue) {
            $mailHeader = $message->getHeaders()->get($headerKey);
            if ($mailHeader instanceof \Laminas\Mail\Header\HeaderInterface) {
                $this->updateMailHeader($mailHeader);
            } elseif ($mailHeader instanceof \ArrayIterator) {
                foreach ($mailHeader as $header) {
                    $this->updateMailHeader($header);
                }
            }
        }

        try {
            $transport = new SmtpTransport();
            $transport->setOptions($options);
            $transport->send($message);
        } catch (Exception $e) {
            throw new MailException(
                new Phrase($e->getMessage()),
                $e
            );
        }
    }

    /**
     * @param $header
     */
    public function updateMailHeader($header)
    {
        if ($header instanceof \Laminas\Mail\Header\HeaderInterface) {
            if (\Laminas\Mime\Mime::isPrintable($header->getFieldValue())) {
                $header->setEncoding('ASCII');
            } else {
                $header->setEncoding('utf-8');
            }
        }
    }
}

I basically override TransportPlugin so it can instantiate a custom ZendMailTwo\Smtp class which has Laminas references.

srenon commented 4 years ago

This seems to only affect users who are upgrading to Magento 2.3.5 and more than likely there is a duplicate entry in composer that causing the error.

Please make sure to follow Magento's update guide https://devdocs.magento.com/guides/v2.3/comp-mgr/cli/upgrade-with-script.html

ci2014 commented 4 years ago

@srenon I followed the guide very precisely and compared the composer.json to the version on GitHub. Unfortunately, I can not find relevant differences.

apedicdev commented 4 years ago

I think @srenon is right, must be something with composer when upgrading to magento 2.3.5. I actually just remembered I first upgraded to 2.3.4 and then 2.3.5 and then got the problem. That would also explain others smtp plugins having same issue

ci2014 commented 4 years ago

@apedicdev @srenon I really couldn't find the issue. I deleted the whole vendor/* folder. Now it's working. For everyone reading this, please be careful when trying the same.

JosephMaxwell commented 4 years ago

This is definitely really strange. I tried what @ci2014 recommended with cleaning out the vendor/ and (for good measure) composer.lock files—no luck.

But, I did have success with a quick Git patch:


From 1b1a6eea8b2426335c2c1b662e9c36a257cf92e1 Mon Sep 17 00:00:00 2001
Date: Fri, 8 May 2020 16:24:51 -0500
Subject: [PATCH] Switching to Laminas

---
 Smtp.php | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Model/ZendMailTwo/Smtp.php b/Model/ZendMailTwo/Smtp.php
index eb285bf..82f3efd 100644
--- a/Model/ZendMailTwo/Smtp.php
+++ b/Model/ZendMailTwo/Smtp.php
@@ -13,10 +13,10 @@ use Magento\Framework\Mail\MessageInterface;
 use Magento\Framework\Phrase;
 use MagePal\GmailSmtpApp\Helper\Data;
 use MagePal\GmailSmtpApp\Model\Store;
-use Zend\Mail\AddressList;
-use Zend\Mail\Message;
-use Zend\Mail\Transport\Smtp as SmtpTransport;
-use Zend\Mail\Transport\SmtpOptions;
+use Laminas\Mail\AddressList;
+use Laminas\Mail\Message;
+use Laminas\Mail\Transport\Smtp as SmtpTransport;
+use Laminas\Mail\Transport\SmtpOptions;
 use Magento\Framework\Mail\EmailMessageInterface;

 /**
-- 

In composer.json add:

    "extra": {
        "magento-force": "override",
        "composer-exit-on-patch-failure": true,
        "patches": {
            "magepal/magento2-gmailsmtpapp": {
                "Fixing laminas problem": "patches/composer/magepal-fix.patch"
            }
        }
    }

BTW, thanks @srenon for the great module. We use it all over the place.

munkhulzii commented 4 years ago

I got an error when I click "Send test email" button in admin configuration.

PHP Fatal error: Cannot declare class Zend_Mime_Part, because the name is already in use in vendor/magento/zendframework1/library/Zend/Mime/Part.php on line 35

munkhulzii commented 4 years ago

@JosephMaxwell I have added your patch. The backend test function works now. But the error is still there if I do a new registration. PHP Fatal error: Cannot declare class Zend_Mail_Transport_Smtp, because the name is already in use in vendor/magento/zendframework1/library/Zend/Mail/Transport/Smtp.php on line 243

bakennguyen commented 4 years ago

It seems to be a bug when ZF1 classes are used instead of Laminas classes since the autoload path is the same, composer autoload will return the wrong ZF1 class instead.

https://magento.stackexchange.com/questions/312482/magento2-3-5-p1-fatal-error-cannot-declare-class-zend-http-client-because-t

vmalyk commented 4 years ago

Hi!

@apedicdev, @JosephMaxwell , @munkhulzii, @srenon

I got the same issues, but after checking autoloader and composer.json for 2.3.5-p1(and all 2.3.x versions) I found diff in composer.json. If you have: "config": { "use-include-path": true },

Remove it, deleted the whole vendor/* folder and run composer install - issue should be fixed. This option was present in Magento 2.1.x and was removed on 2.2-2.3.

Thnx!

fkruidhof commented 4 years ago

The method suggested by @vmalyk worked for me.

bakennguyen commented 4 years ago

@vmalyk fixed the issue for me too!

VinsensiusNiko commented 4 years ago

@vmalyk fixed the issue in magento 2.3.5. thanks.

shigawaka commented 4 years ago

@vmalyk this fixed the issue in magento 2.3.5 p2

ci2014 commented 3 years ago

@vmalyk works with 2.3.6

platonische commented 2 years ago

@vmalyk works to 2.3.7