0

I am new to Magneto. and i searched and tried different solution online but they didn't work. I have an observer from which I generate CSV file whenever a customer place an order. I'm using <sales_order_place_after> to get it triggered. now i want to add the code to send the email with the generated CSV file in attachment to the customer. i'm getting this error: Unable to send mail: Unknown error {"exception":"[object] (Laminas\Mail\Transport\Exception\RuntimeException(code: 0): Unable to send mail: Unknown error at /home/lenovo/Ven/vendor/laminas/laminas-mail/src/Transport/Sendmail.php:298)"} []

Storeven/Orders/Observers/OrderExport.php

<?php
namespace Storeven\Orders\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Translate\Inline\StateInterface;
class Orderexport implements ObserverInterface
{
//changes
protected $_objectManager;
private $logger;
private $productFactory;
//-----//
protected $_transportBuilder;
protected $inlineTranslation;
protected $_request;
protected $_order;
protected $_productRepository;
protected $_scopeConfig;
protected $_customer;
protected $_storemanager;
protected $_dir;
public function __construct(
\Magento\Framework\App\RequestInterface $request,
\Magento\Sales\Model\Order $order,
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
Filesystem $filesystem,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Customer\Model\Customer $customer,
\Magento\Store\Model\StoreManagerInterface $storemanager,
\Magento\Checkout\Model\Session $checkoutSession,
\Magento\Sales\Model\OrderFactory $orderFactory,
\Magento\Framework\ObjectManager\ObjectManager $objectManager,
\Psr\Log\LoggerInterface $logger,
\Magento\Catalog\Model\ProductFactory $productFactory,
\Magento\Catalog\Model\ProductRepository $productRepository,
\Magento\Framework\Filesystem\DirectoryList $dir,
\Magento\Framework\Mail\Template\TransportBuilder $transportBuilder 
) { 
$this->_scopeConfig = $scopeConfig;
$this->_customer = $customer;
$this->_storemanager = $storemanager;
$this->_request = $request;
$this->_order = $order;
$this->_fileFactory = $fileFactory;
$this->directory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
$this->_productRepository = $productRepository;
$this->_transportBuilder = $transportBuilder;
$this->logger = $logger;
$this->dir = $dir;
}
public function getRootDirectory()
{
return $this->dir->getRoot();
}
public function execute(\Magento\Framework\Event\Observer $observer) {
$order = $observer->getEvent()->getOrder();
$store = $this->_storemanager->getStore()->getName();
$websiteID = $this->_storemanager->getStore()->getWebsiteId();
$headers = array('Company Name', 'Contact Name', 'Contact Email', 'Contact Phone','Shipping Address' ,'SKU','ProductColorID','QTY','Price','Total','CBM','Weight');
$name = strtotime('now');
$file = 'customorderexport/'.$name.'_detailed_orderexport.csv';
$this->directory->create('customorderexport');
$stream = $this->directory->openFile($file, 'w+');
$stream->lock();
$stream->writeCsv($headers);
$orderdetail['Company Name'] = "";
$orderdetail['Contact Name'] = $order->getCustomerName();
$orderdetail['Contact Email'] = $order->getCustomerEmail();
$orderdetail['Contact Phone'] = $order->getShippingAddress()->getTelephone();
$streetadd = $order->getShippingAddress()->getStreet();
$orderdetail['Shipping Address'] = $streetadd[0];
$items = $order->getAllItems();
foreach ($items as $item) {
$orderdetail['SKU'] = $item->getSKU();
$orderdetail['ProductColorID']= "";
$orderdetail['QTY'] = $item->getQtyOrdered();
$orderdetail['Price'] = $item->getPrice();
$orderdetail['Total'] = $item->getRowTotalInclTax();
// $id = $item->getProdcutId();
// $product = $this->_productRepository->getById($id);
// $orderdetail['CBM'] = $product->getcbm();
$orderdetail['CBM'] = "";
$quantity = $item->getQtyOrdered();
$orderdetail['Weight'] = $item->getWeight() * $quantity ;
$stream->writeCsv($orderdetail);
}
$stream->unlock();
$stream->close();
//Email code
//$Email_template_name="AddEmailAttachemnt";
// $file_url = 'storeven/var/customorderexport/'.$name.'_detailed_orderexport.csv';
try {
$file_url = '/home/lenovo/storeven/var/customorderexport/1654160951_detailed_orderexport.csv';
$emailTemplateVariables['message'] = 'This is a test message.';
$file_content = file_get_contents($file_url);
$file_name = $name."_detailed_orderexport.csv";
$extension="text/csv";
$transport = $this->_transportBuilder->setTemplateIdentifier('myemail_email_template') 
->setTemplateVars($emailTemplateVariables)
->setTemplateOptions([
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
'store' => $this->_storemanager->getStore()->getId()
]) 
->setFrom([
'email' => '[email protected]',
'name' => 'my store'
])
->addTo('[email protected]') // Receiver Email Address
->addAttachment($file_content, $file_name, $extension) // here Addtement are add with Email
->getTransport();
}
catch (\Exception $e) {
$this->logger->critical($e->getMessage());
}
}
}

Orders/Model/Mail/Template/AddEmailAttachemnt.php


namespace Storeven\Orders\Model\Mail\Template;
use Magento\Framework\App\TemplateTypesInterface;
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\MimeInterface;
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 Magento\Framework\Phrase;
use Laminas\Mime\Mime;
use Laminas\Mime\PartFactory;
class AddEmailAttachemnt extends \Magento\Framework\Mail\Template\TransportBuilder
{
protected $templateIdentifier;
protected $templateModel;
protected $templateVars;
protected $templateOptions;
protected $transport;
protected $templateFactory;
protected $objectManager;
protected $message;
protected $_senderResolver;
protected $mailTransportFactory;
private $messageData = [];
private $emailMessageInterfaceFactory;
private $mimeMessageInterfaceFactory;
private $mimePartInterfaceFactory;
private $addressConverter;
protected $attachments = [];
protected $partFactory;
public function __construct(
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->objectManager = $objectManager;
$this->_senderResolver = $senderResolver;
$this->mailTransportFactory = $mailTransportFactory;
$this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager
->get(EmailMessageInterfaceFactory::class);
$this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager
->get(MimeMessageInterfaceFactory::class);
$this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager
->get(MimePartInterfaceFactory::class);
$this->addressConverter = $addressConverter ?: $this->objectManager
->get(AddressConverter::class);
$this->partFactory = $objectManager->get(PartFactory::class);
parent::__construct(
$templateFactory,
$message,
$senderResolver,
$objectManager,
$mailTransportFactory,
$messageFactory,
$emailMessageInterfaceFactory,
$mimeMessageInterfaceFactory,
$mimePartInterfaceFactory,
$addressConverter
);
}
public function addCc($address, $name = '')
{
$this->addAddressByType('cc', $address, $name);
return $this;
}
public function addTo($address, $name = '')
{
$this->addAddressByType('to', $address, $name);
return $this;
}
public function addBcc($address)
{
$this->addAddressByType('bcc', $address);
return $this;
}
public function setReplyTo($email, $name = null)
{
$this->addAddressByType('replyTo', $email, $name);
return $this;
}
public function setFrom($from)
{
return $this->setFromByScope($from);
}
public function setFromByScope($from, $scopeId = null)
{
$result = $this->_senderResolver->resolve($from, $scopeId);
$this->addAddressByType('from', $result['email'], $result['name']);
return $this;
}
public function setTemplateIdentifier($templateIdentifier)
{
$this->templateIdentifier = $templateIdentifier;
return $this;
}
public function setTemplateModel($templateModel)
{
$this->templateModel = $templateModel;
return $this;
}
public function setTemplateVars($templateVars)
{
$this->templateVars = $templateVars;
return $this;
}
public function setTemplateOptions($templateOptions)
{
$this->templateOptions = $templateOptions;
return $this;
}
public function getTransport()
{
try {
$this->prepareMessage();
$mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]);
} finally {
$this->reset();
}
return $mailTransport;
}
protected function reset()
{
$this->messageData = [];
$this->templateIdentifier = null;
$this->templateVars = null;
$this->templateOptions = null;
return $this;
}
protected function getTemplate()
{
return $this->templateFactory->get($this->templateIdentifier, $this->templateModel)
->setVars($this->templateVars)
->setOptions($this->templateOptions);
}
protected function prepareMessage()
{
$template = $this->getTemplate();
$content = $template->processTemplate();
switch ($template->getType()) {
case TemplateTypesInterface::TYPE_TEXT:
$part['type'] = MimeInterface::TYPE_TEXT;
break;
case TemplateTypesInterface::TYPE_HTML:
$part['type'] = MimeInterface::TYPE_HTML;
break;
default:
throw new LocalizedException(
new Phrase('Unknown template type')
);
}
$mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]);
$parts = count($this->attachments) ? array_merge([$mimePart], $this->attachments) : [$mimePart];
$this->messageData['body'] = $this->mimeMessageInterfaceFactory->create(
['parts' => $parts]
);
$this->messageData['subject'] = html_entity_decode(
(string) $template->getSubject(),
ENT_QUOTES
);
$this->message = $this->emailMessageInterfaceFactory->create($this->messageData);
return $this;
}
private function addAddressByType($addressType, $email, $name = null): void
{
if (is_string($email)) {
$this->messageData[$addressType][] = $this->addressConverter->convert($email, $name);
return;
}
$convertedAddressArray = $this->addressConverter->convertMany($email);
if (isset($this->messageData[$addressType])) {
$this->messageData[$addressType] = array_merge(
$this->messageData[$addressType],
$convertedAddressArray
);
}
}
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;
}
}
asked Jun 3, 2022 at 8:57

2 Answers 2

1

Please to be sure you have a correct template for your custom email

app/code/Acme/StackExchange/etc/email_templates.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
 <template id="myemail_email_template" label="export_email_template" file="export_email_template.html" type="html" module="Acme_StackExchange" area="frontend"/>
</config>

app/code/Acme/StackExchange/view/frontend/email/export_email_template.html

<!--@subject {{trans "StackExchange Email with Attachment"}} @-->
<!--@vars {} @-->
{{template config_path="design/email/header_template"}}
{{template config_path="design/email/footer_template"}}

Working example based on your code with some quick refactoring

app/code/Acme/StackExchange/Observer/Sales/OrderPlaceAfter.php

<?php
declare(strict_types=1);
namespace Acme\StackExchange\Observer\Sales;
use Laminas\Mime\Mime as MimeType;
use Laminas\Mime\Message as MimeMessage;
use Laminas\Mime\Part as MimePart;
use Magento\Framework\App\Area;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Filesystem;
use Magento\Framework\Mail\Template\TransportBuilderFactory;
use Magento\Sales\Model\Order;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
class OrderPlaceAfter implements ObserverInterface
{
 private const EXPORT_DIR = 'customorderexport';
 /**
 * @var StoreManagerInterface
 */
 protected $storeManager;
 /**
 * @var ScopeConfigInterface
 */
 protected $scopeConfig;
 /**
 * @var Filesystem
 */
 protected $filesystem;
 /**
 * @var TransportBuilderFactory
 */
 protected $transportBuilderFactory;
 /**
 * @var LoggerInterface
 */
 protected $logger;
 public function __construct(
 StoreManagerInterface $storeManager,
 ScopeConfigInterface $scopeConfig,
 Filesystem $filesystem,
 TransportBuilderFactory $transportBuilderFactory,
 LoggerInterface $logger
 ) {
 $this->storeManager = $storeManager;
 $this->scopeConfig = $scopeConfig;
 $this->filesystem = $filesystem;
 $this->transportBuilderFactory = $transportBuilderFactory;
 $this->logger = $logger;
 }
 /**
 * @inheritDoc
 */
 public function execute(Observer $observer)
 {
 /** @var Order $order */
 $order = $observer->getEvent()->getData('order');
 try {
 $fileContent = $this->getOrderDetailCsv($order);
 $fileType = 'text/csv';
 $fileName = 'detailed_orderexport.csv';
 $storeId = $this->storeManager->getStore()->getId();
 $sender = 'sales_email/order/identity';
 $transportBuilder = $this->transportBuilderFactory->create();
 $transportBuilder
 ->setTemplateIdentifier('myemail_email_template')
 ->setTemplateOptions(['area' => Area::AREA_FRONTEND, 'store' => $storeId])
 ->setTemplateVars([])
 ->setFromByScope($this->scopeConfig->getValue($sender, ScopeInterface::SCOPE_STORE, $storeId), $storeId)
 ->addTo('[email protected]');
 $transport = $transportBuilder->getTransport();
 $body = $transport->getMessage()->getBody();
 if ($body instanceof MimeMessage) {
 $parts = $body->getParts();
 $attachmentPart = new MimePart();
 $attachmentPart->setContent($fileContent)
 ->setType($fileType)
 ->setFileName($fileName)
 ->setDisposition(MimeType::DISPOSITION_ATTACHMENT)
 ->setEncoding(MimeType::ENCODING_BASE64);
 $parts[] = $attachmentPart;
 $message = new MimeMessage();
 $message->setParts($parts);
 $transport->getMessage()->setBody($message);
 }
 $transport->sendMessage();
 } catch (\Exception $e) {
 $this->logger->critical($e->getMessage());
 }
 }
 private function getOrderDetailCsv(Order $order): string
 {
 $name = $order->getIncrementId();
 $file = self::EXPORT_DIR . '/' . $name . '.csv';
 $directory = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
 $directory->create(self::EXPORT_DIR);
 $stream = $directory->openFile($file, 'w+');
 $stream->lock();
 $headers = ['Company Name', 'Contact Name', 'Contact Email', 'Contact Phone', 'Shipping Address', 'SKU', 'ProductColorID', 'QTY', 'Price', 'Total', 'CBM', 'Weight'];
 $stream->writeCsv($headers);
 $csvRow = [
 'Company Name' => '',
 'Contact Name' => $order->getCustomerName(),
 'Contact Email' => $order->getCustomerEmail(),
 'Contact Phone' => $order->getShippingAddress()->getTelephone(),
 'Shipping Address' => $order->getShippingAddress()->getStreetLine(1),
 ];
 foreach ($order->getAllVisibleItems() as $item) {
 $csvRow['SKU'] = $item->getSKU();
 $csvRow['ProductColorID'] = '';
 $csvRow['QTY'] = $item->getQtyOrdered();
 $csvRow['Price'] = $item->getPrice();
 $csvRow['Total'] = $item->getRowTotalInclTax();
 $csvRow['CBM'] = "";
 $csvRow['Weight'] = $item->getWeight() * $item->getQtyOrdered();
 $stream->writeCsv($csvRow);
 }
 $stream->unlock();
 $stream->close();
 return $directory->readFile($file);
 }
}

Result

answered Jun 3, 2022 at 12:56
2
  • I'm getting this Email template 'myemail_email_template' is not defined. [] [] Commented Jun 3, 2022 at 13:47
  • Please see carefully example of email_templates.xml. I've used myemail_email_template definition from your code. Don't forget to update email_templates.xml and specify correct module and template path and clear cache. Commented Jun 3, 2022 at 13:58
0

This is the method where your code is failing

/**
 * Send mail using PHP native mail()
 *
 * @param string $to
 * @param string $subject
 * @param string $message
 * @param string $headers
 * @param $parameters
 * @throws \Laminas\Mail\Transport\Exception\RuntimeException
 */
public function mailHandler($to, $subject, $message, $headers, $parameters)
{
 set_error_handler([$this, 'handleMailErrors']);
 if ($parameters === null) {
 $result = mail($to, $subject, $message, $headers);
 } else {
 $result = mail($to, $subject, $message, $headers, $parameters);
 }
 restore_error_handler();
 if ($this->errstr !== null || ! $result) {
 $errstr = $this->errstr;
 if (empty($errstr)) {
 $errstr = 'Unknown error';
 }
 throw new Exception\RuntimeException('Unable to send mail: ' . $errstr);
 }
}

I'm suggesting you to dump all of the mail method parameter fields to see which one could create the problem and with that it might be easier to see what you missed in your observer (that you didn't provided).

answered Jun 3, 2022 at 9:06
2
  • I have added the code. Commented Jun 3, 2022 at 10:25
  • @saminakhan first try to send a simple mail without any attachments, to make sure it's not coming from your server configuration. Commented Jun 3, 2022 at 12:21

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.