美文网首页
Laravel队列批量发送邮件,限制调用频率 支持QQ邮箱/16

Laravel队列批量发送邮件,限制调用频率 支持QQ邮箱/16

作者: 众神开挂 | 来源:发表于2020-04-20 23:18 被阅读0次

    项目需要使用邮件拓展业务,要用到队列群发的功能,特此记录一下

    为了防止邮件发送过多导致信件发送失败,同时使用了两种解决方法

    1、使用了多个邮箱批量发送邮件

    2、限制了邮件发送任务的调用频率。

    首先创建一个队列任务:

    php artisan make:job SendMail
    

    队列的环境配置请参考laravel的官方文档

    建议在开发环境下将.env中配置为 QUEUE_CONNECTION=sync 方便调试,生产环境下再配置为redis驱动

    <?php
    
    namespace App\Jobs;
    
    use Illuminate\Bus\Queueable;
    use Illuminate\Queue\SerializesModels;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    use Illuminate\Support\Facades\Log;
    use Illuminate\Support\Facades\Mail;
    use Illuminate\Support\Facades\Redis;
    
    class SendMail implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
        protected $content;
        protected $email;
        protected $user;
        protected $job_id;
        public $timeout =120;  //120秒超时
    
        /**
         * Create a new job instance.
         *
         * @param $job_id
         * @param $content
         * @param $email
         * @param $user
         */
        public function __construct($job_id, $content, $email, $user)
        {
            $this->content = $content;
            $this->email = $email;
            $this->user = $user;
            $this->job_id = $job_id;
        }
    
        /**
         * Execute the job.
         * @return void
         */
        public function handle()
        {
            //限制任务的调用:每20秒钟只调用10次
           Redis::throttle('key')->allow(10)->every(20)->then(function () {
                try {
                    $this->handleEmail();//具体的发送邮件方法
                } catch (\Exception $e) {
                    Log::error('queue error : ' . $e->getMessage());//打印错误日志
                }
            }, function () {
                return $this->release(10);
            });
        }
    
        /**
         * 发送邮件
         */
        function handleEmail()
        {
            //备份原有Mailer
            $backup = Mail::getSwiftMailer();
            $user = $this->user; //获取用户的姓名
            $email = $this->email;//获取用户的邮箱地址
            $content = $this->content;//获取邮件模板的内容
            //使用正则表达式替换相应的用户的姓名
            $email_content = preg_replace('/\{\{s\}\}/', $user->name, $content->content);  //模板内容
            $email_theme = preg_replace('/\{\{s\}\}/', $user->name, $content->theme); //邮件主题
            $email_sign = preg_replace('/\{\{s\}\}/', $user->name, $content->sign);;  //邮件签名
            $email_sign = preg_replace('/\{\{t\}\}/', date('Y-m-d'), $email_sign);;  //邮件签名{{t}}
    
            // 设置邮箱账号,支持qq邮箱/163邮箱/谷歌邮箱/腾讯企业邮箱
            if ($email->type == 'qq') {
                $transport = new \Swift_SmtpTransport('smtp.qq.com', 465, 'ssl');
            } else if ($email->type == 'gmail') {
                $transport = new \Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl');
            }  else if ($email->type == '163') {
                $transport = new \Swift_SmtpTransport('smtp.163.com', 465, 'ssl');
            } else if ($email->type == 'exmail') {
                $transport = new \Swift_SmtpTransport('smtp.exmail.qq.com', 465, 'ssl');
            } else {
                throw  new AdminApiException('邮箱类型不支持!');
            }
            $transport->setUsername($email->email);
            $transport->setPassword($email->secret);
    
            $mailer = new \Swift_Mailer($transport);
    
            Mail::setSwiftMailer($mailer);
    
            Mail::send('emails.kol.index',
                ['content' => $email_content, 'email_sign' => $email_sign],
                function ($message) use ($email_theme, $user, $email) {
                    $message->from($email->email, $email->email);
                    $message->subject($email_theme);
                    $message->to($user->email);
                });
            // 发送后还原
            Mail::setSwiftMailer($backup);
        }
    }
    
    

    由于限制了队列的调用频率,所以任务失败的次数是无法计算的,需要配合超时来做

    我将任务超时时间设置为120秒

    队列的调用

    public function store(Request $request)
    {
        ..........
        foreach ($job->user as $user) {
            $email = $emails->random(); //随机一个邮箱
            //传递邮件的模板、邮箱和用户作为一个单独的发送任务
            SendMail::dispatch($job_id, $template, $email, $user);
        }
    }
    

    相关文章

      网友评论

          本文标题:Laravel队列批量发送邮件,限制调用频率 支持QQ邮箱/16

          本文链接:https://www.haomeiwen.com/subject/regsihtx.html