Magento 2 Order Confirmation Email Send Programatically from Success.php

The question:

I have disabled Order Confirmation Email from backend because I want to send Order Email when User redirect to Success.phtml after order successfully placed.

I have created Plugins for it
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="MagentoCheckoutBlockOnepageSuccess" type="<vendor_name>CheckoutBlockOnepageSuccess"/>
    <type name="MagentoSalesModelOrderEmailSender">
        <plugin name="sale_order_custom_email_send" type="<vendor_name>CheckoutModelPluginSender" sortOrder="1" />
    </type>
    <type name="MagentoSalesModelOrderEmailSenderOrderSender">
        <plugin name="sale_order_sender_custom_email" type="<vendor_name>CheckoutModelPluginOrderSender" sortOrder="1" />
    </type>
</config>

Created Around Plugin: OrderSender.php

<?php

namespace <vendor_name>CheckoutModelPlugin;

use MagentoSalesModelOrder;

class OrderSender
{
    /**
     * Order success action.
     *
     * @return MagentoFrameworkControllerResultInterface
     */
    public function aroundSend(MagentoSalesModelOrderEmailSenderOrderSender $subject, Closure $proceed, Order $order, $forceSyncMode = false, $isCustom = false)
    {
       $order->setSendEmail(true);
        if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
            if ($this->checkAndSend($order, $isCustom)) {
                $order->setEmailSent(true);
                $this->orderResource->saveAttribute($order, ['send_email', 'email_sent']);
                return true;
            }
        }

        $this->orderResource->saveAttribute($order, 'send_email');

        return false;
   }
}

I have passed $isCustom parameter in checkAndSend() method so It can check my custom condition.

Second Plugin : Sender.php

<?php

namespace <vendor_name>CheckoutModelPlugin;

class Sender
{
    /**
     * Order success action.
     *
     * @return MagentoFrameworkControllerResultInterface
     */
    protected function aroundCheckAndSend(MagentoSalesModelOrderEmailSender $subject, Closure $proceed, Order $order, $isCustom = false)
    {
       $this->identityContainer->setStore($order->getStore());
        if (!$this->identityContainer->isEnabled() && $isCustom = false) {
            return false;
        }
        $this->prepareTemplate($order);

        /** @var SenderBuilder $sender */
        $sender = $this->getSender();

        try {
            $sender->send();
            $sender->sendCopyTo();
        } catch (Exception $e) {
            $this->logger->error($e->getMessage());
        }

        return true;
   }
}

If $isCustom is true then even if Order Confirmation is Disabled from backend It should send Order Confirmation Email to customer.

Don’t Know where am I wrong but not getting any email. May be We can not create a plugin for Absract class’s Protected method but any other solution to change condition in checkAndSend().

Any help would be appreciated.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

As you specified in your question that you have disabled Order Confirmation email from backend, I have assumed the same and write code in such a way that email will not sent twice even if you have enabled Order Confirmation email from backend. So, Order Confirmation Email will only sent from success page when you have disabled it from backend.

To send email on order success page, we need to bind observer with event checkout_onepage_controller_success_action. Here, We write our code send mail. To assure that email is not sent twice, I have created plugin for isEnable() method of OrderIdentity.php class from Magento_Sales module.

First, you need to register event using events.xml. Check the below code.

[Package_Name][Module_Name]etcfrontendevents.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_onepage_controller_success_action">
        <observer name="checkout_onepage_controller_success_action_sendmail" instance="[Package_Name][Module_Name]ObserverSendMailOnOrderSuccess" />
    </event>
</config>

After registering event, We will create Observer Class.

[Package_Name][Module_Name]ObserverSendMailOnOrderSuccess.php

<?php

namespace [Package_Name][Module_Name]Observer;

use MagentoFrameworkEventObserverInterface;

class SendMailOnOrderSuccess implements ObserverInterface
{
    /**
     * @var MagentoSalesModelOrderFactory
     */
    protected $orderModel;

    /**
     * @var MagentoSalesModelOrderEmailSenderOrderSender
     */
    protected $orderSender;

    /**
     * @var MagentoCheckoutModelSession $checkoutSession
     */
    protected $checkoutSession;

    /**
     * @param MagentoSalesModelOrderFactory $orderModel
     * @param MagentoSalesModelOrderEmailSenderOrderSender $orderSender
     * @param MagentoCheckoutModelSession $checkoutSession
     *
     * @codeCoverageIgnore
     */
    public function __construct(
        MagentoSalesModelOrderFactory $orderModel,
        MagentoSalesModelOrderEmailSenderOrderSender $orderSender,
        MagentoCheckoutModelSession $checkoutSession
    )
    {
        $this->orderModel = $orderModel;
        $this->orderSender = $orderSender;
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param MagentoFrameworkEventObserver $observer
     * @return void
     */
    public function execute(MagentoFrameworkEventObserver $observer)
    {
        $orderIds = $observer->getEvent()->getOrderIds();
        if(count($orderIds))
        {
            $this->checkoutSession->setForceOrderMailSentOnSuccess(true);
            $order = $this->orderModel->create()->load($orderIds[0]);
            $this->orderSender->send($order, true);
        }
    }
}

After adding observer, order cofirmation email will sent on order success page, if we have enabled order confirmation email from Stores > Configuration > Sales > Sales Email > Order. But, now order confirmation sent twice if we enable this field. So, we need to create plugin to avoid this scenario.

To create plugin, you need to use di.xml.

[Package_Name][Module_Name]etcdi.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="MagentoSalesModelOrderEmailContainerOrderIdentity">
        <plugin name="change_is_enable_method" type="[Package_Name][Module_Name]PluginSalesOrderEmailContainerOrderIdentityPlugin"/>
    </type>
</config>

[Package_Name][Module_Name]PluginSalesOrderOrderEmailContainer
OrderIdentityPlugin.php

<?php

namespace [Package_Name][Module_Name]PluginSalesOrderEmailContainer;

class OrderIdentityPlugin
{
    /**
     * @var MagentoCheckoutModelSession $checkoutSession
     */
    protected $checkoutSession;

    /**
     * @param MagentoCheckoutModelSession $checkoutSession
     *
     * @codeCoverageIgnore
     */
    public function __construct(
        MagentoCheckoutModelSession $checkoutSession
    )
    {
        $this->checkoutSession = $checkoutSession;
    }

    /**
     * @param MagentoSalesModelOrderEmailContainerOrderIdentity $subject
     * @param callable $proceed
     * @return bool
     */
    public function aroundIsEnabled(MagentoSalesModelOrderEmailContainerOrderIdentity $subject, callable $proceed)
    {
        $returnValue = $proceed();

        $forceOrderMailSentOnSuccess = $this->checkoutSession->getForceOrderMailSentOnSuccess();
        if(isset($forceOrderMailSentOnSuccess) && $forceOrderMailSentOnSuccess)
        {
            if($returnValue)
                $returnValue = false;
            else
                $returnValue = true;

            $this->checkoutSession->unsForceOrderMailSentOnSuccess();
        }

        return $returnValue;
    }
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment