6

Custom email attachment file is not working in magento 2.3. its working in Magento 2.2.X

Fatal error: Uncaught Error: Call to undefined method Magento\Framework\Mail\Message\Interceptor::createAttachment() in Mail/TransportBuilder.php

In magento 2.2.6 there is createAttachment method inside following path as same as magento 2.3

vendor\magento\zendframework1\library\Zend\Mail.php

but its giving method not defined

Please give any suggestion regarding issue

  • How did you used code can you please show? – Zaheerabbas Dec 6 '18 at 7:23
  • /*see extend template and all */ class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder { /*This file used for add method to attach file in email and also used preference in di.xml*/ public function addAttachment($path,$name) { $this->message->createAttachment( $path, 'application/image', \Zend_Mime::DISPOSITION_ATTACHMENT, \Zend_Mime::ENCODING_BASE64, $name ); return $this; } } – Manish Maheshwari Dec 6 '18 at 11:50
  • Hello @ManishMaheshwari Have you got solution? I stuck in same issue – Sameer Bhayani Jan 8 at 6:08
  • @SameerBhayani I haven't tried yet but you can try last answer – Manish Maheshwari Jan 9 at 6:51
  • @ManishMaheshwari I tried but It didn't work :( – Sameer Bhayani Jan 9 at 7:05
4

1) in your custom transport builder add the below function for atatchment:

<?php namespace Magebees\Demo\Model\Mail;

class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
    /**
     * @param Api\AttachmentInterface $attachment
     */
    public function addAttachment($pdfString,$filename)
    {
       $attachment = new \Zend\Mime\Part($pdfString);
            $attachment->type = \Zend_Mime::TYPE_OCTETSTREAM;
            $attachment->disposition = \Zend_Mime::DISPOSITION_ATTACHMENT;
            $attachment->encoding = \Zend_Mime::ENCODING_BASE64;
            $attachment->filename = $filename;
        return $attachment;
}
}

2) Then where you have used
$transport = $this->_transportBuilder->getTransport(); in that file add below code for send mail

$html='my testing html';            
            $bodyMessage = new \Zend\Mime\Part($html);
            $bodyMessage->type = 'text/html';
            $attachment=$this->_transportBuilder->addAttachment($pdfString,$pdf_name);      
            $bodyPart = new \Zend\Mime\Message();
            $bodyPart->setParts(array($bodyMessage,$attachment));
            $transport->getMessage()->setBody($bodyPart);
 $transport->sendMessage();
  • what we have to assign on that variables $pdfString,$pdf_name? – sumeet bajaj Jun 3 at 15:09
  • @sumeetbajaj ,here $pdfString will be $pdf->render() and $pdf_name will be name of pdf which you want. – Urvashi Prajapati Jun 4 at 8:52
  • ok but In ZF2 ,createAttachment() and addAttachment(), are not available anymore, so the correct way of dealing with multipart e-mails is using the Zend\Mime package.(according to above answer),i am using magento 2.3.1 verion but still unable to send email with attachment – sumeet bajaj Jun 4 at 9:48
4

Magento2.3 using ZendFramework2, Magento2.3 start deprecated us of ZendFramework1.

In ZF2 ,createAttachment() and addAttachment(), are not available anymore, so the correct way of dealing with multipart e-mails is using the Zend\Mime package.

See detail at https://zf2.readthedocs.io/en/release-2.2.3/modules/zend.mail.attachments.html

  • so how can we use Zend\Mime in Mail/TransportBuilder.php ? – Manish Maheshwari Dec 6 '18 at 8:50
  • /*i have tried in TransportBuilder class but attached not coming*/ public function addAttachment($path,$name) { $mail = new \Zend_Mail(); $fileContents = fopen($path, 'r'); $at = new \Zend_Mime_Part($fileContents); $at->type = 'image/jpg'; $at->disposition = \Zend_Mime::DISPOSITION_INLINE; $at->encoding = \Zend_Mime::ENCODING_BASE64; $at->filename = $name; $mail->addAttachment($at); return $this; } – Manish Maheshwari Dec 7 '18 at 4:37
  • @ManishMaheshwari add those code in your question – Murtuza Zabuawala Dec 17 '18 at 14:26
2

Yes, now it's needed to use ZF2 only. I'm no sure that the methods above will work smoothly. I found a better way to set this process.

I have managed to create a new class for Magento\Framework\Mail\Message default one by implementing of the Magento\Framework\Mail\MailMessageInterface interface. See the code that I've used https://github.com/extait-com/email-attachment/blob/master/Mail/Message.php

Also, this article will be helpful: https://extait.com/blog/how-to-send-email-with-attachment-in-magento-2-3/

Hope I help you.

  • Thank you @Jack Rush. While implementing above solution, I am getting error "main. ERROR: Unable to send mail: Unknown error". Emails are going to stop. – Sameer Bhayani Jan 7 at 8:18
  • @SameerBhayani I checked once again the stuff. All is working. Simply use this module github.com/extait-com/email-attachment – Jack Rush Jan 10 at 9:19
  • Then it could be problem in somewhere from my end. Ty – Sameer Bhayani Jan 10 at 10:36
  • i have used same module but i got this error PHP Fatal error: Uncaught Error: Call to undefined method Extait\Attachment\Mail\Message\Interceptor::setFromAddress() – Abdul Kadir Jun 13 at 8:33
  • @JackRush I have implement code as you said but i got this error: Uncaught Error: Call to undefined method Extait\Attachment\Mail\Message\Interceptor::setFromAddress() in / /public_html/vendor/magento/framework/Mail/Template/TransportBuilder.php:206 – Abdul Kadir Jun 13 at 8:49
1

This extension works fine on Magento ver. 2.3.1, https://github.com/extait-com/email-attachment

Just add a function in Extait/Attachment/Mail/Message.php,

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

and test it via command php bin/magento extait:test:attachment.

0

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;
}
0

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 for file is attachment

I Hope This Helps You.

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.