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?
Дахук Мітеш

@ManishMaheshwari & Mitesh Ви отримали рішення?
Самер Бхаяні

1
Це рішення більше не працює в Magento2.3. Хтось має альтернативу для вкладення.?
nishu

8

Станом на Magento 2.2.7, описані вище рішення більше не працюють, оскільки їх \Magento\Framework\Mail\Messageрозширення поширюється \Zend_Mail.
Щоб обійти відсутність простого способу додавання вкладених файлів через конструктор транспорту (який, здається, зараз є правильним місцем для такої функції), потрібно створити заміну на TransportBuilder і скористатися цим \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\TransportBuilderвашою реалізацією через di.xml.

Зауважте, що ця реалізація, ймовірно, порушиться з майбутнім випуском Magento, оскільки \Magento\Framework\Mail\MessageInterface::setBody()він застарілий і може бути скоро видалений.

HTH


Привіт! У вашому коді є метод addAttachment, але куди ви їх зателефонували? Я цього не бачу.
Микола Сілін

Спасибі! Я додав цикл для підготовкиMessage методу та вічно працюючих.
Микола Сілін

@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?
Самер Бхаяні

Створені вкладення таким чином до 2.2.7. 2.2.8 та 2.3+ не працюють
Маттіас Клейн

Я щойно опублікував відповідь на 2.3.x @MatthiasKleine
domdambrogia

привіт, як я можу приєднати, якщо у мене є рядок кодування base64?
Кетан Борада

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

Привіт, це кидає фатальну помилку: Невдала помилка: Виклик до функції
учасника geneMessage

Ви створюєте нове повідомлення, яке є непотрібним, коли у вашому транспорті вже є повідомлення. Чому б просто не додати частину до тієї на місці? Це безладно і важко дотримуватися. Не кажучи вже про те, що ви подвоюєте роботу та пам'ять, необхідну для вирішення цієї проблеми.
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 () на рядку" ... будь-яка ідея про це? : /
галлерон

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, тоді кожен міг зрозуміти, що не так, thx
LucScu

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

отримання цієї невдалої помилки: виклик не визначеного методу Magento \\ Framework \\ Mail \\ EmailMessage :: setBody ()
imtiazau

Ці коментарі не пов’язані з відповіддю
LucScu

я отримую цю помилку в magento 2.3.3
imtiazau
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.