Magento 2: E-Mail mit Anhang senden

Antworten:

19

M2 ist nicht im Lieferumfang enthalten, es ist jedoch eine Funktion, die in das zend-Framework integriert ist. Hier ist eine gute Referenz, wie man diese Funktionalität in Magento hinzufügt: https://blog.bitexpert.de/blog/sending-mails-with-attachments-in-magento-2/

Wenn der Link nicht mehr funktioniert, erstellen Sie Folgendes

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

Fügen Sie dann zu etc / di.xml hinzu

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

Jetzt können Sie addAttachment()auf Ihrer gesamten Website verwenden.

Xenocide8998
quelle
8
Ich frage mich immer noch, warum magento TransportBuilder diese Methode nicht hat
Murtuza Zabuawala
4
Wie können wir eine Datei in Custom Email Magento 2.3 anhängen? weil es zendframework 2 verwendet und diese Antwort nicht mehr funktioniert
Manish Maheshwari
3
Wie versende ich eine E-Mail mit Anhang in Magento 2.3?
Dhaduk Mitesh
@ManishMaheshwari & Mitesh Hast du die Lösung?
Sameer Bhayani
1
Diese Lösung funktioniert nicht mehr in Magento2.3. Hat jemand eine Alternative zur Bindung?
Nishu
7

Ab Magento 2.2.7 funktionieren die oben beschriebenen Lösungen nicht mehr, da \Magento\Framework\Mail\Messagedie Erweiterung entfällt \Zend_Mail.
Um das Fehlen einer einfachen Möglichkeit zum Hinzufügen von Anhängen über den Transport Builder (der derzeit der richtige Ort für eine solche Funktion zu sein scheint) zu umgehen, müssen Sie einen Ersatz für den TransportBuilder erstellen und Folgendes verwenden \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;
    }
}

Vergessen Sie nicht, das Original \Magento\Framework\Mail\Template\TransportBuilderdurch Ihre Implementierung über zu ersetzen di.xml.

Beachten Sie, dass diese Implementierung wahrscheinlich mit einem bevorstehenden Release von Magento \Magento\Framework\Mail\MessageInterface::setBody()abbricht, da es veraltet ist und möglicherweise bald entfernt wird.

HTH

Jean-Bernard Valentaten
quelle
Hallo! Sie haben eine Methode addAttachment in Ihrem Code, aber wo haben Sie sie aufgerufen? Ich sehe es nicht
Nikolai Silin
Vielen Dank! Ich habe loop zur prepareMessage-Methode hinzugefügt und alles funktioniert.
Nikolai Silin
@NikolaiSilin wie man ein PNG oder andere Dateien sendet.
Sumeet Bajaj
1

Magento 2 Benutzerdefinierte E-Mail vom Modul, Bietet keinen Bildanhang.

Wenn Sie einen Bildanhang mit E-Mail-Vorlagen in Magento 2 verwenden möchten, müssen Sie die Klasse Magento \ Framework \ Mail \ Template \ TransportBuilder überschreiben

Magento Out-of-Box bietet keine Anhangsfunktion für E-Mails. Sie können Blogs zum Senden von Bildanhängen in Details verweisen,

Sie müssen Logik wie unten hinzufügen,

 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;
    }
Rakesh Jesadiya
quelle
1
Können Sie dazu beitragen, dasselbe in Magento 2.3 zu erreichen?
Sameer Bhayani
Auf diese Weise erstellte Anhänge bis 2.2.7. 2.2.8 und 2.3+ funktionieren nicht
Matthias Kleine
Ich habe gerade eine Antwort für 2.3.x @MatthiasKleine
domdambrogia
Hallo, wie kann ich anhängen, wenn ich Base64-Codierungszeichenfolge habe?
Ketan Borada
1

Hier ist die perfekte Antwort, um ein PDF in E-Mail in magetno 2.3 zu senden

$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();
Jignesh Patel
quelle
Hallo, es wird ein schwerwiegender Fehler
ausgelöst: Nicht abgefangener
Sie erstellen eine neue Nachricht, die nicht erforderlich ist, wenn Ihr Transport bereits eine Nachricht enthält. Warum nicht einfach einen Teil zu dem vorhandenen hinzufügen? Das ist chaotisch und schwer zu verfolgen. Ganz zu schweigen davon, dass Sie die Arbeit und den Arbeitsspeicher verdoppeln müssen, um dieses Problem zu lösen.
Domdambrogia
0

Wie in den vorherigen Antworten erwähnt, verfügt magento2 nicht über eine sofort einsatzbereite Funktion zum Versenden von E-Mails mit Anhängen.

Ich weiß nicht, ob es sich um eine bewährte Methode handelt, aber Sie können direkt Zend_Mailclass aufrufen , um dies zu tun, ohne eine benutzerdefinierte Funktion zu erstellen und zu überschreiben Magento\Framework\Mail\Template\TransportBuilder(siehe unten)

$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();
LucScu
quelle
Bevor -1 angegeben wird, wird empfohlen, dieses Kommentartextfeld zu verwenden, damit jeder versteht, was falsch ist, danke
LucScu
$ transport-> getMessage () -> setBody ($ bodyPart);
Imtiazau
Abrufen dieses nicht erfassten Fehlers: Aufruf der undefinierten Methode Magento \\ Framework \\ Mail \\ EmailMessage :: setBody ()
imtiazau
Diese Kommentare beziehen sich nicht auf die Antwort
LucScu
Ich erhalte diesen Fehler in Magento 2.3.3
Imtiazau
0

Magento 2.3.x kompatibel:

Dies war meine Antwort für Magento 2.3, da dies eine Top-Frage bei Google war und es scheint, dass viele Leute in den Kommentaren suchen.

Es scheint , über das Überschreiben der Standard viel Lust in anderen Beiträgen zu sein TransportBuilderKlasse über etc/di.xml, aber das Modul I auf mich arbeiten , ist so klein , dass ich will nicht , dass es für die Standard verantwortlich seinTransportBuilder , damit ich eine Helper - Klasse gebaut (sollte wahrscheinlich ein Modell basierend darauf, wie gekoppelt es mit der deklarierten E-Mail-Vorlage ist - aber ich schweife ab).

Der TransportBuilderhat keinen öffentlichen Zugriff auf den TransportInterface, sondern generiert stattdessen jedes Mal einen Klon und setzt dann den Builder zurück. Ich fand es einfacher, meine TransportInterfaceInstanz zu erstellen und dann meine Anhangsobjekte Partan die Nachricht des Transports anzuhängen . Wenn Sie den Standardwert TransportBuilderüber die Abhängigkeitsinjektionseinstellung überschreiben müssen , müssen Sie die öffentlichen Methoden sorgfältig aktualisieren. Denken Sie daran, das O zu üben, wenn Sie Ihren Code SOLID halten !

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;
    }
}
Domdambrogie
quelle
Ich kann es nicht richtig zum Laufen bringen. Ich bekomme immer eine Ausnahme mit der Meldung "Uncaught Error: Aufruf einer Member-Funktion addPart () on string" ... Hast du eine Idee dazu? : /
Hallleron
1
@hallleron Seltsamerweise ist das anders als das, was ich bekommen habe, aber es sieht so aus, als hättest du recht. Die MessageInterface::getBodyMethodensignatur zeigt einen Stringrückgabetyp. Möglicherweise müssen Sie in Ihrem TransportInterfaceObjekt herumgraben, aber ich kann Ihnen sagen, dass die addPartMethode für ein Zend\Mime\MessageObjekt vorhanden ist. Da Magento wahrscheinlich diese Klasse für sich erweitertMessage Klasse, ich glaube , es klug wäre , zu versuchen$transport->getMessage()->addpart($part);
domdambrogia