0

I am working on a module in which I need to attach an attachment with sales email. However, Magento 2.3 use zendframework2 so email attachment is not the same as zendframework1 (in Magento 2.2).

Can anyone help me to achieve the same task? How to implement attachment functions in Magento 2.3

I have searched in google and read several questions but I didn't find the solution.

1

Fixed this issue by extending Magento\Framework\Mail\Message and adding new function createCustomAttachment in this, also edited the createHtmlMimeFromString function.

protected $attachment;

public function createCustomAttachment($body, $mimeType, $disposition, $encoding, $filename){
    $attachment = new Part($body);
    $attachment->setType($mimeType);
    $attachment->setDisposition($disposition);
    $attachment->setEncoding($encoding);
    $attachment->setFileName($filename);
    $this->attachment = $attachment;
    return $this;
}

Called the global variable $this->attachment in the function createHtmlMimeFromString. If the variable has value then we are adding the attachment data to the addPart function.

The code be like this

private function createHtmlMimeFromString($htmlBody)
{
    $htmlPart = new Part($htmlBody);
    $htmlPart->setCharset($this->zendMessage->getEncoding());
    $htmlPart->setType(Mime::TYPE_HTML);
    $mimeMessage = new \Zend\Mime\Message();
    $mimeMessage->addPart($htmlPart);
    if ($this->attachment) {
        $mimeMessage->addPart($this->attachment);
    }

    return $mimeMessage;
}

We need to copy the Magento\Framework\Mail\Message entire content in the extended file because the zendMessage is private and this is called in almost all functions.

We can call the createCustomAttachment function from the transport builder to pass the attachment details.

public function addAttachment($body,
                              $mimeType = Mime::TYPE_OCTETSTREAM,
                              $disposition = Mime::DISPOSITION_ATTACHMENT,
                              $encoding = Mime::ENCODING_BASE64,
                              $filename = null)
{
    //$this->message->createAttachment($body, $mimeType, $disposition, $encoding, $filename);
    $this->message->createCustomAttachment($body, $mimeType, $disposition, $encoding, $filename);
    return $this;
}
2

Try this way

Some of the functionalities in Magento 2.3.x is different from previous version.
The reason is that in most cases the 2.3.x framework uses Zend Framework 2 (ZF2) and almost totally refuses to applyZend Framework 1 (ZF1).

Magento\Framework\Mail\MailMessageInterface::createAttachment()


So, due to this, the previous method is deprecated and there is no direct method to do so.

As createAttachment() method is no more available, we will override Magento\Framework\Mail\Message and create a class which will implement Magento\Framework\Mail\MailMessageInterface.


[vendor_name] / [Module_name] /Mail

Message.php

<?php

namespace [vendor_name]\[Module_name]\Mail;

use Magento\Framework\Mail\MailMessageInterface;
use Zend\Mail\MessageFactory as MailMessageFactory;
use Zend\Mime\MessageFactory as MimeMessageFactory;
use Zend\Mime\Mime;
use Zend\Mime\Part;
use Zend\Mime\PartFactory;


class Message implements MailMessageInterface
{
    protected $partFactory;
    protected $mimeMessageFactory;
    private $zendMessage;
    private $messageType = self::TYPE_TEXT;
    protected $parts = [];

    public function __construct(PartFactory $partFactory, MimeMessageFactory $mimeMessageFactory, $charset = 'utf-8')
    {
        $this->partFactory = $partFactory;
        $this->mimeMessageFactory = $mimeMessageFactory;
        $this->zendMessage = MailMessageFactory::getInstance();
        $this->zendMessage->setEncoding($charset);
    }
    public function setBodyText($content)
    {
        $this->setMessageType(self::TYPE_TEXT);
        $textPart = $this->partFactory->create();

        $textPart->setContent($content)
            ->setType(Mime::TYPE_TEXT)
            ->setCharset($this->zendMessage->getEncoding());

        $this->parts[] = $textPart;

        return $this;
    }
    public function setBodyHtml($content)
    {
        $this->setMessageType(self::TYPE_HTML);
        $htmlPart = $this->partFactory->create();

        $htmlPart->setContent($content)
            ->setType(Mime::TYPE_HTML)
            ->setCharset($this->zendMessage->getEncoding());

        $this->parts[] = $htmlPart;

        $mimeMessage = new \Zend\Mime\Message();
        $mimeMessage->addPart($htmlPart);
        $this->zendMessage->setBody($mimeMessage);

        return $this;
    }
    public function setBodyAttachment($content, $fileName, $fileType, $encoding = '8bit')
    {
        $attachmentPart = $this->partFactory->create();

        $attachmentPart->setContent($content)
            ->setType($fileType)
            ->setFileName($fileName)
            ->setDisposition(Mime::DISPOSITION_ATTACHMENT)
            ->setEncoding($encoding);

        $this->parts[] = $attachmentPart;

        return $this;
    }
    public function setPartsToBody()
    {
        $mimeMessage = $this->mimeMessageFactory->create();
        $mimeMessage->setParts($this->parts);
        $this->zendMessage->setBody($mimeMessage);

        return $this;
    }
    public function setBody($body)
    {
        if (is_string($body) && $this->messageType === self::TYPE_HTML) {
            $body = self::createHtmlMimeFromString($body);
        }
        $this->zendMessage->setBody($body);

        return $this;
    }
    public function setSubject($subject)
    {
        $this->zendMessage->setSubject($subject);

        return $this;
    }
    public function getSubject()
    {
        return $this->zendMessage->getSubject();
    }
    public function getBody()
    {
        return $this->zendMessage->getBody();
    }
    public function setFrom($fromAddress)
    {
        $this->setFromAddress($fromAddress, null);

        return $this;
    }
    public function setFromAddress($fromAddress, $fromName = null)
    {
        $this->zendMessage->setFrom($fromAddress, $fromName);

        return $this;
    }
    public function addTo($toAddress)
    {
        $this->zendMessage->addTo($toAddress);

        return $this;
    }
    public function addCc($ccAddress)
    {
        $this->zendMessage->addCc($ccAddress);

        return $this;
    }
    public function addBcc($bccAddress)
    {
        $this->zendMessage->addBcc($bccAddress);

        return $this;
    }
    public function setReplyTo($replyToAddress)
    {
        $this->zendMessage->setReplyTo($replyToAddress);

        return $this;
    }
    public function getRawMessage()
    {
        return $this->zendMessage->toString();
    }
    private function createHtmlMimeFromString($htmlBody)
    {
        $htmlPart = new Part($htmlBody);
        $htmlPart->setCharset($this->zendMessage->getEncoding());
        $htmlPart->setType(Mime::TYPE_HTML);
        $mimeMessage = new \Zend\Mime\Message();
        $mimeMessage->addPart($htmlPart);

        return $mimeMessage;
    }
    public function setMessageType($type)
    {
        $this->messageType = $type;

        return $this;
    }
}

After implementation of the Mail\Message class we need to extend the \Magento\Framework\Mail\Template\TransportBuilder class.
This class is used for building the \Magento\Framework\Mail\Transport class which is in turn used for email sending.

[Vendor_name] / [Module_name] /Model/Mail/Template

AddEmailAttachemnt.php

<?php
namespace [Vendor_name]\[module_name]\Model\Mail\Template;

class AddEmailAttachemnt extends \Magento\Framework\Mail\Template\TransportBuilder
{

    public function addAttachment($file_content,$file_name,$file_type) 
    {
        $encoding = \Zend_Mime::ENCODING_BASE64;
        $this->message->setBodyAttachment($file_content, $file_name, $file_type, $encoding);
        return $this;
    }
    protected function prepareMessage()
    {
        parent::prepareMessage();
        $this->message->setPartsToBody();
        return $this;
    }
}


Here value of Function Parameter

$file_content

$file_url = "Exiting File URL (WEB-URL)";
$file_content = file_get_contents($file_url);


$file_name
this is name of file with extension like we have PDF file so name is FileName.pdf

$file_type
There are many File type for Different Files here are some File type list

'txt'  => 'text/plain',
'pdf'  => 'application/pdf',
'png' => 'image/png'

Click Here to More File Type


$encoding
here is Encoding type value of File on Internet if you are not pass this argument by default is 6-bit Encoding is apply. this value is depends on your file.

Now you Have to add below Lines to your di.xml file which are call your Overwrite files.

[vendor_name] / [Module_name] / etc

di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

   <preference for="\Magento\Framework\Mail\Template\TransportBuilder" type="[Vendor_name]\[module_name]\Model\Mail\Template\AddEmailAttachemnt" />

   <preference for="Magento\Framework\Mail\Message" type="[Vendor_name]\[module_name]\Mail\Message"/>

</config>

so now all file are place properly so now we will use send Email Attechment

Add this Code to send Email With Attechment

protected $_transportBuilder;

 public function __construct(
        ...................................................................
        ...................................................................
        \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,
        ....................................................................
        ....................................................................
   ) {
       .................................
       .................................
       $this->_transportBuilder = $transportBuilder;
      ..................................... 
      .....................................
   }
   public function execute() {

        ...........................
        ...........................
        ...........................

         $transport = $this->_transportBuilder->setTemplateIdentifier($Email_template_name) // put Email Template Name
              ->setTemplateOptions(['area' => 'frontend', 'store' => $store]) // $store is Current Store Name 
              ->setTemplateVars(
                    [
                       'var_1' => 'value_1',
                       'var_2' => 'value_2',
                       'var_3'    => 'value_3'
                    ]
                  )
              ->setFrom('Sender@gamil.com') // Sender Email address
              ->addTo('Receiver@gmail.com') // Receiver Email Address
              ->addAttachment($file_content, $file_name, $extension) // here Addtement are add with Email
              ->getTransport();
          $transport->sendMessage();

        ............................
        ............................
        ............................
   }

Now All code are Place at the Right place now run This Command

php bin/magento s:up

php bin/magento s:s:d -f

php bin/magento c:c

php bin/magento c:f

Now check your Receiver Email address attachment

Update in Magento [2.3.3]

Mangento 2.3.3 release introduces a new, immutable **EmailMessageInterface** that supports the sending of multi-part MIME-type content in email.
The Magento\Framework\Mail\Template\TransportBuilder and Magento\Newsletter\Model\Queue\TransportBuilder structures were refactored to use this new EmailMessageInterface instead of MessageInterface, which was previously used.
If you are a Magento extension developer and rely on \Magento\Email\Model\Transport::getMessage() or \Magento\Framework\Mail\TransportInterface::getMessage(), those methods will now return the new EmailMessageInterface.

Here add below Lines to your di.xml file which are call your Overwrite files.

[vendor_name] / [Module_name] / etc

di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

   <preference for="\Magento\Framework\Mail\Template\TransportBuilder" type="[Vendor_name]\[module_name]\Model\Mail\Template\AddEmailAttachemnt" />


</config>

[Vendor_name] / [Module_name] /Model/Mail/Template

AddEmailAttachemnt.php

<?php
declare (strict_types = 1);

namespace [Vendor_name]\[module_name]\Model\Mail\Template;

use Magento\Framework\App\TemplateTypesInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Mail\AddressConverter;
use Magento\Framework\Mail\EmailMessageInterfaceFactory;
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\TransportInterfaceFactory;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Phrase;
use Zend\Mime\Mime;
use Zend\Mime\PartFactory;

class AddEmailAttachemnt extends \Magento\Framework\Mail\Template\TransportBuilder
{

    protected $templateIdentifier;
    protected $templateModel;
    protected $templateVars;
    protected $templateOptions;
    protected $transport;
    protected $templateFactory;
    protected $objectManager;
    protected $message;
    protected $_senderResolver;
    protected $mailTransportFactory;
    private $messageData = [];
    private $emailMessageInterfaceFactory;
    private $mimeMessageInterfaceFactory;
    private $mimePartInterfaceFactory;
    private $addressConverter;
    protected $attachments = [];
    protected $partFactory;

    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
        );
    }
    public function addCc($address, $name = '')
    {
        $this->addAddressByType('cc', $address, $name);

        return $this;
    }
    public function addTo($address, $name = '')
    {
        $this->addAddressByType('to', $address, $name);

        return $this;
    }
    public function addBcc($address)
    {
        $this->addAddressByType('bcc', $address);

        return $this;
    }
    public function setReplyTo($email, $name = null)
    {
        $this->addAddressByType('replyTo', $email, $name);

        return $this;
    }
    public function setFrom($from)
    {
        return $this->setFromByScope($from);
    }
    public function setFromByScope($from, $scopeId = null)
    {
        $result = $this->_senderResolver->resolve($from, $scopeId);
        $this->addAddressByType('from', $result['email'], $result['name']);

        return $this;
    }
    public function setTemplateIdentifier($templateIdentifier)
    {
        $this->templateIdentifier = $templateIdentifier;

        return $this;
    }
    public function setTemplateModel($templateModel)
    {
        $this->templateModel = $templateModel;
        return $this;
    }
    public function setTemplateVars($templateVars)
    {
        $this->templateVars = $templateVars;

        return $this;
    }
    public function setTemplateOptions($templateOptions)
    {
        $this->templateOptions = $templateOptions;

        return $this;
    }
    public function getTransport()
    {
        try {
            $this->prepareMessage();
            $mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]);
        } finally {
            $this->reset();
        }

        return $mailTransport;
    }
    protected function reset()
    {
        $this->messageData = [];
        $this->templateIdentifier = null;
        $this->templateVars = null;
        $this->templateOptions = null;
        return $this;
    }
    protected function getTemplate()
    {
        return $this->templateFactory->get($this->templateIdentifier, $this->templateModel)
            ->setVars($this->templateVars)
            ->setOptions($this->templateOptions);
    }
    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;
    }
    private function addAddressByType($addressType, $email, $name = null): void
    {
        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
            );
        }
    }
    public function addAttachment($content, $fileName, $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;
    }
}

Add this Code to send Email With Attechment

protected $_transportBuilder;

 public function __construct(
        ...................................................................
        ...................................................................
        \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,
        ....................................................................
        ....................................................................
   ) {
       .................................
       .................................
       $this->_transportBuilder = $transportBuilder;
      ..................................... 
      .....................................
   }
   public function execute() {

        ...........................
        ...........................
        ...........................

         $transport = $this->_transportBuilder->setTemplateIdentifier($Email_template_name) // put Email Template Name
              ->setTemplateOptions(['area' => 'frontend', 'store' => $store]) // $store is Current Store Name 
              ->setTemplateVars(
                    [
                       'var_1' => 'value_1',
                       'var_2' => 'value_2',
                       'var_3'    => 'value_3'
                    ]
                  )
              ->setFrom('Sender@gamil.com') // Sender Email address
              ->addTo('Receiver@gmail.com') // Receiver Email Address
              ->addAttachment($file_content, $file_name, $extension) // here Addtement are add with Email
              ->getTransport();
          $transport->sendMessage();

        ............................
        ............................
        ............................
   }

Now All code are Place at the Right place now run This Command

php bin/magento s:up

php bin/magento s:s:d -f

php bin/magento c:c

php bin/magento c:f

Now check your Receiver Email address for attachment

I Hope This Helps You.

0

I had the same issue.

To solve this i created a helper.

use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Mail\MessageInterface;
use Magento\Framework\Mail\Template\FactoryInterface;
use Magento\Framework\Mail\Template\SenderResolverInterface;
use Magento\Framework\Mail\TransportInterfaceFactory;   
use Magento\Framework\Mail\Template\TransportBuilder;

class UploadTransportBuilder extends TransportBuilder {

public function __construct(FactoryInterface $templateFactory,
    MessageInterface $message,
    SenderResolverInterface $senderResolver,
    ObjectManagerInterface $objectManager,
    TransportInterfaceFactory $mailTransportFactory) {
    parent::__construct($templateFactory,
        $message,
        $senderResolver,
        $objectManager,
        $mailTransportFactory);
}

public function attachFile(
    $body,
    $filename    = null,
    $mimeType    = \Zend_Mime::TYPE_OCTETSTREAM,
    $disposition = \Zend_Mime::DISPOSITION_ATTACHMENT,
    $encoding    = \Zend_Mime::ENCODING_BASE64
)
{
    $this->message->createAttachment($body, $mimeType, $disposition, $encoding, $filename);
    return $this;
}

}

Then I loaded this on my controller.

use BVZ\Wishlist\Helper\UploadTransportBuilder;

UploadTransportBuilder $transportBuilder
$this->_transportBuilder = $transportBuilder

$transport = $this->_transportBuilder->setTemplateIdentifier('bvz_customer_wishlist')
            ->setTemplateOptions(['area' => 'frontend', 'store' => $store])
            ->setTemplateVars(['data' => $postObject])
            ->setFrom('support')
            ->addTo($formEmail, $customerName)
            ->attachFile($pdf,'Seleção de Produtos.pdf')
            ->getTransport();

$this->messageManager->addSuccess(__('Um e-mail foi enviado com sua lista de desejo.'));

            $transport->sendMessage();

The code method for attach a file is attachFile();

  • Thank you @Gabriel Fernandes I will try this. Is it working in magento 2.3 ? – Sameer Bhayani Jan 8 '19 at 13:39
  • i'm using 2.2.3, maybe works on 2.3 – Gabriel Fernandes Jan 8 '19 at 13:42
  • Thanks @Gabriel. Magento 2.3 using zendframework2 & zendframework had deleted createAttachment() function so it is not working in 2.3 however older magento 2 version use zendframework1 so It is working in those versions error: prnt.sc/m4gr1e – Sameer Bhayani Jan 8 '19 at 13:54
0

Send Email with Attachment in Magento 2.3

https://extait.com/blog/how-to-send-email-with-attachment-in-magento-2-3/

0

This solution is working so charming

 $transport = $_transportBuilder->setTemplateIdentifier(20)
->setTemplateOptions($templateOptions)
->setTemplateVars($templateVars)
->setFrom($from)
->addTo($vendor_email)
->getTransport();

 $html= $transport->getMessage()->getBody()->generateMessage();            
$bodyMessage = new \Zend\Mime\Part($html);
$bodyMessage->type = 'text/html';
$attachment=$_transportBuilder->addAttachment($pdfData,$fileName);      
$bodyPart = new \Zend\Mime\Message();
$bodyPart->setParts(array($bodyMessage,$attachment));
$transport->getMessage()->setBody($bodyPart);                
$transport->sendMessage();
$inlineTranslation->resume();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.