Yii 2 Console
Scheduled Console Action (Emailing)

Create command in Yii console ([app]/commands/MailController.php):

file /commands/MailController.php
namespace app\commands;
use yii\console\Controller;
 
class MailController extends Controller {
 
    public function actionSend() {
       // Code here to send the mail
       // Example details: http://www.yiiframework.com/doc-2.0/yii-swiftmailer-mailer.html
       Yii::$app->mailer->compose('contact/html', ['contactForm' => $form])
          ->setFrom('from@domain.com')
          ->setTo($form->email)
          ->setSubject($form->subject)
          //->setTextBody($this->body)  // optionally set data here
          ->send();
    } 
    ...
}

Run this command from CLI:

C:\WAMP\WWW\ACME\>yii mail/send

Run a crontab job calling a task in Yii2. Eg: /etc/cron.daily/send-email

#!/bin/bash
## script: /etc/cron.daily/send-email
##
 
#-----------------------------
# Define Yii2 Source Directory
#-----------------------------
SOURCEDIR="/var/www/acme"
 
#-----------------------------
# Run Yii2 Action
#-----------------------------
/usr/bin/php -f $SOURCEDIR/yii mail/send
 
## Log operation
echo "Daily Email Reminder Completed: $(date)" >> /var/log/yii2.log
#mail root@localhost -s "Daily Email Reminder Completed"

Or create task directly in /etc/crontab. For example, run a command every 5 min:

*/5 * * * * /var/www/[yiiroot]/yii mail/send
Running Console Action from Web View

Let us assume the following command controller for our console action:

...
class EmailNotificationController extends Controller
{
    public function actionSendEmail($dstEmail, $workOrderId)
    {
       ...
    }
}

Console actions are typically called directly from the command line. Eg: For a command send-email in console controller [app]/commands/email-notification, we run it at the console as follows:

$ yii email-notification/send-email dstEmail='info@acme.com' workOrderId=1

Sometimes we need to call this command from the web side, in order to avoid duplicate functionality, to automate the process, or simply when a command shell is not available with a hosting provider.

Method 1

To enable this, create a new action in a web controller to call the console action:

use app\commands\EmailNotificationController;
...
class WorkOrderController extends Controller
{
    ...
 
    public function actionSendEmail($id)
    {
        // use app\commands\EmailNotificationController;   // add this include to file
        // "test" is a placeholder with no effect (required though)
        $command = new EmailNotificationController("test", "test");   
        $command->actionSendEmail('info@acme.com', $id);  // $dstEmail, $workOrderId
        ...
        Yii::$app->session->setFlash('success', "Sent Email");
        return $this->redirect(['view', 'id' => $id]);
    }
}    

Call the action from the view as usual:

...
<?php
//
// [app]/views/work-order/view.php
//
?>
<?= Html::a(Yii::t('app', 'Notify by Email'), 
  ['work-order/send-email', 'id' => $model->id], 
  ['class' => 'btn btn-primary']) 
?>
...

Define STDIN and STDOUT in the console action:

namespace app\commands;
 
use Yii;
use yii\console\Controller;
use app\models\Email;
use app\models\WorkOrder;
use yii\helpers\Console;
 
/**
 * 
 */
class EmailNotificationController extends Controller
{
    /**
     * This command send email message.
     * @param string $message the message to be echoed.
     */
    public function actionSendEmail($dstEmail, $workOrderId)
    {
        // NOTE: Define these for the console app to work correctly
        // when called from web controller.
        defined('STDIN')  or define('STDIN',  fopen('php://stdin',  'r'));
        defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));
        ...
    }
}

See: http://stackoverflow.com/questions/10151887/how-to-call-a-console-command-in-web-application-action-in-yii

Method 2

Alternatively, you can use a component to do similar work:

// File  : [app]/common/components/General.php
// Author: sadaa
// Source: https://github.com/yiisoft/yii2/issues/6853
 
namespace common\components;
 
use Yii;
use yii\base\Component;
use yii\console\Application;
 
class General extends Component
{
    /**
     * Create and return an application instance
     * if the console app doesn't exist we create a new instance
     * otherwise, it returns the existing instance
     *
     * @return null|\yii\base\Module|Application
     */
    public static function switchToConsoleApp()
    {
        $config = self::getConsoleConfig();
        if (!$consoleApp = Yii::$app->getModule($config['id'])) {
            $consoleApp = new Application($config);
        }
 
        // Assuming that switching apps only happens when making console commands through the web app,
        // we have to redefine STDOUT to trick the console output into going straight to the web output
        define('STDOUT', fopen('php://output', 'w'));
 
        return $consoleApp;
    }
 
    public static function runConsoleActionFromWebApp($action, $params = [])
    {
        $webApp     = Yii::$app;
        $consoleApp = self::switchToConsoleApp();
        $result     = ($consoleApp->runAction($action, $params) == \yii\console\Controller::EXIT_CODE_NORMAL);
        Yii::$app   = $webApp;
        return $result;
    }
 
 
    public static function getConsoleConfig()
    {
        return ArrayHelper::merge(
            require(Yii::getAlias('@common/config/main.php')),
            require(Yii::getAlias('@common/config/main-local.php')),
            require(Yii::getAlias('@console/config/main.php')),
            require(Yii::getAlias('@console/config/main-local.php'))
        );
    }
}

In any web controller, we call the console action as follows:

// Example usage within any web controller
SiteController extends \yii\web\Controller
{
    public function actionRbacLoad() 
    {
        General::runConsoleActionFromWebApp('rbac/load');
    }
 
    public function actionMigrate() 
    {
        General::runConsoleActionFromWebApp('migrate', 
            ['migrationPath' => '@console/migrations/', 'interactive' => false]
        );
    }
}

Method 3

/**
 * Class ConsoleAppHelper
 * @package app\components
 */
class ConsoleAppHelper
{
    public static function runAction( $route, $params = [ ], $controllerNamespace = null )
    {
        $origApp = \Yii::$app;
 
        // fcgi doesn't have STDIN and STDOUT defined by default
        defined( 'STDIN' ) or define( 'STDIN', fopen( 'php://stdin', 'r' ) );
        defined( 'STDOUT' ) or define( 'STDOUT', fopen( 'php://stdout', 'w' ) );
 
        /** @noinspection PhpIncludeInspection */
        $config = require( \Yii::getAlias( '@app/config/console.php' ) );
        $consoleApp = new ConsoleApplication( $config );
 
        if (!is_null( $controllerNamespace )) {
            $consoleApp->controllerNamespace = $controllerNamespace;
        }
 
        try {
            // use current connection to DB
            \Yii::$app->set( 'db', $origApp->db );
 
            ob_start();
            $exitCode = $consoleApp->runAction(
                $route,
                array_merge( func_get_arg( 1 ), [ 'interactive' => false, 'color' => false ] )
            );
            $result = ob_get_clean();
 
            \Yii::trace( $result, 'console' );
 
        } catch ( \Exception $e ) {
            \Yii::warning( $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine(), 'console' );
            $exitCode = 1;
        }
        \Yii::$app = $origApp;
 
        return $exitCode;
    }
} 

Call it as:

use app\commands\EmailNotificationController;
use app\components\ConsoleAppHelper;
...
class WorkOrderController extends Controller
{
    ...
 
    public function actionSendEmail($id)
    {
        // use app\components\ConsoleAppHelper;   // add this include to file
        // params: $dstEmail, $workOrderId
        ConsoleAppHelper::runAction( 'email-notification/send-mail', ['info@acme.com', $id] );  
        ...
        Yii::$app->session->setFlash('success', "Sent Email");
        return $this->redirect(['view', 'id' => $id]);
    }
}   

See: https://github.com/yiisoft/yii2/issues/1764