Attach PDF to Invoice Email in Magento 2 Programmatically
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!
How to Attach PDF to Invoice Email in Magento 2
Step 1: Create a TransportBuilder class
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;
}
}
Step 2: Create the SenderBuilder class
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>
A Better Solution to Attach PDF File to Invoice Email
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:
- Compatible with API/GraphQL
- Provide attractive pre-made PDF templates
- Send PDF documents
- Offer various convenient payment methods
- Download and print professional PDF documents from My Order page
- Download and print PDF documents in mass
- Allow documents to be printed in customer and admin accounts
Learn more on how to use the extension here.
Final Word
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.