How to Send Email with Attachment in Magento 2.3

How to Send Email with Attachment in Magento 2.3

How to Send Email with Attachment in Magento 2.3

The Magento 2.3.x framework (actually as all previous versions) doesn't provide an opportunity to add attachments to email messages. Yet, the implementation of this functionality for Magento 2.3.x is different from that of previous versions. The reason is that in most cases the 2.3.x framework uses Zend Framework 2 (ZF2) and almost totally refuses to apply ZF1. So, in this article, we're going to describe how to implement the email attachment in Magento 2.3.x.

For you to be confident in the topic, we'd highly recommended to familiarize with some ZF2 components such as

Now we can go ahead. Being one of the most important classes, Magento\Framework\Mail\Message has a disappointing implementation. We must create our own class by implementing the Magento\Framework\Mail\MailMessageInterface interface. The whole code of this class you can find by clicking this GitHub link.

Let's look at the methods which are used for the setting of mime parts.

1. Message::setBodyText() Method

First one is the Message::setBodyText() method.

public function setBodyText($content) 
{
    $textPart = $this->partFactory->create();

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

    $this->parts[] = $textPart;

    return $this;
}

With this method, we are able to add the text mime part to an email. Here we set content, define the type as well as specify the charset. After that we add this part to $this->parts array.

2. Message::setBodyText() Method

The next method is the Message::setBodyText() which is pretty similar to the previous one.

public function setBodyHtml($content) 
{
    $htmlPart = $this->partFactory->create();

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

    $this->parts[] = $htmlPart;

    return $this;
}

In this method, we do the same, except only one thing, we set another type - HTML.

3. Message::setBodyAttachment() Method

And finally, the third method is also simple, yet a little bit different.

public function setBodyAttachment($content, $fileName, $fileType)
{
    $attachmentPart = $this->partFactory->create();

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

    $this->parts[] = $attachmentPart;

    return $this;
}

Here we set the content of the file, then set a file type and specify its name. In addition, we set disposition. It’s necessary for the file to be treated as an attachment.

Above we've described all methods that help us to add mime parts to the message. But we also added to this class one more important method - Message::setPartsToBody().

4. Message::setPartsToBody Method

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

This method is used to put all the pieces together. It will be called in the TransportBuilder class that we'll create in the next step.

5. TransportBuilder::addAttachment() Method

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.

There is only one new simple method, i.e. TransportBuilder::addAttachment(), that provides adding attachments by builder.

public function addAttachment($content, $fileName, $fileType) 
{
    $this->message->setBodyAttachment($content, $fileName, $fileType);
    return $this;
}

Also there is one extended method, TransportBuilder::prepareMessage().

protected function prepareMessage()
{
    parent::prepareMessage();
    $this->message->setPartsToBody();
    return $this;
}

It just calls the Message::setPartsToBody() method that we’ve described above.

Specify Preference in di.xml

The only one thing that we haven't done is to specify preference for the \Magento\Framework\Mail\Message class. So let's create the di.xml file (if it doesn't exist) and add the preference to it.

<?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\Message" type="Extait\Attachment\Mail\Message"/>
</config>

So, that's all. Now you can use the TransportBuilder created earlier in your classes and call the TransportBuilder::addAttachment() method for adding attachments to emails.

You can find a sample module with this functionality here. Also, we implemented a CLI command that helps you in testing of the functionality described above.

Hope this post is helpful for you to set up Magento 2.3.x email attachment. If any questions, feel free to ask.

Comments

© Extait, 2019