Discover Shopify App Store – A Comprehensive Handbook 2024
Explore the Shopify App Store for tailored solutions to grow your business. Discover your perfect app today!
Vinh Jacker | 11-11-2024
If you’re running an e-commerce site built on Magento 2, chances are you have needed to attach a PDF file to the invoice email at least once. This happens a lot actually so it’s not a strange need. The point is that it will take too much time and effort to manually add each PDF file whenever you need.
Understand your concern, this blog will guide you on how to attach a PDF file to the invoice email programmatically.
Let’s head straight to the instructions!
Magento 2 sends emails by using the TransportBuilder, but it doesn’t allow admins to attach files. So, the first step is to create a TransportBuilder class in app/code/Vendor/Module /Mail/Template/ TransportBuilder.php
<?php
namespace Vendor\Module\Mail\Template;
class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
/**
* addAttachment
*
* @param mixed $body
* @param string $filename
* @param mixed $mimeType
* @param mixed $disposition
* @param mixed $encoding
* @return object
*/
public function addAttachment(
$body,
$filename = null,
$mimeType = \Zend_Mime::TYPE_OCTETSTREAM,
$disposition = \Zend_Mime::DISPOSITION_ATTACHMENT,
$encoding = \Zend_Mime::ENCODING_BASE64
) {
$attachmentPart = new \Zend\Mime\Part();
$attachmentPart->setContent($body)
->setType($mimeType)
->setFileName($filename)
->setEncoding($encoding)
->setDisposition($disposition);
return $attachmentPart;
}
}
Next, you need to create the SenderBuilder class in order to attach files. This class will allow you to add PDF, image, and calendar files to emails. Add the SenderBuilder class in app/code/Vendor/Module/Model/Sales/Order/Email/SenderBuilder.php
<?php
namespace Vendor\Module\Model\Sales\Order\Email;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Mail\Template\TransportBuilderByStore;
use Magento\Sales\Model\Order\Email\Container\IdentityInterface;
use Magento\Sales\Model\Order\Email\Container\Template;
/**
* Email sender builder for attachments
*/
class SenderBuilder extends \Magento\Sales\Model\Order\Email\SenderBuilder
{
/**
* @param Template $templateContainer
* @param IdentityInterface $identityContainer
* @param TransportBuilder $transportBuilder
* @param TransportBuilderByStore $transportBuilderByStore
* @param \Magento\Framework\Filesystem\Driver\File $reader
*/
public function __construct(
Template $templateContainer,
IdentityInterface $identityContainer,
TransportBuilder $transportBuilder,
TransportBuilderByStore $transportBuilderByStore = null,
\Vendor\Module\Helper\Data $helper,
\Magento\Framework\Filesystem\Driver\File $reader
) {
parent::__construct(
$templateContainer,
$identityContainer,
$transportBuilder
);
$this->helper = $helper;
$this->reader = $reader;
}
/**
* Prepare and send email message
*
* @return void
*/
public function send()
{
$this->configureEmailTemplate();
$this->transportBuilder->addTo(
$this->identityContainer->getCustomerEmail(),
$this->identityContainer->getCustomerName()
);
$copyTo = $this->identityContainer->getEmailCopyTo();
if (!empty($copyTo) && $this->identityContainer->getCopyMethod() == 'bcc') {
foreach ($copyTo as $email) {
$this->transportBuilder->addBcc($email);
}
}
/* to attach events in invoice email */
$templateVars = $this->templateContainer->getTemplateVars();
$transport = $this->transportBuilder->getTransport();
if (!empty($templateVars['order'])) {
$order = $templateVars['order'];
foreach ($order->getAllItems() as $item) {
$data = $this->helper->createPdfFile($item, $order->getId());
if (!empty($data) && !empty($data['filename']) && !empty($data['pdfFile'])) {
// adds attachment in mail
$attachmentPart = $this->transportBuilder->addAttachment(
$this->reader->fileGetContents($data['pdfFile']),
$data['filename'],
'application/pdf'
);
$message = $transport->getMessage();
$body = \Zend\Mail\Message::fromString($message->getRawMessage())->getBody();
$body = \Zend_Mime_Decode::decodeQuotedPrintable($body);
$html = '';
if ($body instanceof \Zend\Mime\Message) {
$html = $body->generateMessage(\Zend\Mail\Headers::EOL);
} elseif ($body instanceof \Magento\Framework\Mail\MimeMessage) {
$html = (string) $body->getMessage();
} elseif ($body instanceof \Magento\Framework\Mail\EmailMessage) {
$html = (string) $body->getBodyText();
} else {
$html = (string) $body;
}
$htmlPart = new \Zend\Mime\Part($html);
$htmlPart->setCharset('utf-8');
$htmlPart->setEncoding(\Zend_Mime::ENCODING_QUOTEDPRINTABLE);
$htmlPart->setDisposition(\Zend_Mime::DISPOSITION_INLINE);
$htmlPart->setType(\Zend_Mime::TYPE_HTML);
$parts = [$htmlPart, $attachmentPart];
$bodyPart = new \Zend\Mime\Message();
$bodyPart->setParts($parts);
$message->setBody($bodyPart);
}
}
}
$transport->sendMessage();
}
}
Finally, run this code in app/code/Vendor/Module/etc/di.xml
to activate the new TransportBuilder class you created in step 1.
<?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\Module\Model\Mail\TransportBuilder" />
</config>
If you’re not an expert developer, the programmatic method may not be an ideal choice. Instead, using an extension would be easier. All the features are displayed as fields in the backend clearly for store owners to use.
Among the choices, we would like to introduce PDF Invoice for Magento 2. It can automatically send PDF Invoices to your customers via emails with essential information, including order details, payment methods, etc.
Highlight features:
Learn more on how to use the extension here.
Sending a PDF file with detailed order information to invoice emails would be solid proof of e-commerce dedication to customers. If you’re confident with coding skills, the programmatic method would be a good option. In case you’re not, that’s okay. Using the Magento extension can solve the problem since it’s much easier to use.