| 
 | 
 | 
 <?php
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 use Model\folderSql;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 require_once "../vendor/autoload.php";
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 /**
 | 
| 
 | 
 | 
  * 预热自动回复
 | 
| 
 | 
 | 
  * @author:dc
 | 
| 
 | 
 | 
  * @time 2025/7/2 9:58
 | 
| 
 | 
 | 
  * Class fob_ai_mail_auto_reply
 | 
| 
 | 
 | 
  */
 | 
| 
 | 
 | 
 class fob_hot_ai_mail_auto_reply {
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public $isStop = false;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * @var \Lib\Db
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public $db;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public $startTime = 0;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * SyncToEsCmd constructor.
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function __construct()
 | 
| 
 | 
 | 
     {
 | 
| 
 | 
 | 
         $this->db = db();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         $handler = function ($signal){
 | 
| 
 | 
 | 
             _echo('收到进程信号 '. $signal);
 | 
| 
 | 
 | 
             // 可以处理其他程序
 | 
| 
 | 
 | 
             $this->isStop = true;
 | 
| 
 | 
 | 
         };
 | 
| 
 | 
 | 
         pcntl_signal(SIGTERM, $handler); // 这个是kill
 | 
| 
 | 
 | 
         pcntl_signal(SIGINT, $handler); // 这个是 ctrl+c
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         $this->startTime = time();
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * @return bool
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function isStop(): bool
 | 
| 
 | 
 | 
     {
 | 
| 
 | 
 | 
         // 检查是否接收到信号
 | 
| 
 | 
 | 
         pcntl_signal_dispatch();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         // 是否超过来最大执行时间
 | 
| 
 | 
 | 
         if(time()-43200 > $this->startTime){
 | 
| 
 | 
 | 
             return true;
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return $this->isStop;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     protected $bodys = [];
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function getDelayTime(){
 | 
| 
 | 
 | 
         /**
 | 
| 
 | 
 | 
          * 随机一个延时时间秒 极小的概率30-60分钟,小概率60-120分钟,中概率120-180分钟 大概率180-240分钟
 | 
| 
 | 
 | 
          */
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 // 生成一个 0 到 100 之间的随机数
 | 
| 
 | 
 | 
         $randomValue = rand(0, 100);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         // 根据随机值的范围来决定延迟时间
 | 
| 
 | 
 | 
         if ($randomValue < 5) { // 5% 的概率
 | 
| 
 | 
 | 
             // 随机 30-60分钟
 | 
| 
 | 
 | 
             $rand = rand(45, 60) * 60; // 转换为秒
 | 
| 
 | 
 | 
         } elseif ($randomValue < 15) { // 10% 的概率 (5% + 10%)
 | 
| 
 | 
 | 
             // 随机 60-120分钟
 | 
| 
 | 
 | 
             $rand = rand(65, 120) * 60; // 转换为秒
 | 
| 
 | 
 | 
         } elseif ($randomValue < 45) { // 30% 的概率 (15% + 30%)
 | 
| 
 | 
 | 
             // 随机 120-180分钟
 | 
| 
 | 
 | 
             $rand = rand(125, 180) * 60; // 转换为秒
 | 
| 
 | 
 | 
         } else { // 55% 的概率 (45% + 55%)
 | 
| 
 | 
 | 
             // 随机 180-240分钟
 | 
| 
 | 
 | 
             $rand = rand(180, 240) * 60; // 转换为秒
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return time()+$rand;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function handler(){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         $this->bodys = file_get_contents(__DIR__."/body.reply");
 | 
| 
 | 
 | 
         $this->bodys = explode("--------------",$this->bodys);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         while (!$this->isStop()){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             $id = redis()->lPop('new_hot_mail_auto_reply_ids');
 | 
| 
 | 
 | 
             if($id){
 | 
| 
 | 
 | 
                 // 检查是否到时间了
 | 
| 
 | 
 | 
                 list($did,$time)  = explode('.',((string) $id).'.0');
 | 
| 
 | 
 | 
                 if($time == '0'){
 | 
| 
 | 
 | 
                     redis()->rPush('new_hot_mail_auto_reply_ids',$id.'.'.$this->getDelayTime());
 | 
| 
 | 
 | 
                     continue;
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
                 if($time > time()){
 | 
| 
 | 
 | 
                     redis()->rPush('new_hot_mail_auto_reply_ids',$id);
 | 
| 
 | 
 | 
                     usleep(10000);
 | 
| 
 | 
 | 
                     continue;
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
                 // 查询数据
 | 
| 
 | 
 | 
                 $data = $this->db->first(\Model\listsSql::first('`id` = '.$did,'`id`,`email_id`,`subject`,`is_hots`,`from`,`udate`,`uid`'));
 | 
| 
 | 
 | 
                 if($data && $data['is_hots']){
 | 
| 
 | 
 | 
                     // 在检查下是否是 收件箱
 | 
| 
 | 
 | 
                     if($this->db->cache(3600)->value(\Model\folderSql::has(['id'=>$data['folder_id'],'origin_folder'=>'INBOX']))){
 | 
| 
 | 
 | 
                         _echo('处理 '.$data['id']);
 | 
| 
 | 
 | 
                         $email = $this->db->throw()->cache(3600)->first(\Model\emailSql::first($data['email_id']));
 | 
| 
 | 
 | 
                         // 标记已读
 | 
| 
 | 
 | 
                         $mailInstance = \Lib\Imap\ImapPool::get((new \Lib\Imap\ImapConfig($email)));
 | 
| 
 | 
 | 
                         if($mailInstance->login()){
 | 
| 
 | 
 | 
                             $mailInstance->folder('INBOX')->msg()->uid($data['uid'])->seen();
 | 
| 
 | 
 | 
                             $mailInstance = null;
 | 
| 
 | 
 | 
                         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                         // 来回超过5次就不回了
 | 
| 
 | 
 | 
                         if(substr_count($data['subject'],"Re:") < 3){
 | 
| 
 | 
 | 
 // 有配置才回复
 | 
| 
 | 
 | 
                             $ret = \Lib\Mail\MailFun::sendEmail([
 | 
| 
 | 
 | 
                                 'subject'   =>  'Re:'.$data['subject'],
 | 
| 
 | 
 | 
                                 'tos'   =>  [['email'=>$data['from'],'name'=>explode('@',$data['from'])[0]]],
 | 
| 
 | 
 | 
                                 'body'  => $this->trimBody($data,$data['subject']),
 | 
| 
 | 
 | 
                                 'mail-header' => [
 | 
| 
 | 
 | 
                                     'Aicc-Hot-Mail' =>  'hot' // 预热邮件
 | 
| 
 | 
 | 
                                 ]
 | 
| 
 | 
 | 
                             ],$email);
 | 
| 
 | 
 | 
                             _echo('回复成功'.$data['id']." ".$email['email'].' to '.$data['from']." ".$ret[1]);
 | 
| 
 | 
 | 
                         }else{
 | 
| 
 | 
 | 
                             _echo('来回超过5次就不回了 '.$data['id']);
 | 
| 
 | 
 | 
                         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             }else{
 | 
| 
 | 
 | 
                 sleep(1);
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function trimBody($data,$inbox){
 | 
| 
 | 
 | 
         // 随机body内容
 | 
| 
 | 
 | 
         $reply = $this->bodys[array_rand($this->bodys)];
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return "<pre>------------------ 原始邮件 ------------------
 | 
| 
 | 
 | 
 发件人: {$data['from']};
 | 
| 
 | 
 | 
 发送时间: ".date("Y年m月d日 H:i",$data['udate'])."
 | 
| 
 | 
 | 
 收件人: {$data['to']};
 | 
| 
 | 
 | 
 主题: {$data['subject']}
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 {$inbox}</pre>".$reply;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 (new fob_ai_mail_auto_reply())->handler();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 return 1; | 
 | 
 | 
\ No newline at end of file | 
...
 | 
...
 | 
 |