3

Admin -> Stores -> Configuration -> Sales -> Sales Email -> Order -> Disabled

Where should I look and which module or modal to send the same email programmatically?

Update

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$order = $objectManager->create('\Magento\Sales\Model\Order')->load($orderId);

$emailSender = $objectManager->create('\Magento\Sales\Model\Order\Email\Sender\OrderSender');
$emailSender->send($order);

If I Admin -> Stores -> Configuration -> Sales -> Sales Email -> Order -> Disabled the above code doesn't trigger the email. Or if I enable, it send 2 email. I don't want the email that magento trigger for order confirmation. I want to do it.

1
  • Hello @iamkdev, it will send admin too? May 30, 2018 at 14:00

5 Answers 5

6

Look at Magento\Sales\Model\Order\Email\Sender\OrderSender. This is where you'll find the method to send the order confirmation for a given order.

1

Another solution without influencing Magento Core functionality (which happens when using a plugin) would be to inject a custom OrderIdentity that will always return true for isEnabled.

I tried out the solution on Magento OSS ver. 2.4.2-p1.

First, you extend \Magento\Sales\Model\Order\Email\Container\OrderIdentity and just return true for isEnabled. Alhtough, extending should be kept to a minimum, I think it is ok in this case, as we won't override the original class with a preference. We will just use it as a argument in di.xml.

app/code/Vendor/YourModule/Model/Order/Email/Container/EnabledOrderIdentity.php:

<?php

declare(strict_types=1);

namespace Vendor\YourModule\Model\Order\Email\Container;

/**
 * An order identity that will ignore the configuration for sales_email/order/enabled.
 */
class EnabledOrderIdentity extends \Magento\Sales\Model\Order\Email\Container\OrderIdentity
{
    /**
     * Always return true and do not consider config options
     *
     * @return bool
     */
    public function isEnabled(): bool
    {
        return true;
    }
}

Now, as we have our custom identity that won't care when sales_email/order/enabled is disabled, we can create a virtual type that replaces the identityContainer argument for OrderSender with our custom one. This virtual type can be used as argument for places where the injected OrderSender should be able to send emails without paying attention to the sales_email/order/enabled` setting.

app/code/Vendor/YourModule/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">
    <!-- Virtual OrderSender type that ignores order email disable setting -->
    <virtualType name="Vendor\YourModule\Model\Order\Email\Sender\OrderSender"
                 type="Magento\Sales\Model\Order\Email\Sender\OrderSender">
        <arguments>
            <argument name="identityContainer" xsi:type="object">Vendor\YourModule\Model\Order\Email\Container\EnabledOrderIdentity</argument>
        </arguments>
    </virtualType>

    <!-- Example usage -->
    <type name="Class\Where\You\Want\Custom\OrderSender\Test">
        <arguments>
            <argument name="orderSender" xsi:type="object">Vendor\YourModule\Model\Order\Email\Sender\OrderSender</argument>
        </arguments>
    </type>
</config>

In the class where you want to programmatically send the email while sales_email/order/enabled is set to disabled, must use constructor injection (instead of ObjectManager) to inject your custom OrderSender.

This can look like the following example:

<?php

declare(strict_types=1);

namespace Class\Where\You\Want\Custom\OrderSender;

use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order\Email\Sender\OrderSender;

class Test {
    /**
     * @var OrderRepositoryInterface
     */
    private OrderRepositoryInterface $orderRepository;
    
    /**
     * @var OrderSender
     */
    private OrderSender $orderSender;

    /**
     * Index constructor.
     *
     * @param OrderRepositoryInterface $orderRepository
     * @param OrderSender $orderSender
     */
    public function __construct(
        OrderRepositoryInterface $orderRepository,
        OrderSender $orderSender
    ) {
        $this->orderRepository = $orderRepository;
        $this->orderSender = $orderSender;
    }

    public function someFunction() {
        $order = $this->orderRepository->get(8); // Your logic to get the order
        $this->orderSender->send($order); // Order sender has custom identity that ignores settings
    }
}
0

Simply you can use below code to send order email

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();        
$order = $objectManager->create('\Magento\Sales\Model\Order')->load($orderId);
$order->setCanSendNewEmailFlag(true);
$order->save();
$session = $objectManager->create('\Magento\Checkout\Model\Session');
$session->setForceOrderMailSentOnSuccess(true);
$emailSender = $objectManager->create('\Magento\Sales\Model\Order\Email\Sender\OrderSender');
$emailSender->send($order);

You should not use the ObjectManager directly!

0

A hacky script to force send order confirmation emails, used to recover when some SMTP connection errors occurred.

Don't use object manager or bootstrap magento like this in production code.

<?php
use Magento\Framework\App\Bootstrap;
require __DIR__ . '/app/bootstrap.php';
$bootstrap = Bootstrap::create(BP, $_SERVER);
$obj = $bootstrap->getObjectManager();
$state = $obj->get(Magento\Framework\App\State::class);
$state->setAreaCode('frontend');
$obj->get(\Magento\Store\Model\App\Emulation::class)->startEnvironmentEmulation(1, 'frontend'); # replace with store id

$incrementIds = [
    '123456789',
];

$counter = 1;
foreach ($incrementIds as $incrementId) {
    echo str_pad((string)$counter, 3, " ", STR_PAD_LEFT) . " - $incrementId - " ;
    $order = $obj->create(\Magento\Sales\Model\Order::class);
    $order->loadByIncrementId($incrementId);
    if (!$order->getId()) {
        echo "DOES NOT EXIST" . PHP_EOL;
        continue;
    }

    $orderSender = $obj->create(\Magento\Sales\Model\Order\Email\Sender\OrderSender::class);
    $orderSender->send($order);
    $counter++;
    echo "SENT" . PHP_EOL;
}

echo "DONE" . PHP_EOL;
-7

I created an around plugin for the send function OrderSender and check my custom condition. Now it works for me.

5
  • 1
    Can you please share your plugin code? we have same issue. Jul 4, 2017 at 13:29
  • 1
    The point of the stackexchange.com is to share information and solutions to the problem. @iamkdev could you please share your code.
    – knospe
    Jan 30, 2018 at 9:31
  • Hello @iamkdev, it will send admin too? May 30, 2018 at 12:22
  • 2
    Adding a comment and not sharing the code how can this be the accepted answer? Atleast show some code to prove it Mar 24, 2019 at 19:00
  • Can you share the code..?? Mar 20, 2020 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.