简体   繁体   中英

Yii2 sending emails in the background

I have a RESTful API which registers a user and later sends an email to that user for account activation. This works just fine but there is a great delay, since my code has to send the account activation email which sometimes takes time. How can I schedule jobs to run later or in the background for that task?

This is what I am doing currently:

actionCreateUser(){

   //HERE REGISTRATION

  if($model->save()){  //successifull registration

    //send email here which takes time
    if($emailsent){
      return ["data"=>true];
     }else{
        return ["data"=>false];
     }
   }

}

Then in the front-end I am checking the response of the POST request which is data(true or false).

How can I send the email in the background?

I had the same problem not so long ago. The solution looks optimal for me.

  1. You should install RabbitMQ message system. In Yii2 you can use webtoucher/yii2-amqp extension.

  2. Define you own message component. Well, you can also redefine mailer component. Your component must send message to our RabbitMQ worker. In your web-application you have to use it instead of normal mailer.

use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\base\ErrorException;
use PhpAmqpLib\Message\AMQPMessage;

use webtoucher\amqp\components\Amqp;

class MessengerComponent extends Component
{

    protected $_recipient;
    protected $_subject;
    protected $_message_view;
    protected $_params;
    protected $_to;

    public function send()
    {

        $msg = [
            'to' => $this->_to,
            'message_view' => $this->_message_view,
            'subject' => $this->_subject,
            'params' => $this->_params,
        ];

        try {
            if(! YII_ENV_TEST)
                Yii::$app->amqp->send('send-message', 'send_message', $msg, Amqp::TYPE_DIRECT);
            return true;
        } catch(\Exception $e) {
            return false;
        }
    }
}
  1. Set up your RabbitMQ worker in your console application of Yii2. Note, that worker is a permanent process but not a request-like. So, you cannot declare mailer component and use it. You have to create mailer object only for a short time. For example, only for one mail. You can do this like that:

     $mailer = Yii::createObject([ 'class' => 'yii\\swiftmailer\\Mailer', 'viewPath' => '@common/mail', 'transport' => [ 'class' => 'Swift_SmtpTransport', 'host' => 'mail.host.domain', 'username' => 'mail username', 'password' => 'mail passwork', 'port' => '465', 'encryption' => 'SSL', ], ]); $mailer ->compose( ['html' => $html, 'text' => $text], $this->params ) ->setFrom([Yii::$app->params['systemEmail'] => Yii::t('app', '{service} email title', [ 'service' => Yii::$app->name] ->setTo($this->email) ->setSubject($this->subject) ->send(); 

as thread implemntation is hard in php I suggest you to: if you need to imediatly send your mail you can write action to send mail and just call it in your self action and don't wait for result and if user didn't got activation mail you can set an option for him to send it again.

you have to use cron jobs options too.by default yii don't implemented cronjobs you can use repository like cron-manager or something like this.just save your information in db and you can set every one minute your cron tab to run.

yii also is implementing queue but it's experimental yet.you can see it here : https://github.com/yiisoft/yii2-queue

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM