Simple use of redis to send mail asynchronously

Keywords: PHP Redis Database github

Are you also stuck in redis, knowing why it is, and how to use it? A simple example of using message queues to send messages asynchronously under yii

Preparations for redis~~

First of all, you have to configure redis service. I have written some articles about redis service before. You can refer to them here. https://segmentfault.com/a/11...

yii's redis library: https://github.com/yiisoft/yi...

Using composer to install redis dependency Libraries

php composer.phar require --prefer-dist yiisoft/yii2-redis

Relevant configuration of web.php:

return [
    //....
    'components' => [
        'redis' => [
            'class' => 'yii\redis\Connection',
            'hostname' => 'localhost',
            'port' => 6379,
            'database' => 0,
        ],
    ]
];

At this point, redis can be used to operate in yii

redis ~ ~ synchronization and asynchronization

So how to achieve asynchronous message queue to send mail?

The traditional method of operation is as follows:

  1. User Input Mail Information

  2. The server obtains the data input by the user and submits it to the third party's mail server.

  3. Third Party Mail Server Sends Mail and Returns Processing Result

Asynchronous processing mail sending:

  1. Users enter mail-related information

  2. Store registration information in memory queue to inform the user of successful sending

  3. The server monitors the memory queue and sends the mail data in the memory queue in turn which is not perceived by the user.

What's the difference between the two?

Asynchronism is better than synchronization because the page is non-blocking and reduces the user's waiting time experience.

redis ~ ~ mail delivery

Principle:
Users input mail information, servers receive the incoming mail information and call the mail process, which is actually the process of assigning mail class attributes. At this time, we can grab the user's information, store it in the queue, and then read the mail information in turn, and send it.

 //Instantiate mail components

$mailer = Yii::$app->mailer->compose();
$mailer->setFrom('sender address');
$mailer->setTo('Addressee address');
$mailer->setSubject('Send title');
//if ($mailer->send() && $this->reg($data, 'regbymail')) {
//Note that this itself is a direct call to the send method for sending and now override the parent method for processing with redis 
if ($mailer->queue()) {
    return true;
}

At this time, we will instantiate the mail class to send mail. At this time, we can grab the mail information and store it in the queue.

    <?php
    namespace mail\mailerqueue;
    use Yii;
    class Message extends \yii\swiftmailer\Message
    {
        /*Grab mail messages to redis queue*/
        public function queue()
        {
            $redis = Yii::$app->redis;
            if (empty($redis)) {
                throw new \yii\base\InvalidConfigException('redis not found in config.');
            }
            // 0 - 15  select 0 select 1
            // db => 1
            $mailer = Yii::$app->mailer;
            //Does the database stored in mail exist?
            if (empty($mailer) || !$redis->select($mailer->db)) {
                throw new \yii\base\InvalidConfigException('db not defined.');
            }
            //Grabbing Mail Information
            $message = [];
            $message['from'] =array_keys($this->from);
            $message['to'] =  array_keys($this->getTo());
            $message['cc'] =  array_keys($this->getCc());
            $message['bcc'] = array_keys($this->getBcc());
            $message['reply_to'] = array_keys($this->getReplyTo());
            $message['charset'] = array_keys($this->getCharset());
            $message['subject'] = array_keys($this->getSubject());
            //Get mail information and sub-information
            $parts = $this->getSwiftMessage()->getChildren();
    
            if (!is_array($parts) || !sizeof($parts)) {
                $parts = [$this->getSwiftMessage()];
            }
            foreach ($parts as $part) {
    
                if (!$part instanceof \Swift_Mime_Attachment) {
                    //Get the content type
                    switch($part->getContentType()) {
                        case 'text/html':
                            $message['html_body'] = $part->getBody();
                            break;
                        case 'text/plain':
                            $message['text_body'] = $part->getBody();
                            break;
                    }
                    if (!$message['charset']) {
                        $message['charset'] = $part->getCharset();
                    }
                }
            }
            //The serialized fetched content is stored in the queue
            
            return $redis->rpush($mailer->key, json_encode($message));
        }
    }

 //The next step is to read the redis queue and send it. 
<?php
namespace mail\mailerqueue;
use Yii;

class MailerQueue extends \yii\swiftmailer\Mailer
{
    public $messageClass = "doctorjason\mailerqueue\Message";
    public $key = 'mails';
    public $db = '1';
    /*Send mail*/
    public function process()
    {
        $redis = Yii::$app->redis;
        if (empty($redis)) {
            throw new \yii\base\InvalidConfigException('redis not found in config.');
        }
        //If there is data in the queue
        if ($redis->select($this->db) && $messages = $redis->lrange($this->key, 0, -1)) {
            $messageObj = new Message;
            //Traveling through mailing lists
            foreach ($messages as $message) {
                $message = json_decode($message, true);
                if (empty($message) || !$this->setMessage($messageObj, $message)) {
                    throw new \ServerErrorHttpException('message error');
                }
                if ($messageObj->send()){
                    $redis->lrem($this->key, -1, json_encode($message));
                }
            }
        }
        return true;
    }

    //Setting up message headers
    public function setMessage($messageObj, $message) 
    {
        if (empty($messageObj)) {
            return false;
        }
        if (!empty($message['from']) && !empty($message['to'])) {
            $messageObj->setFrom($message['from'])->setTo($message['to']);
            if (!empty($message['cc'])) {
                $messageObj->setCc($message['cc']);
            }
            if (!empty($message['bcc'])) {
                $messageObj->setBcc($message['bcc']);
            }
            if (!empty($message['reply_to'])) {
                $messageObj->setReplyTo($message['reply_to']);
            }
            if (!empty($message['charset'])) {
                $messageObj->setCharset($message['charset']);
            }
            if (!empty($message['subject'])) {
                $messageObj->setSubject($message['subject']);
            }
            if (!empty($message['html_body'])) {
                $messageObj->setHtmlBody($message['html_body']);
            }
            if (!empty($message['text_body'])) {
                $messageObj->setTextBody($message['text_body']);
            }
            return $messageObj;
        }
        return false;
    }
}   

So far we have implemented redis queue to send mail asynchronously

Posted by Archy on Tue, 18 Jun 2019 13:07:54 -0700