Magento 2: invia e-mail con allegato


Risposte:


19

M2 non viene fornito immediatamente, ma è una funzionalità integrata nel framework zend. Ecco un buon riferimento su come aggiungere questa funzionalità in magento: https://blog.bitexpert.de/blog/sending-mails-with-attachments-in-magento-2/

Se il collegamento si interrompe, creare quanto segue

<?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;
    }
}

quindi aggiungere 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>

Ora puoi utilizzare addAttachment()tutto il tuo sito.


8
Mi chiedo ancora perché magento TransportBuilder non abbia questo metodo
Murtuza Zabuawala,

4
Come possiamo allegare file nell'e-mail personalizzata magento 2.3? perché usa zendframework 2 e questa risposta non funziona più
Manish Maheshwari,

3
Come inviare e-mail con allegato in Magento 2.3?
Dhaduk Mitesh il

@ManishMaheshwari & Mitesh Hai la soluzione?
Sameer Bhayani,

1
Questa soluzione non funziona più in Magento2.3. Qualcuno ha un'alternativa per l'attaccamento.?
nishu,

8

A partire da Magento 2.2.7 le soluzioni sopra descritte non funzionano più da quando \Magento\Framework\Mail\Messagesono state estese \Zend_Mail.
Per evitare la mancanza di un modo semplice per aggiungere allegati tramite il generatore di trasporto (che attualmente sembra essere il posto corretto per tale funzione), è necessario creare un sostituto per TransportBuilder e utilizzare \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;
    }
}

Non dimenticare di sostituire l'originale \Magento\Framework\Mail\Template\TransportBuildercon l'implementazione tramite di.xml.

Nota che questa implementazione probabilmente si interromperà con una prossima versione di Magento poiché \Magento\Framework\Mail\MessageInterface::setBody()è obsoleta e potrebbe essere rimossa a breve.

HTH


Ciao! Hai un metodo addAttachment nel tuo codice, ma dove li hai chiamati? Non lo vedo
Nikolai Silin,

Grazie! Ho aggiunto un ciclo per preparare il metodo Message e tutto funziona.
Nikolai Silin,

@NikolaiSilin come inviare un png o altri file.
sumeet bajaj,

1

Magento 2 E-mail personalizzata dal modulo, non fornisce immagini allegate.

Se si desidera utilizzare l'allegato immagine con i modelli di posta elettronica in Magento 2, è necessario sostituire la classe, Magento \ Framework \ Mail \ Template \ TransportBuilder

Magento Out-of-box non fornisce funzionalità di allegato per e-mail. Puoi fare riferimento ai blog per inviare allegati di immagini in dettaglio,

Devi aggiungere la logica come sotto,

 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;
    }

1
Puoi aiutarci a raggiungere lo stesso in Magento 2.3?
Sameer Bhayani,

Ha creato allegati in questo modo fino al 2.2.7. 2.2.8 e 2.3+ non funzionano
Matthias Kleine,

Ho appena pubblicato una risposta per 2.3.x @MatthiasKleine
domdambrogia

ciao, come posso collegarmi se ho una stringa di codifica base64?
Ketan Borada,

1

Ecco la risposta perfetta per inviare pdf in e-mail in 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();

Ciao, sta generando un errore fatale: Errore non rilevato: chiamata a una funzione membro generateMessage () su null
gajjala sandeep

Stai creando un nuovo messaggio che non è necessario quando il tuo trasporto ha già un messaggio. Perché non aggiungere semplicemente una parte a quella in atto? Questo è disordinato e difficile da seguire. Per non parlare del fatto che stai raddoppiando il lavoro e la memoria necessari per risolvere questo problema.
domdambrogia,

1

Magento 2.3.x compatibile:

Questa è stata la mia risposta per Magento 2.3 poiché questa era una delle domande principali su Google e sembra che ci siano molte persone nei commenti alla ricerca.

Sembra che ci sia molto desiderio in altri post di sovrascrivere la TransportBuilderclasse predefinita tramite etc/di.xml, tuttavia il modulo su cui sto lavorando è così piccolo che non voglio che sia responsabile per il valore predefinito, TransportBuilderquindi ho creato una classe Helper (dovrei probabilmente sarà un modello basato su quanto è accoppiato al modello di email dichiarato - ma sto divagando).

The TransportBuildernon ha accesso pubblico a TransportInterface, ma genera sempre un clone ogni volta e quindi reimposta il builder. Ho trovato più semplice creare la mia TransportInterfaceistanza e quindi collegare i miei Partoggetti allegato al messaggio del trasporto. Se ritieni necessario sovrascrivere il valore predefinito TransportBuildertramite la preferenza di iniezione di dipendenza, fai attenzione all'aggiornamento dei metodi pubblici. Ricorda di esercitarti con O quando mantieni il tuo codice SOLID !

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;
    }
}

Non riesco a farlo funzionare correttamente, ricevo sempre un'eccezione che dice "Errore non rilevato: chiamata a una funzione membro addPart () su stringa" ... qualche idea al riguardo? : /
hallleron

1
@hallleron Stranamente questo è diverso da quello che stavo ottenendo, ma sembra che tu abbia ragione. La MessageInterface::getBodyfirma del metodo mostra un tipo di ritorno stringa. Potrebbe essere necessario scavare nel tuo TransportInterfaceoggetto, ma posso dirti che il addPartmetodo esiste su un Zend\Mime\Messageoggetto. Dal momento che Magento probabilmente ha esteso quella classe per la propria Messageclasse, penso che sarebbe intelligente provarci$transport->getMessage()->addpart($part);
domdambrogia,

0

Come menzionato nelle risposte precedenti, magento2 non ha una funzione pronta per inviare e-mail con allegati.

Non so se sia una buona pratica, ma potresti chiamare direttamente la Zend_Mailclasse per farlo, senza creare una funzione personalizzata e sovrascrivere Magento\Framework\Mail\Template\TransportBuilder, come di seguito

$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();

prima di dare -1, si consiglia di utilizzare questo commento textarea, quindi tutti potrebbero capire cosa c'è che non va, grazie
LucScu

$ Transport-> getMessage () -> setBody ($ BodyPart);
imtiazau,

ottenere questo errore non rilevato: chiamata al metodo indefinito Magento \\ Framework \\ Mail \\ EmailMessage :: setBody ()
imtiazau

Questi commenti non sono collegati alla risposta
LucScu il

sto ricevendo questo errore in magento 2.3.3
imtiazau il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.