作者 邓超

自动回复

  1 +<?php
  2 +
  3 +
  4 +require_once "../vendor/autoload.php";
  5 +
  6 +
  7 +/**
  8 + * 自动回复
  9 + * @author:dc
  10 + * @time 2025/7/2 9:58
  11 + * Class fob_ai_mail_auto_reply
  12 + */
  13 +class fob_ai_mail_auto_reply {
  14 +
  15 +
  16 + public $isStop = false;
  17 +
  18 +
  19 + /**
  20 + * @var \Lib\Db
  21 + */
  22 + public $fob_db;
  23 +
  24 + /**
  25 + * @var \Lib\Db
  26 + */
  27 + public $db;
  28 +
  29 +
  30 + public $startTime = 0;
  31 +
  32 + /**
  33 + * SyncToEsCmd constructor.
  34 + */
  35 + public function __construct()
  36 + {
  37 + $this->db = db();
  38 + $this->fob_db = fob_mysql();
  39 +
  40 + $handler = function ($signal){
  41 + _echo('收到进程信号 '. $signal);
  42 + // 可以处理其他程序
  43 + $this->isStop = true;
  44 + };
  45 + pcntl_signal(SIGTERM, $handler); // 这个是kill
  46 + pcntl_signal(SIGINT, $handler); // 这个是 ctrl+c
  47 +
  48 + $this->startTime = time();
  49 + }
  50 +
  51 +
  52 + /**
  53 + * @return bool
  54 + */
  55 + public function isStop(): bool
  56 + {
  57 + // 检查是否接收到信号
  58 + pcntl_signal_dispatch();
  59 +
  60 + // 是否超过来最大执行时间
  61 + if(time()-43200 > $this->startTime){
  62 + return true;
  63 + }
  64 +
  65 + return $this->isStop;
  66 + }
  67 +
  68 +
  69 + public function handler(){
  70 +
  71 +
  72 + while (!$this->isStop()){
  73 +
  74 + $id = redis()->lPop('new_mail_ids');
  75 + if($id){
  76 + // 检查是否到时间了
  77 + list($did,$time) = explode('.',$id);
  78 + if($time > time()){
  79 + redis()->rPush('new_mail_ids',$id);
  80 + usleep(10000);
  81 + continue;
  82 + }
  83 + // 查询数据
  84 + $data = $this->db->throw()->first(\Model\listsSql::first('`id` = '.$did,'`id`,`folder_id`,`email_id`,`subject`,`is_hots`,`from`,`udate`'));
  85 + if($data && !$data['is_hots']){
  86 + // 不是屏蔽的
  87 + $body = getBodyHtml(getMailBody($data['id']));
  88 + if(isAiAutoMail($data['from'],$data['subject'],$body)===0){
  89 + // 在检查下是否是 收件箱
  90 + if($this->db->value(\Model\folderSql::has(['id'=>$data['folder_id'],'origin_folder'=>'INBOX']))){
  91 +
  92 + // 检查 是否开启了自动回复
  93 + list($postid,$source) = $this->getPostid($data['email_id']);
  94 + if($source == 2){
  95 + $email = $this->db->throw()->first(\Model\emailSql::first($data['email_id']));
  96 + // 配置
  97 + $replySetting = $this->getAutoReplySetting($postid,$email['email']);
  98 + if($replySetting){
  99 + // 有配置才回复
  100 + $this->log([$data,$replySetting]); // 立即写入日志
  101 + \Lib\Mail\MailFun::sendEmail([
  102 + 'subject' => 'Re:'.$data['subject'],
  103 + 'tos' => [['email'=>$data['from'],'name'=>explode('@',$data['from'])[0]]],
  104 + 'body' => $this->trimBody($replySetting['content'],$body)
  105 + ],$email);
  106 + }
  107 +
  108 + }
  109 +
  110 + }
  111 + }
  112 + }
  113 +
  114 + }else{
  115 + sleep(1);
  116 + }
  117 + }
  118 +
  119 + }
  120 +
  121 + public function trimBody($reply,$inbox){
  122 + $reply = explode('</body>',$reply,2);
  123 +
  124 + return $reply[0]."<pre>{$inbox}</pre>".($reply[1]??'');
  125 + }
  126 +
  127 +
  128 + public function log($msg){
  129 + logs($msg,LOG_PATH.'fob_ai_mail_auto_reply.log')->write(); // 立即写入日志
  130 + }
  131 +
  132 + /**
  133 + * 读取自动回复的配置
  134 + * @param $postid
  135 + * @param $email
  136 + * @return false|mixed
  137 + * @author:dc
  138 + * @time 2025/7/2 11:22
  139 + */
  140 + public function getAutoReplySetting($postid,$email){
  141 + $sets = $this->fob_db->throw()->all("select * from `ai_mail_auto_reply_setting` where ".dbWhere([
  142 + 'postid' => $postid
  143 + ]));
  144 + if(!$sets){
  145 + return false;
  146 + }
  147 +
  148 + foreach ($sets as $set){
  149 + $set['emails'] = @json_decode($set['emails'],true);
  150 + // 是否开启了
  151 + if($set['emails']&&(in_array($email,$set['emails'])||in_array('所有邮箱',$set['emails']))){
  152 + // 必须设置了内容
  153 + if($set['content']){
  154 + $set['week'] = @json_decode($set['week'],true);
  155 + // 是否满足周
  156 + if(!$set['week'] || in_array(date('w'),$set['week'])){
  157 + $hi = date('H:i');
  158 + // 是否跨天
  159 + if ($set['day2day']){
  160 + // 跨天设置
  161 + if($hi > $set['s_hour'] || $hi < $set['e_hour']){
  162 + return $set;
  163 + }
  164 + }else{
  165 + // 非夸天
  166 + if($hi > $set['s_hour'] && $hi < $set['e_hour']){
  167 + return $set;
  168 + }
  169 + }
  170 + }
  171 + }
  172 + }
  173 + }
  174 +
  175 + return false;
  176 + }
  177 +
  178 +
  179 + /**
  180 + * 项目id
  181 + * @author:dc
  182 + * @time 2025/5/20 15:44
  183 + */
  184 + public function getPostid($email_id){
  185 +
  186 + // 没有找到历史,就找绑定表
  187 + $data = redis()->getSet('fob_bind_mail:'.$email_id,300,function ($email_id){
  188 + return $this->fob_db->throw()->first("select `post_id`,`source` from `e_mail_binds` where `email_id` = '{$email_id}' and `deleted_at` is null order by `id` desc limit 1");
  189 + },$email_id);
  190 +
  191 + return [
  192 + $data['post_id']??0,
  193 + $data['source']??0,
  194 + ];
  195 + }
  196 +
  197 +
  198 +
  199 +}
  200 +
  201 +(new fob_ai_mail_auto_reply())->handler();
  202 +
  203 +return 1;
  1 +这个目录是存放fob那边的脚本
  2 +
  3 +* fob_ai_mail_auto_reply.php 文件是ai邮件自动回复脚本
@@ -532,6 +532,9 @@ class SyncMail { @@ -532,6 +532,9 @@ class SyncMail {
532 // 新邮件标记 532 // 新邮件标记
533 if($item->getFolderName() == 'INBOX' && !$data['is_hots']){ 533 if($item->getFolderName() == 'INBOX' && !$data['is_hots']){
534 redis()->incr('have_new_mail_'.$this->emailId(),120); 534 redis()->incr('have_new_mail_'.$this->emailId(),120);
  535 + // 新邮件id,丢入redis
  536 + redis()->rPush('new_mail_ids',$id.'.'.(time()+120));
  537 +
535 // 通知 538 // 通知
536 if(stripos(trim($data['subject']),'re:')===0){ 539 if(stripos(trim($data['subject']),'re:')===0){
537 // 通知黑格 2024-08-22 新上 这个是异步的不会阻塞当前进程 540 // 通知黑格 2024-08-22 新上 这个是异步的不会阻塞当前进程