Magento 2: kirim email dengan Lampiran

Jawaban:

19

M2 tidak keluar dari kotak tetapi itu adalah fitur yang dibangun ke dalam kerangka zend. Berikut ini adalah referensi yang bagus bagaimana cara menambahkan fungsi ini ke dalam magento: https://blog.bitexpert.de/blog/sending-mails-with-attachments-in-magento-2/

Jika tautannya mati, buat yang berikut ini

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

lalu tambahkan ke 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>

Sekarang Anda dapat menggunakan addAttachment()seluruh situs Anda.

Xenocide8998
sumber
8
Saya masih bertanya-tanya mengapa magento TransportBuilder tidak memiliki metode ini
Murtuza Zabuawala
4
Bagaimana kita bisa melampirkan file di magento email khusus 2.3? karena menggunakan zendframework 2 dan jawaban ini tidak berfungsi lagi
Manish Maheshwari
3
Bagaimana cara mengirim email dengan lampiran di Magento 2.3?
Dhaduk Mitesh
@ManishMaheshwari & Mitesh Sudah punya solusinya?
Sameer Bhayani
1
Solusi ini tidak lagi berfungsi di Magento2.3. Adakah yang punya alternatif untuk lampiran.?
nishu
8

Pada Magento 2.2.7 solusi yang dijelaskan di atas tidak berfungsi lagi sejak \Magento\Framework\Mail\Messagedijatuhkan \Zend_Mail.
Untuk menghindari kurangnya cara mudah untuk menambahkan lampiran melalui pembangun transportasi (yang saat ini tampaknya menjadi tempat yang tepat untuk fungsi seperti itu), kita perlu membuat pengganti untuk TransportBuilder dan menggunakan \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;
    }
}

Jangan lupa ganti yang asli \Magento\Framework\Mail\Template\TransportBuilderdengan implementasi Anda viadi.xml .

Perhatikan bahwa implementasi ini mungkin akan berakhir dengan rilis Magento yang akan datang \Magento\Framework\Mail\MessageInterface::setBody() sudah usang dan mungkin akan segera dihapus.

HTH

Jean-Bernard Valentaten
sumber
Hai! Anda memiliki metode addAttachment dalam kode Anda, tetapi di mana Anda memanggil mereka? Saya tidak melihatnya.
Nikolai Silin
Terima kasih! Saya menambahkan loop ke metode prepMessage dan karya everithing.
Nikolai Silin
@NikolaiSilin cara mengirim png atau file lainnya.
sumeet bajaj
1

Magento 2 Email khusus dari Modul, Tidak menyediakan lampiran gambar.

Jika Anda ingin menggunakan lampiran gambar dengan templat email di Magento 2 Anda harus menimpa kelas, Magento \ Framework \ Mail \ Template \ TransportBuilder

Magento Out-of-box tidak menyediakan fitur lampiran untuk email. Anda dapat merujuk blog untuk mengirim lampiran gambar secara detail,

Anda perlu menambahkan logika seperti di bawah ini,

 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
sumber
1
Bisakah Anda membantu mencapai yang sama di Magento 2.3?
Sameer Bhayani
Membuat lampiran dengan cara ini hingga 2.2.7. 2.2.8 dan 2.3+ tidak berfungsi
Matthias Kleine
Saya baru saja mengirim jawaban untuk 2.3.x @MatthiasKleine
domdambrogia
halo, bagaimana saya bisa melampirkan jika saya memiliki string encoding base64?
Ketan Borada
1

Inilah jawaban sempurna untuk mengirim pdf dalam Email di 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();
jignesh patel
sumber
Hai, Ini melempar kesalahan fatal: Kesalahan Tidak Tertangkap: Memanggil ke fungsi anggota generateMessage () di null
gajjala sandeep
Anda sedang membuat pesan baru yang tidak perlu saat transportasi Anda sudah memiliki pesan. Mengapa tidak menambahkan saja bagian yang sudah ada? Ini berantakan dan sulit untuk diikuti. Belum lagi Anda menggandakan pekerjaan dan memori yang dibutuhkan untuk menyelesaikan masalah ini.
domdambrogia
0

Seperti disebutkan oleh jawaban sebelumnya, magento2 tidak memiliki fungsi out-of-the-box untuk mengirim email dengan lampiran.

Saya tidak tahu apakah ini adalah praktik terbaik, tetapi Anda dapat memanggil langsung Zend_Mailkelas untuk melakukannya, tanpa membuat fungsi khusus dan menimpanya Magento\Framework\Mail\Template\TransportBuilder, seperti di bawah ini

$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
sumber
sebelum memberi -1, disarankan untuk menggunakan textarea komentar ini, maka semua orang bisa mengerti apa yang salah, thx
LucScu
$ transport-> getMessage () -> setBody ($ bodyPart);
imtiazau
mendapatkan Kesalahan Tidak Tertangkap ini: Panggil ke metode yang tidak ditentukan Magento \\ Framework \\ Mail \\ EmailMessage :: setBody ()
imtiazau
Komentar-komentar ini tidak terkait dengan jawaban
LucScu
saya mendapatkan kesalahan ini di
magento
0

Kompatibel dengan Magento 2.3.x:

Ini adalah jawaban saya untuk Magento 2.3 karena ini adalah pertanyaan teratas di google dan sepertinya ada banyak orang di komentar mencari.

Tampaknya ada banyak keinginan dalam posting lain tentang menimpa TransportBuilderkelas default melalui etc/di.xml, namun modul yang saya kerjakan sangat kecil sehingga saya tidak ingin bertanggung jawab atas defaultTransportBuilder sehingga saya membangun kelas Helper (harus mungkin model yang didasarkan pada bagaimana digabungkan ke template email yang dinyatakan - tapi saya ngelantur).

Tidak TransportBuildermemiliki akses publik ke TransportInterface, tetapi menghasilkan klon setiap kali dan kemudian me-reset pembangun. Saya merasa lebih mudah untuk membangun TransportInterfaceinstance saya dan kemudian melampirkan Partobjek lampiran saya ke pesan transport. Jika Anda merasa perlu untuk menimpa default TransportBuildermelalui preferensi injeksi ketergantungan, berhati-hatilah memperbarui metode publik. Ingatlah untuk berlatih O saat menjaga kode Anda 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;
    }
}
domdambrogia
sumber
Saya tidak bisa membuatnya berfungsi dengan baik, saya selalu mendapatkan pengecualian yang mengatakan "Kesalahan Tidak Tertangkap: Memanggil ke fungsi anggota addPart () di string" ... ada ide tentang itu? : /
hallleron
1
@ Hallleron Anehnya ini berbeda dari yang saya dapatkan, tetapi sepertinya Anda benar. Tanda MessageInterface::getBodytangan metode menunjukkan tipe pengembalian string. Anda mungkin harus menggali di dalam TransportInterfaceobjek Anda , tetapi saya dapat memberitahu Anda bahwa addPartmetode ini ada pada Zend\Mime\Messageobjek. Karena magento kemungkinan memperpanjang kelas itu untuk kelas mereka sendiri Message, saya pikir akan lebih pintar untuk mencoba$transport->getMessage()->addpart($part);
domdambrogia