Magento 2: envoyer un e-mail avec pièce jointe


Réponses:


19

M2 n'est pas livré avec, mais c'est une fonctionnalité intégrée au framework zend. Voici une bonne référence pour ajouter cette fonctionnalité dans magento: https://blog.bitexpert.de/blog/sending-mails-with-attachments-in-magento-2/

Dans le cas où le lien devient mort, créez ce qui suit

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

puis ajoutez à 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>

Maintenant, vous pouvez utiliser addAttachment()tout au long de votre site.


8
Je me demande toujours pourquoi magento TransportBuilder n'a pas cette méthode
Murtuza Zabuawala

4
Comment pouvons-nous joindre un fichier dans un e-mail personnalisé magento 2.3? parce que son utilisation de zendframework 2 et cette réponse ne fonctionne plus
Manish Maheshwari

3
Comment envoyer un e-mail avec pièce jointe dans Magento 2.3?
Dhaduk Mitesh

@ManishMaheshwari & Mitesh Avez-vous la solution?
Sameer Bhayani

1
Cette solution ne fonctionne plus dans Magento2.3. Quelqu'un at-il une alternative pour l'attachement.?
nishu

8

Depuis Magento 2.2.7, les solutions décrites ci-dessus ne fonctionnent plus depuis l' \Magento\Framework\Mail\Messageextension abandonnée \Zend_Mail.
Pour contourner le manque d'un moyen facile d'ajouter des pièces jointes via le constructeur de transport (qui semble actuellement être le bon endroit pour une telle fonction), il faut créer un remplacement pour TransportBuilder et utiliser \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;
    }
}

N'oubliez pas de remplacer l'original \Magento\Framework\Mail\Template\TransportBuilderpar votre implémentation via di.xml.

Notez que cette implémentation rompra probablement avec une prochaine version de Magento car elle \Magento\Framework\Mail\MessageInterface::setBody()est obsolète et peut être supprimée bientôt.

HTH


Salut! Vous avez une méthode addAttachment dans votre code, mais où les avez-vous appelés? Je ne le vois pas.
Nikolai Silin

Merci! J'ai ajouté une boucle à la méthode prepareMessage et à tous les travaux.
Nikolai Silin

@NikolaiSilin comment envoyer un png ou d'autres fichiers.
sumeet bajaj

1

Magento 2 Courriel personnalisé du module, ne fournit pas de pièce jointe d'image.

Si vous souhaitez utiliser la pièce jointe Image avec des modèles d'e-mail dans Magento 2, vous devez remplacer la classe, Magento \ Framework \ Mail \ Template \ TransportBuilder

Magento Out-of-box ne fournit pas de fonction de pièce jointe pour les e-mails. Vous pouvez parrainer des blogs pour envoyer des images jointes en détail,

Vous devez ajouter une logique comme ci-dessous,

 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
Pouvez-vous aider à réaliser la même chose dans magento 2.3?
Sameer Bhayani

Création de pièces jointes de cette manière jusqu'au 2.2.7. 2.2.8 et 2.3+ ne fonctionnent pas
Matthias Kleine

Je viens de poster une réponse pour 2.3.x @MatthiasKleine
domdambrogia

bonjour, comment puis-je attacher si j'ai une chaîne de codage base64?
Ketan Borada du

1

Voici la réponse parfaite pour envoyer un pdf par e-mail dans 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();

Salut, Il lance une erreur fatale: Erreur non interceptée: appel à une fonction membre generateMessage () sur null
gajjala sandeep

Vous créez un nouveau message qui n'est pas nécessaire lorsque votre transport a déjà un message. Pourquoi ne pas simplement ajouter une pièce à celle en place? C'est compliqué et difficile à suivre. Sans oublier que vous doublez le travail et la mémoire nécessaires pour résoudre ce problème.
domdambrogia

1

Compatible avec Magento 2.3.x:

Ce fut ma réponse pour Magento 2.3 car c'était une question majeure sur Google et il semble y avoir beaucoup de gens dans les commentaires.

Il semble y avoir beaucoup de désir dans d'autres articles sur le remplacement de la TransportBuilderclasse par défaut viaetc/di.xml , mais le module sur lequel je travaille est si petit que je ne veux pas qu'il soit responsable de la valeur par défaut TransportBuilder, j'ai donc construit une classe Helper (devrait être probablement un modèle basé sur la façon dont il est couplé au modèle d'e-mail déclaré - mais je m'écarte).

Le TransportBuildern'a pas d'accès public à TransportInterface, mais génère à la place un clone à chaque fois, puis réinitialise le générateur. J'ai trouvé plus facile de créer mon TransportInterfaceinstance, puis d'attacher mes Partobjets attachés au message du transport. Si vous trouvez nécessaire d'écraser la valeur TransportBuilderpar défaut via la préférence d'injection de dépendance, faites attention à la mise à jour des méthodes publiques. N'oubliez pas de pratiquer le O lorsque vous gardez votre code SOLIDE !

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

Je n'arrive pas à le faire fonctionner correctement, j'ai toujours une exception disant "Erreur non interceptée: appel à une fonction membre addPart () sur la chaîne" ... une idée à ce sujet? : /
hallleron

1
@hallleron Curieusement, c'est différent de ce que je recevais, mais il semble que vous ayez raison. La MessageInterface::getBodysignature de méthode montre un type de retour de chaîne. Vous devrez peut-être fouiller dans votre TransportInterfaceobjet, mais je peux vous dire que la addPartméthode existe sur un Zend\Mime\Messageobjet. Puisque magento a probablement étendu cette classe pour leur propre Messageclasse, je pense qu'il serait intelligent d'essayer$transport->getMessage()->addpart($part);
domdambrogia

0

Comme mentionné dans les réponses précédentes, magento2 n'a pas de fonction prête à l'emploi pour envoyer des e-mails avec des pièces jointes.

Je ne sais pas si c'est une meilleure pratique, mais vous pouvez appeler directement la Zend_Mailclasse pour le faire, sans créer de fonction personnalisée et remplacer Magento\Framework\Mail\Template\TransportBuilder, comme ci-dessous

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

avant de donner -1, il est suggéré par donc d'utiliser ce commentaire textarea, alors tout le monde pourrait comprendre ce qui ne va pas, thx
LucScu

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

obtenir cette erreur non interceptée: appel à une méthode non définie Magento \\ Framework \\ Mail \\ EmailMessage :: setBody ()
imtiazau

Ces commentaires ne sont pas liés à la réponse
LucScu

je reçois cette erreur dans magento 2.3.3
imtiazau
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.