Magento 2: ส่งอีเมลพร้อมไฟล์แนบ


คำตอบ:


19

M2 ไม่ได้มาพร้อมกับกล่อง แต่มันเป็นคุณสมบัติที่สร้างขึ้นในกรอบ zend นี่คือข้อมูลอ้างอิงที่ดีเกี่ยวกับวิธีเพิ่มฟังก์ชันนี้ใน magento: https://blog.bitexpert.de/blog/sending-mails-with-attachments-in-magento-2/

ในกรณีที่ลิงค์ตายให้สร้างสิ่งต่อไปนี้

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

จากนั้นเพิ่มไปยัง 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>

ตอนนี้คุณสามารถใช้ได้addAttachment()ทั่วทั้งไซต์ของคุณ


8
ฉันยังคงสงสัยว่าทำไม Magento TransportBuilder ไม่มีวิธีนี้
Murtuza Zabuawala

4
เราจะแนบไฟล์ใน magento อีเมลที่กำหนดเอง 2.3 ได้อย่างไร? เพราะมันใช้ zendframework 2 และคำตอบนี้ไม่ทำงานอีกต่อไป
Manish Maheshwari

3
จะส่งอีเมลพร้อมไฟล์แนบใน Magento 2.3 ได้อย่างไร
Dhaduk Mitesh

@ManishMaheshwari & Mitesh คุณมีทางออกหรือไม่
Sameer Bhayani

1
โซลูชันนี้ไม่ทำงานใน Magento2.3 อีกต่อไป ใครบ้างมีทางเลือกสำหรับสิ่งที่แนบมา?
nishu

8

ในฐานะของวีโอไอพี 2.2.7 การแก้ปัญหาที่อธิบายไว้ข้างต้นไม่ทำงานอีกต่อไปตั้งแต่ลดลงขยาย\Magento\Framework\Mail\Message เพื่อหลีกเลี่ยงการขาดวิธีง่ายๆในการเพิ่มสิ่งที่แนบผ่านตัวสร้างการขนส่ง (ซึ่งปัจจุบันดูเหมือนจะเป็นสถานที่ที่ถูกต้องสำหรับฟังก์ชั่นดังกล่าว) เราจำเป็นต้องสร้างสิ่งทดแทนสำหรับ TransportBuilder และใช้งาน:\Zend_Mail
\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;
    }
}

อย่าลืมที่จะมาแทนที่เดิมโดยการดำเนินการของคุณผ่านทาง\Magento\Framework\Mail\Template\TransportBuilderdi.xml

โปรดทราบว่าการใช้งานนี้อาจจะแตกออกด้วยการเปิดตัววีโอไอพีที่\Magento\Framework\Mail\MessageInterface::setBody()กำลังจะเลิกใช้และอาจถูกลบออกในไม่ช้า

HTH


Hi! คุณมีเมธอด addAttachment ในรหัสของคุณ แต่คุณโทรหาที่ไหน ฉันไม่เห็นมัน
Nikolai Silin

ขอบคุณ! ฉันเพิ่มการวนลูปไปที่เมธอดการจัดเตรียมข้อความและงานที่ไม่สิ้นสุด
Nikolai Silin

@NikolaiSilin วิธีส่ง png หรือไฟล์อื่น ๆ
sumeet bajaj

1

Magento 2 อีเมลที่กำหนดเองจากโมดูลไม่มีภาพที่แนบมา

ถ้าคุณต้องการใช้สิ่งที่แนบภาพกับแม่แบบอีเมลใน Magento 2 คุณต้องแทนที่คลาสMagento \ Framework \ Mail \ Template \ TransportBuilder

Magento Out-of-box ไม่มีคุณสมบัติไฟล์แนบสำหรับอีเมล คุณสามารถอ้างอิงบล็อกเพื่อส่งไฟล์แนบรูปภาพโดยละเอียด

คุณต้องเพิ่มตรรกะเช่นวิธีด้านล่าง

 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
คุณสามารถช่วยให้ประสบความสำเร็จใน magento 2.3 ได้หรือไม่?
Sameer Bhayani

สร้างไฟล์แนบด้วยวิธีนี้จนถึง 2.2.7 2.2.8 และ 2.3+ ไม่ทำงาน
Matthias Kleine

ฉันเพิ่งโพสต์คำตอบสำหรับ 2.3.x @MatthiasKleine
domdambrogia

สวัสดีฉันจะแนบถ้าฉันมีสตริงการเข้ารหัส base64 ได้อย่างไร
Ketan Borada

1

นี่คือคำตอบที่สมบูรณ์แบบในการส่งไฟล์ PDF ในอีเมล์ใน 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();

สวัสดีมันกำลังโยนข้อผิดพลาดร้ายแรง: ข้อผิดพลาดที่ไม่ได้บันทึก: การเรียกไปยังฟังก์ชันสมาชิก generateMessage () บน null
gajjala sandeep

คุณกำลังสร้างข้อความใหม่ที่ไม่จำเป็นเมื่อการขนส่งของคุณมีข้อความอยู่แล้ว ทำไมไม่เพียงเพิ่มส่วนหนึ่งในสถานที่? สิ่งนี้ยุ่งและยากที่จะติดตาม ไม่พูดถึงคุณเพิ่มงานและหน่วยความจำที่จำเป็นในการแก้ปัญหานี้เป็นสองเท่า
domdambrogia

1

Magento 2.3.x เข้ากันได้:

นี่คือคำตอบของฉันสำหรับ Magento 2.3 เนื่องจากนี่เป็นคำถามยอดนิยมใน google และดูเหมือนว่าจะมีผู้คนจำนวนมากในความคิดเห็นที่กำลังมองหา

ดูเหมือนจะมีความปรารถนาอย่างมากในการโพสต์อื่น ๆ เกี่ยวกับการเขียนทับTransportBuilderคลาสเริ่มต้นผ่านทางetc/di.xmlแต่โมดูลที่ฉันทำงานมีขนาดเล็กจนฉันไม่ต้องการให้รับผิดชอบในการเริ่มต้นTransportBuilderดังนั้นฉันจึงสร้างคลาส Helper (ควร อาจเป็นรูปแบบขึ้นอยู่กับว่าเป็นแม่แบบอีเมลที่ประกาศไว้ - แต่ฉันพูดนอกเรื่อง)

TransportBuilderไม่ได้มีการเข้าถึงของประชาชนไปTransportInterfaceแต่แทนที่จะสร้างทุกโคลนแล้วรีเซ็ตสร้าง ฉันพบว่าการสร้างTransportInterfaceอินสแตนซ์ของฉันนั้นง่ายขึ้นแล้วแนบPartวัตถุที่แนบมากับข้อความของการขนส่ง หากคุณพบว่าจำเป็นต้องเขียนทับค่าเริ่มต้นTransportBuilderผ่านการตั้งค่าการฉีดพึ่งพาต้องระวังเกี่ยวกับการปรับปรุงวิธีการสาธารณะ อย่าลืมฝึกOเมื่อเก็บรหัสของคุณไว้อย่างมั่นคง !

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

ฉันไม่สามารถทำงานได้อย่างถูกต้องฉันมักจะได้รับการยกเว้นว่า "ข้อผิดพลาดที่ไม่ได้รับ: การเรียกใช้ฟังก์ชั่นสมาชิก addPart () บนสายอักขระ" ... ความคิดใด ๆ : /
hallleron

1
@ hallleron ผิดปกติพอนี้แตกต่างจากที่ฉันได้รับ แต่ดูเหมือนว่าคุณถูกต้อง MessageInterface::getBodyลายเซ็นวิธีแสดงให้เห็นถึงผลตอบแทนประเภทสตริง คุณอาจต้องขุดในTransportInterfaceวัตถุของคุณแต่ฉันสามารถบอกคุณได้ว่าaddPartวิธีการที่มีอยู่ในZend\Mime\Messageวัตถุ ตั้งแต่วีโอไอพีมีแนวโน้มที่จะขยายชั้นเรียนสำหรับชั้นเรียนของตัวเองMessageฉันคิดว่ามันคงจะดีถ้าลอง$transport->getMessage()->addpart($part);
domdambrogia

0

ดังที่ได้กล่าวไปแล้วในคำตอบก่อนหน้า magento2 ไม่มีฟังก์ชั่นนอกการใช้งานเพื่อส่งอีเมลพร้อมไฟล์แนบ

ฉันไม่รู้ว่านี่เป็นวิธีปฏิบัติที่ดีที่สุดหรือไม่ แต่คุณสามารถโทรหาZend_Mailชั้นเรียนได้โดยตรงโดยไม่ต้องสร้างฟังก์ชั่นที่กำหนดเองและลบล้างMagento\Framework\Mail\Template\TransportBuilderเช่นด้านล่าง

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

ก่อนที่จะให้ -1 ก็แนะนำให้ใช้ความคิดเห็น textarea นี้จากนั้นทุกคนสามารถเข้าใจสิ่งที่ผิดขอบคุณ
LucScu

$ transport-> getMessage () -> setBody ($ bodypart);
imtiazau

รับข้อผิดพลาดที่ไม่ได้รับ: โทรหาวิธีที่ไม่ได้กำหนด Magento \\ Framework \\ Mail \\ EmailMessage :: setBody ()
imtiazau

ความคิดเห็นเหล่านี้ไม่เกี่ยวข้องกับคำตอบ
LucScu

ฉันได้รับข้อผิดพลาดนี้ใน magento 2.3.3
imtiazau
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.