Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to send invoice email after upgrade from 2.2.10 to latest 2.3.5 #98

Open
pawelmie opened this issue May 8, 2020 · 2 comments
Open

Comments

@pawelmie
Copy link

pawelmie commented May 8, 2020

Hey,
we recently upgraded store from 2.2.10 to 2.3.5-p1 and after that an error appears when trying to send invoice.

Fatal error: Uncaught Error: Call to a member function createAttachments() on null in /var/www/html/store/vendor/eadesignro/module-opicmsppdfgenerator/Model/Email/TransportBuilder.php:16

we use eadesignro/module-opicmsppdfgenerator v2.2.22

@thisisandrew
Copy link

thisisandrew commented Nov 26, 2020

You can get some success by following the approach here - https://meetanshi.com/blog/add-attachments-with-email-in-magento-2-3-x/

Apply the part about Method to Add Attachments with Email in Magento 2.3.3: - Confirmed this works with Magento 2.3.5-p1
In essence you only need update the TransportBuiler to match this article and update the checkInvoice methos of the SenderBuilder to call $this->transportBuilder->addAttachment($pdfFileData['filestream'], $pdfFileData['filename'] . $date . '.pdf', 'application/pdf');
Remove the reference for the Model\Email\Message for the di.xml - not needed and Magento deprecated that interface.

I've applied this as a patch and since this module seems inactive I'm not going to PR it.

So just here to help in case you get stuck hoping this module will do what you hoped it would.

Using latest 1.2.10 of this module

PATCH File

--- module-pdfgenerator/Model/Email/SenderBuilder.php	2020-04-16 12:38:25.000000000 +0100
+++ module-pdfgenerator.PATCHED/Model/Email/SenderBuilder.php	2020-11-26 15:22:05.000000000 +0000
@@ -112,10 +112,7 @@
 
             $date = $this->dateTime->date('Y-m-d_H-i-s');
 
-            $this->transportBuilder->addAttachment(
-                $pdfFileData['filestream'],
-                $pdfFileData['filename'] . $date . '.pdf'
-            );
+            $this->transportBuilder->addAttachment($pdfFileData['filestream'], $pdfFileData['filename'] . $date . '.pdf', 'application/pdf');
         }
 
         return $this;
diff -ur module-pdfgenerator/Model/Email/TransportBuilder.php module-pdfgenerator.PATCHED/Model/Email/TransportBuilder.php
--- module-pdfgenerator/Model/Email/TransportBuilder.php	2020-04-16 12:38:25.000000000 +0100
+++ module-pdfgenerator.PATCHED/Model/Email/TransportBuilder.php	2020-11-26 15:22:05.000000000 +0000
@@ -6,14 +6,457 @@
 
 namespace Eadesigndev\Pdfgenerator\Model\Email;
 
-use Magento\Framework\Mail\Template\TransportBuilder as TransportBuilderParent;
+use Magento\Framework\App\TemplateTypesInterface;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Exception\MailException;
+use Magento\Framework\Mail\EmailMessageInterface;
+use Magento\Framework\Mail\EmailMessageInterfaceFactory;
+use Magento\Framework\Mail\AddressConverter;
+use Magento\Framework\Mail\Exception\InvalidArgumentException;
+use Magento\Framework\Mail\MessageInterface;
+use Magento\Framework\Mail\MessageInterfaceFactory;
+use Magento\Framework\Mail\MimeInterface;
+use Magento\Framework\Mail\MimeMessageInterfaceFactory;
+use Magento\Framework\Mail\MimePartInterfaceFactory;
+use Magento\Framework\Mail\Template\FactoryInterface;
+use Magento\Framework\Mail\Template\SenderResolverInterface;
+use Magento\Framework\Mail\TemplateInterface;
+use Magento\Framework\Mail\TransportInterface;
+use Magento\Framework\Mail\TransportInterfaceFactory;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\Phrase;
+use Zend\Mime\Mime;
+use Zend\Mime\PartFactory;
 
-class TransportBuilder extends TransportBuilderParent
+/**
+ * TransportBuilder
+ *
+ * @api
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @since 100.0.2
+ */
+class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
 {
+    /**
+     * Template Identifier
+     *
+     * @var string
+     */
+    protected $templateIdentifier;
 
-    public function addAttachment($content, $fileName)
+    /**
+     * Template Model
+     *
+     * @var string
+     */
+    protected $templateModel;
+
+    /**
+     * Template Variables
+     *
+     * @var array
+     */
+    protected $templateVars;
+
+    /**
+     * Template Options
+     *
+     * @var array
+     */
+    protected $templateOptions;
+
+    /**
+     * Mail Transport
+     *
+     * @var TransportInterface
+     */
+    protected $transport;
+
+    /**
+     * Template Factory
+     *
+     * @var FactoryInterface
+     */
+    protected $templateFactory;
+
+    /**
+     * Object Manager
+     *
+     * @var ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * Message
+     *
+     * @var EmailMessageInterface
+     */
+    protected $message;
+
+    /**
+     * Sender resolver
+     *
+     * @var SenderResolverInterface
+     */
+    protected $_senderResolver;
+
+    /**
+     * @var TransportInterfaceFactory
+     */
+    protected $mailTransportFactory;
+
+    /**
+     * Param that used for storing all message data until it will be used
+     *
+     * @var array
+     */
+    private $messageData = [];
+
+    /**
+     * @var EmailMessageInterfaceFactory
+     */
+    private $emailMessageInterfaceFactory;
+
+    /**
+     * @var MimeMessageInterfaceFactory
+     */
+    private $mimeMessageInterfaceFactory;
+
+    /**
+     * @var MimePartInterfaceFactory
+     */
+    private $mimePartInterfaceFactory;
+
+    /**
+     * @var AddressConverter|null
+     */
+    private $addressConverter;
+
+    protected $attachments = [];
+
+    protected $partFactory;
+
+    /**
+     * TransportBuilder constructor
+     *
+     * @param FactoryInterface $templateFactory
+     * @param MessageInterface $message
+     * @param SenderResolverInterface $senderResolver
+     * @param ObjectManagerInterface $objectManager
+     * @param TransportInterfaceFactory $mailTransportFactory
+     * @param MessageInterfaceFactory|null $messageFactory
+     * @param EmailMessageInterfaceFactory|null $emailMessageInterfaceFactory
+     * @param MimeMessageInterfaceFactory|null $mimeMessageInterfaceFactory
+     * @param MimePartInterfaceFactory|null $mimePartInterfaceFactory
+     * @param addressConverter|null $addressConverter
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+     */
+    public function __construct(
+        FactoryInterface $templateFactory,
+        MessageInterface $message,
+        SenderResolverInterface $senderResolver,
+        ObjectManagerInterface $objectManager,
+        TransportInterfaceFactory $mailTransportFactory,
+        MessageInterfaceFactory $messageFactory = null,
+        EmailMessageInterfaceFactory $emailMessageInterfaceFactory = null,
+        MimeMessageInterfaceFactory $mimeMessageInterfaceFactory = null,
+        MimePartInterfaceFactory $mimePartInterfaceFactory = null,
+        AddressConverter $addressConverter = null
+    ) {
+        $this->templateFactory = $templateFactory;
+        $this->objectManager = $objectManager;
+        $this->_senderResolver = $senderResolver;
+        $this->mailTransportFactory = $mailTransportFactory;
+        $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager
+            ->get(EmailMessageInterfaceFactory::class);
+        $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager
+            ->get(MimeMessageInterfaceFactory::class);
+        $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager
+            ->get(MimePartInterfaceFactory::class);
+        $this->addressConverter = $addressConverter ?: $this->objectManager
+            ->get(AddressConverter::class);
+        $this->partFactory = $objectManager->get(PartFactory::class);
+        parent::__construct($templateFactory, $message, $senderResolver, $objectManager, $mailTransportFactory, $messageFactory, $emailMessageInterfaceFactory, $mimeMessageInterfaceFactory,
+            $mimePartInterfaceFactory, $addressConverter);
+    }
+
+    /**
+     * Add cc address
+     *
+     * @param array|string $address
+     * @param string $name
+     *
+     * @return $this
+     */
+    public function addCc($address, $name = '')
+    {
+        $this->addAddressByType('cc', $address, $name);
+
+        return $this;
+    }
+
+    /**
+     * Add to address
+     *
+     * @param array|string $address
+     * @param string $name
+     *
+     * @return $this
+     * @throws InvalidArgumentException
+     */
+    public function addTo($address, $name = '')
+    {
+        $this->addAddressByType('to', $address, $name);
+
+        return $this;
+    }
+
+    /**
+     * Add bcc address
+     *
+     * @param array|string $address
+     *
+     * @return $this
+     * @throws InvalidArgumentException
+     */
+    public function addBcc($address)
+    {
+        $this->addAddressByType('bcc', $address);
+
+        return $this;
+    }
+
+    /**
+     * Set Reply-To Header
+     *
+     * @param string $email
+     * @param string|null $name
+     *
+     * @return $this
+     * @throws InvalidArgumentException
+     */
+    public function setReplyTo($email, $name = null)
+    {
+        $this->addAddressByType('replyTo', $email, $name);
+
+        return $this;
+    }
+
+    /**
+     * Set mail from address
+     *
+     * @param string|array $from
+     *
+     * @return $this
+     * @throws InvalidArgumentException
+     * @see setFromByScope()
+     *
+     * @deprecated 102.0.1 This function sets the from address but does not provide
+     * a way of setting the correct from addresses based on the scope.
+     */
+    public function setFrom($from)
+    {
+        return $this->setFromByScope($from);
+    }
+
+    /**
+     * Set mail from address by scopeId
+     *
+     * @param string|array $from
+     * @param string|int $scopeId
+     *
+     * @return $this
+     * @throws InvalidArgumentException
+     * @throws MailException
+     * @since 102.0.1
+     */
+    public function setFromByScope($from, $scopeId = null)
+    {
+        $result = $this->_senderResolver->resolve($from, $scopeId);
+        $this->addAddressByType('from', $result['email'], $result['name']);
+
+        return $this;
+    }
+
+    /**
+     * Set template identifier
+     *
+     * @param string $templateIdentifier
+     *
+     * @return $this
+     */
+    public function setTemplateIdentifier($templateIdentifier)
+    {
+        $this->templateIdentifier = $templateIdentifier;
+
+        return $this;
+    }
+
+    /**
+     * Set template model
+     *
+     * @param string $templateModel
+     *
+     * @return $this
+     */
+    public function setTemplateModel($templateModel)
+    {
+        $this->templateModel = $templateModel;
+        return $this;
+    }
+
+    /**
+     * Set template vars
+     *
+     * @param array $templateVars
+     *
+     * @return $this
+     */
+    public function setTemplateVars($templateVars)
+    {
+        $this->templateVars = $templateVars;
+
+        return $this;
+    }
+
+    /**
+     * Set template options
+     *
+     * @param array $templateOptions
+     * @return $this
+     */
+    public function setTemplateOptions($templateOptions)
+    {
+        $this->templateOptions = $templateOptions;
+
+        return $this;
+    }
+
+    /**
+     * Get mail transport
+     *
+     * @return TransportInterface
+     * @throws LocalizedException
+     */
+    public function getTransport()
+    {
+        try {
+            $this->prepareMessage();
+            $mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]);
+        } finally {
+            $this->reset();
+        }
+
+        return $mailTransport;
+    }
+
+    /**
+     * Reset object state
+     *
+     * @return $this
+     */
+    protected function reset()
+    {
+        $this->messageData = [];
+        $this->templateIdentifier = null;
+        $this->templateVars = null;
+        $this->templateOptions = null;
+        return $this;
+    }
+
+    /**
+     * Get template
+     *
+     * @return TemplateInterface
+     */
+    protected function getTemplate()
+    {
+        return $this->templateFactory->get($this->templateIdentifier, $this->templateModel)
+            ->setVars($this->templateVars)
+            ->setOptions($this->templateOptions);
+    }
+
+    /**
+     * Prepare message.
+     *
+     * @return $this
+     * @throws LocalizedException if template type is unknown
+     */
+    protected function prepareMessage()
+    {
+        $template = $this->getTemplate();
+        $content = $template->processTemplate();
+        switch ($template->getType()) {
+            case TemplateTypesInterface::TYPE_TEXT:
+                $part['type'] = MimeInterface::TYPE_TEXT;
+                break;
+
+            case TemplateTypesInterface::TYPE_HTML:
+                $part['type'] = MimeInterface::TYPE_HTML;
+                break;
+
+            default:
+                throw new LocalizedException(
+                    new Phrase('Unknown template type')
+                );
+        }
+        $mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]);
+        $parts = count($this->attachments) ? array_merge([$mimePart], $this->attachments) : [$mimePart];
+        $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create(
+            ['parts' => $parts]
+        );
+
+        $this->messageData['subject'] = html_entity_decode(
+            (string)$template->getSubject(),
+            ENT_QUOTES
+        );
+        $this->message = $this->emailMessageInterfaceFactory->create($this->messageData);
+
+        return $this;
+    }
+
+    /**
+     * Handles possible incoming types of email (string or array)
+     *
+     * @param string $addressType
+     * @param string|array $email
+     * @param string|null $name
+     *
+     * @return void
+     * @throws InvalidArgumentException
+     */
+    private function addAddressByType(string $addressType, $email, ?string $name = null): void
     {
-        $this->message->setBodyAttachment($content, $fileName);
+        if (is_string($email)) {
+            $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name);
+            return;
+        }
+        $convertedAddressArray = $this->addressConverter->convertMany($email);
+        if (isset($this->messageData[$addressType])) {
+            $this->messageData[$addressType] = array_merge(
+                $this->messageData[$addressType],
+                $convertedAddressArray
+            );
+        }
+    }
+
+    /**
+     * @param string|null $content
+     * @param string|null $fileName
+     * @param string|null $fileType
+     * @return TransportBuilder
+     */
+    public function addAttachment(?string $content, ?string $fileName, ?string $fileType)
+    {
+        $attachmentPart = $this->partFactory->create();
+        $attachmentPart->setContent($content)
+            ->setType($fileType)
+            ->setFileName($fileName)
+            ->setDisposition(Mime::DISPOSITION_ATTACHMENT)
+            ->setEncoding(Mime::ENCODING_BASE64);
+        $this->attachments[] = $attachmentPart;
+
         return $this;
     }
 }
diff -ur module-pdfgenerator/etc/di.xml module-pdfgenerator.PATCHED/etc/di.xml
--- module-pdfgenerator/etc/di.xml	2020-04-16 12:38:25.000000000 +0100
+++ module-pdfgenerator.PATCHED/etc/di.xml	2020-11-26 15:21:44.000000000 +0000
@@ -10,13 +10,10 @@
                 type="Eadesigndev\Pdfgenerator\Model\Pdfgenerator" />
     <preference for="Eadesigndev\Pdfgenerator\Api\TemplatesRepositoryInterface"
                 type="Eadesigndev\Pdfgenerator\Model\PdfgeneratorRepository" />
-    <preference for="\Magento\Framework\Mail\Template\TransportBuilder"
-                type="Eadesigndev\Pdfgenerator\Model\Email\TransportBuilder"/>
     <preference for="\Magento\Sales\Model\Order\Email\SenderBuilder"
                 type="Eadesigndev\Pdfgenerator\Model\Email\SenderBuilder"/>
-    <preference for="Magento\Framework\Mail\Message"
-                type="Eadesigndev\Pdfgenerator\Model\Email\Message"/>
-
+    <preference for="\Magento\Framework\Mail\Template\TransportBuilder"
+                type="Eadesigndev\Pdfgenerator\Model\Email\TransportBuilder"/>
 
     <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
         <arguments>
Only in module-pdfgenerator.PATCHED: module-pdfgenerator.patch

@thisisandrew
Copy link

fixed by #106

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants