Respuestas:
M2 no viene listo para usar, sin embargo, es una característica integrada en el marco zend. Aquí hay una buena referencia sobre cómo agregar esta funcionalidad a magento: https://blog.bitexpert.de/blog/sending-mails-with-attachments-in-magento-2/
En caso de que el enlace se bloquee, cree lo siguiente
<?php
namespace Your\CustomModule\Magento\Mail\Template;
class TransportBuilder
extends \Magento\Framework\Mail\Template\TransportBuilder
{
public function addAttachment(
$body,
$mimeType = Zend_Mime::TYPE_OCTETSTREAM,
$disposition = Zend_Mime::DISPOSITION_ATTACHMENT,
$encoding = Zend_Mime::ENCODING_BASE64,
$filename = null
) {
$this->message->createAttachment($body, $mimeType, $disposition, $encoding, $filename);
return $this;
}
}
luego agregue a etc / 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="\Your\CustomModule\Magento\Mail\Template\TransportBuilder" />
</config>
Ahora puede usarlo en addAttachment()
todo su sitio.
A partir de Magento 2.2.7, las soluciones descritas anteriormente ya no funcionan ya que \Magento\Framework\Mail\Message
dejó de extenderse \Zend_Mail
.
Para evitar la falta de una manera fácil de agregar archivos adjuntos a través del constructor de transporte (que actualmente parece ser el lugar correcto para tal función), es necesario crear un reemplazo para el TransportBuilder y utilizar \Zend\Mime\Part
:
<?php
namespace Your\CustomModule\Magento\Mail\Template;
use Magento\Framework\Mail\MessageInterface;
use Magento\Framework\Mail\MessageInterfaceFactory;
use Magento\Framework\Mail\Template\FactoryInterface;
use Magento\Framework\Mail\Template\SenderResolverInterface;
use Magento\Framework\Mail\TransportInterfaceFactory;
use Magento\Framework\ObjectManagerInterface;
use Zend\Mime\Mime;
use Zend\Mime\Part as MimePart;
use Zend\Mime\PartFactory as MimePartFactory;
use Zend\Mime\Message as MimeMessage;
use Zend\Mime\MessageFactory as MimeMessageFactory;
class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
/** @var MimePart[] */
private $parts = [];
/** @var MimeMessageFactory */
private $mimeMessageFactory;
/** @var MimePartFactory */
private $mimePartFactory;
public function __construct(
FactoryInterface $templateFactory,
MessageInterface $message,
SenderResolverInterface $senderResolver,
ObjectManagerInterface $objectManager,
TransportInterfaceFactory $mailTransportFactory,
MimePartFactory $mimePartFactory,
MimeMessageFactory $mimeMessageFactory,
MessageInterfaceFactory $messageFactory = null
) {
parent::__construct(
$templateFactory,
$message,
$senderResolver,
$objectManager,
$mailTransportFactory,
$messageFactory
);
$this->mimePartFactory = $mimePartFactory;
$this->mimeMessageFactory = $mimeMessageFactory;
}
protected function prepareMessage()
{
parent::prepareMessage();
$mimeMessage = $this->getMimeMessage($this->message);
foreach ($this->parts as $part) {
$mimeMessage->addPart($part);
}
$this->message->setBody($mimeMessage);
return $this;
}
public function addAttachment(
$body,
$mimeType = Mime::TYPE_OCTETSTREAM,
$disposition = Mime::DISPOSITION_ATTACHMENT,
$encoding = Mime::ENCODING_BASE64,
$filename = null
) {
$this->parts[] = $this->createMimePart($body, $mimeType, $disposition, $encoding, $filename);
return $this;
}
private function createMimePart(
$content,
$type = Mime::TYPE_OCTETSTREAM,
$disposition = Mime::DISPOSITION_ATTACHMENT,
$encoding = Mime::ENCODING_BASE64,
$filename = null
) {
/** @var MimePart $mimePart */
$mimePart = $this->mimePartFactory->create(['content' => $content]);
$mimePart->setType($type);
$mimePart->setDisposition($disposition);
$mimePart->setEncoding($encoding);
if ($filename) {
$mimePart->setFileName($filename);
}
return $mimePart;
}
private function getMimeMessage(MessageInterface $message)
{
$body = $message->getBody();
if ($body instanceof MimeMessage) {
return $body;
}
/** @var MimeMessage $mimeMessage */
$mimeMessage = $this->mimeMessageFactory->create();
if ($body) {
$mimePart = $this->createMimePart((string)$body, Mime::TYPE_TEXT, Mime::DISPOSITION_INLINE);
$mimeMessage->setParts([$mimePart]);
}
return $mimeMessage;
}
}
No olvide reemplazar el original \Magento\Framework\Mail\Template\TransportBuilder
por su implementación a través dedi.xml
.
Tenga en cuenta que esta implementación probablemente se romperá con un próximo lanzamiento de Magento como \Magento\Framework\Mail\MessageInterface::setBody()
está en desuso y puede eliminarse pronto.
HTH
Correo electrónico personalizado de Magento 2 desde el módulo, no proporciona datos adjuntos
Si desea utilizar archivos adjuntos de imágenes con plantillas de correo electrónico en Magento 2, debe anular la clase, Magento \ Framework \ Mail \ Template \ TransportBuilder
Magento listo para usar no proporciona la función de archivo adjunto para correo electrónico. Puede referir blogs para enviar datos adjuntos de imágenes en detalles,
Necesitas agregar lógica como a continuación,
public function addAttachment(
$body,
$mimeType = \Zend_Mime::TYPE_OCTETSTREAM,
$disposition = \Zend_Mime::DISPOSITION_ATTACHMENT,
$encoding = \Zend_Mime::ENCODING_BASE64,
$filename = null
) {
$this->message->createAttachment($body, $mimeType, $disposition, $encoding, $filename);
return $this;
}
Aquí hay una respuesta perfecta para enviar pdf en correo electrónico en magetno 2.3
$transport = $_transportBuilder->setTemplateIdentifier(20)
->setTemplateOptions($templateOptions)
->setTemplateVars($templateVars)
->setFrom($from)
->addTo($vendor_email)
->getTransport();
$html = $transport->getMessage()>getBody()->generateMessage();
$bodyMessage = new \Zend\Mime\Part($html);
$bodyMessage->type = 'text/html';
$attachment = $_transportBuilder->addAttachment($pdfData,$fileName);
$bodyPart = new \Zend\Mime\Message();
$bodyPart->setParts(array($bodyMessage,$attachment));
$transport->getMessage()->setBody($bodyPart);
$transport->sendMessage();
$inlineTranslation->resume();
Esta fue mi respuesta para Magento 2.3 ya que esta era una pregunta importante en Google y parece que hay mucha gente mirando los comentarios.
Parece que hay muchas ganas en otras publicaciones sobre sobrescribir la TransportBuilder
clase predeterminada a través de etc/di.xml
, sin embargo, el módulo en el que estoy trabajando es tan pequeño que no quiero que sea responsable de la clase predeterminadaTransportBuilder
así que construí una clase auxiliar (debería probablemente sea un modelo basado en qué tan acoplado está a la plantilla de correo electrónico declarada, pero estoy divagando).
El TransportBuilder
no tiene acceso público al TransportInterface
, sino que genera un clon cada vez y luego restablece el generador. Me resultó más fácil construir mi TransportInterface
instancia y luego adjuntar mis Part
objetos adjuntos al mensaje del transporte. Si considera necesario sobrescribir el valor predeterminado TransportBuilder
mediante la preferencia de inyección de dependencia, tenga cuidado al actualizar los métodos públicos. ¡Recuerde practicar el O cuando mantenga su código SOLIDO !
namespace Vendor\Module\Helper;
use Magento\Framework\App\Area;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\DataObject;
use Magento\Framework\Filesystem\Io\File;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Mail\TransportInterface;
use Magento\Store\Model\StoreManagerInterface;
use Zend_Mime;
use Zend\Mime\Part;
/**
* This was initially built out to send a single email. Abstract this as you
* wish.
*
* @package Vendor\Module\Helper
*/
class Mail extends AbstractHelper
{
/**
* @var Context
*/
protected $context;
/**
* @var TransportBuilder
*/
protected $transportBuilder;
/**
* @var StoreManagerInterface
*/
protected $storeManager;
/**
* @var Config
*/
protected $config;
/**
* Mail constructor.
*
* @param Context $context
* @param TransportBuilder $transportBuilder
* @param StoreManagerInterface $storeManager
* @param Config $config
* @param File $file
*/
public function __construct(
Context $context,
TransportBuilder $transportBuilder,
StoreManagerInterface $storeManager,
Config $config,
File $file
) {
parent::__construct($context);
$this->transportBuilder = $transportBuilder;
$this->storeManager = $storeManager;
$this->config = $config;
$this->file = $file;
}
/**
* Send the email for a Help Center submission.
*
* @param DataObject $templateParams
* @param array $attachments
* @return void
*/
public function send(DataObject $templateParams, array $attachments = [])
{
$storeId = $this->storeManager->getStore()->getId();
// Build transport
/** @var \Magento\Framework\Mail\TransportInterface $transport */
$transport = $this->transportBuilder
->setTemplateOptions(['area' => Area::AREA_FRONTEND, 'store' => $storeId])
->setTemplateIdentifier($this->config->getEmailTemplate())
->setTemplateVars($templateParams->toArray())
->setFrom($this->config->getEmailSender())
->addTo($this->config->getEmailRecipient(), 'Help Center')
/**
* Something important to note is that when the getTransport()
* function is run, the message is compiled and then the builder
* class resets (as of 2.3.1).
*
* This is note worthy because if you want to send > 1 attachment,
* your $builder will be reset -- losing all of the ->set* functions
* you just used above as well as your attachment.
*
* Since we append attachments to the transport, it's easier to:
* build -> attach -> send. And this way multiple attachments
* can be included. :thumbsup:
*/
->getTransport();
// Attach Images to transport
foreach ($attachments as $a) {
$transport = $this->addAttachment($transport, $a);
}
// Send transport
$transport->sendMessage();
}
/**
* Add an attachment to the message inside the transport builder.
*
* @param TransportInterface $transportBuilder
* @param array $file Sanitized index from $_FILES
* @return TransportInterface
*/
protected function addAttachment(TransportInterface $transport, array $file): TransportInterface
{
$part = $this->createAttachment($file);
$transport->getMessage()->addPart($part);
return $transport;
}
/**
* Create an zend mime part that is an attachment to attach to the email.
*
* This was my usecase, you'll need to edit this to your own needs.
*
* @param array $file Sanitized index from $_FILES
* @return Part
*/
protected function createAttachment(array $file): Part
{
$ext = '.' . explode('/', $file['type'])[1];
$fileName = md5(uniqid(microtime()), true) . $ext;
$attachment = new Part($this->file->read($file['tmp_name']));
$attachment->disposition = Zend_Mime::TYPE_OCTETSTREAM;
$attachment->encoding = Zend_Mime::ENCODING_BASE64;
$attachment->filename = $fileName;
return $attachment;
}
}
MessageInterface::getBody
firma del método muestra un tipo de retorno de cadena. Puede que tenga que cavar en su TransportInterface
objeto, pero puedo decirle que el addPart
método existe en un Zend\Mime\Message
objeto. Dado que magento probablemente extendió esa clase para su propia Message
clase, creo que sería inteligente intentarlo$transport->getMessage()->addpart($part);
Como se mencionó en las respuestas anteriores, magento2 no tiene una función lista para usar para enviar correos con archivos adjuntos.
No sé si es una mejor práctica, pero podría llamar directamente a la Zend_Mail
clase para hacerlo, sin crear una función personalizada y anular Magento\Framework\Mail\Template\TransportBuilder
, como se muestra a continuación
$mail = new \Zend_Mail('utf-8');
$mail->setFrom($senderEmail);
$mail->addTo($receiverEmail);
$mail->setSubject($subject);
$mail->setBodyHtml($text);
$content = file_get_contents($attachmentAbsolutePath);
$attachment = new \Zend_Mime_Part($content);
$attachment->type = 'text/xml'; // attachment's mime type
$attachment->disposition = \Zend_Mime::DISPOSITION_ATTACHMENT;
$attachment->encoding = \Zend_Mime::ENCODING_BASE64;
$attachment->filename = $filename;
$mail->addAttachment($attachment);
$mail->send();