In Magento, enhancing your communication strategy can significantly impact customer satisfaction and engagement. One effective way to achieve this is to add attachments to your emails, providing customers with comprehensive information, and improving the overall user experience.
In this blog post, we’ll guide you through the process of creating a Magento module to seamlessly attach invoices to your emails, enhancing the overall user experience.
Why adding attachments to Magento email is a valuable enhancement
Attaching files to Magento email proves beneficial for both enterprises and customers alike.
With businesses
Efficiency and Time Savings
With the automatic preparation of invoice attachments beforehand, businesses save time and effort. Senders can effortlessly click “send”, streamlining the communication process.
Professional Brand Image
Including well-designed attachments contributes to a professional image for the company. It reflects a commitment to organized and detailed communication, enhancing the overall perception of the business.
With customers
Comprehensive Order Details
Attachments provide customers with detailed order information, such as invoices, receipts, and shipping details, directly within the email. This eliminates the need for customers to navigate external platforms and ensures a comprehensive understanding of their purchase.
Simplified Communication
Attachments offer an easy-to-follow format, reducing the need for customers to read lengthy emails. Important information is presented clearly and concisely, enhancing the overall user experience.
Step-by-step Instructions to Add an Invoice Attachment to Magento Email
1. Create Module Files
To begin, you need to set up the basic structure of your module with the following files:
File 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="Tigren\SendPdf\Mail\Template\TransportBuilder"/>
<type name="Magento\Sales\Model\Order\Email\SenderBuilder">
<plugin name="add.attachment.email" type="Tigren\SendPdf\Plugin\SenderBuilder"/>
</type>
</config>
File module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Tigren_SendPdf" />
</config>
File registration.php
<?php
/*
* @author Tigren Solutions <[email protected]>
* @copyright Copyright (c) 2023 Tigren Solutions <https://www.tigren.com>. All rights reserved.
* @license Open Software License (“OSL”) v. 3.0
*/
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Tigren_SendPdf', __DIR__);
2. Override TransportBuilder
Then, we need to override the TransportBuilder file in the Tigren\SendPdf\Mail\Template directory of Magento to include the attachment functionality.
<?php
declare (strict_types=1);
namespace Tigren\SendPdf\Mail\Template;
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\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 Laminas\Mime\Mime;
use Laminas\Mime\Message;
use Laminas\Mime\PartFactory;
/**
* Class TransportBuilder
* @package Tigren\SendPdf\Mail\Template
*/
class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
/**
* @var Message
*/
protected $messageMime;
/**
* @var
*/
protected $message;
/**
* @var array
*/
protected $attachments = [];
/**
* @var PartFactory|mixed
*/
protected $partFactory;
/**
* @param Message $messageMime
* @param PartFactory $partFactory
* @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
*/
public function __construct(
Message $messageMime,
PartFactory $partFactory,
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->partFactory = $partFactory;
$this->messageMime = $messageMime;
parent::__construct(
$templateFactory,
$message,
$senderResolver,
$objectManager,
$mailTransportFactory,
$messageFactory,
$emailMessageInterfaceFactory,
$mimeMessageInterfaceFactory,
$mimePartInterfaceFactory,
$addressConverter
);
}
/**
* @return $this|TransportBuilder
* @throws LocalizedException
*/
protected function prepareMessage()
{
$result = parent::prepareMessage();
if (!empty($this->attachments)) {
foreach ($this->attachments as $attachment) {
$body = $this->message->getBody();
if (!$body) {
$body = $this->messageMime;
}
$body->addPart($attachment);
$this->message->setBody($body);
}
$this->attachments = [];
}
return $result;
}
/**
* @param $content
* @param $fileName
* @param $fileType
* @return $this
*/
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;
}
}
3. Plugin for SenderBuilder
<?php
namespace Tigren\SendPdf\Plugin;
use Laminas\Validator\Date;
use Tigren\SendPdf\Mail\Template\TransportBuilder;
use Magento\Sales\Model\Order\Email\Container\Template;
use Magento\Sales\Model\Order\Pdf\Invoice;
use Magento\Framework\Stdlib\DateTime\DateTime;
class SenderBuilder
{
private TransportBuilder $transportBuilder;
private Template $templateContainer;
private Invoice $renderInvoice;
private DateTime $dateTime;
public function __construct(
DateTime $dateTime,
Invoice $renderInvoice,
Template $templateContainer,
TransportBuilder $transportBuilder
) {
$this->transportBuilder = $transportBuilder;
$this->templateContainer = $templateContainer;
$this->renderInvoice = $renderInvoice;
$this->dateTime = $dateTime;
}
public function beforeSend(\Magento\Sales\Model\Order\Email\SenderBuilder $subject)
{
$dataInvoice = $this->_getDataTemplate();
try {
if(!empty($dataInvoice)){
$pdfContent = $this->renderInvoice->getPdf($dataInvoice)->render();
$date = $this->dateTime->date('Y-m-d_H-i-s');
$this->transportBuilder->addAttachment($pdfContent, 'invoice' . $date . '.pdf', 'application/pdf');
}
} catch (\Exception $e) {
return;
}
}
private function _getDataTemplate()
{
$data = $this->templateContainer->getTemplateVars();
if (array_key_exists('invoice_id', $data)) {
return [$data['invoice']];
}
if (isset($data['order']) && $data['order']->hasInvoices()) {
return $data['order']->getInvoiceCollection()->getItems();
}
return [$data['invoice']] ?? '';
}
Result
When an email for an invoice or order is dispatched, an invoice attachment is seamlessly appended to the email.
Conclusion
Following these steps, you can seamlessly add invoice attachments to your Magento emails. This enhances your communication strategy, providing customers with detailed information and contributing to a positive shopping experience.
Customize the module as needed for your specific use case, and elevate your customer engagement in the competitive world of e-commerce. Reach out to us for more tailor-made services that cater specifically to the needs of your online store.