作者 邓超

v2 调整

@@ -12,7 +12,7 @@ use Model\emailSql; @@ -12,7 +12,7 @@ use Model\emailSql;
12 use Model\folderSql; 12 use Model\folderSql;
13 use Model\listsSql; 13 use Model\listsSql;
14 use Model\sendJobsSql; 14 use Model\sendJobsSql;
15 - 15 +use function Co\run;
16 16
17 17
18 /** 18 /**
@@ -24,23 +24,9 @@ use Model\sendJobsSql; @@ -24,23 +24,9 @@ use Model\sendJobsSql;
24 class Home extends Base { 24 class Home extends Base {
25 25
26 26
27 - /**  
28 - * 邮件列表 针对aicc应用那边  
29 - * @author:dc  
30 - * @time 2023/2/17 14:12  
31 - */  
32 - public function lists(){  
33 -  
34 - $limit = app()->request('limit',20,['intval','abs']);  
35 -  
36 - $last_id = app()->request('last_id',0,['intval','abs']);  
37 - 27 + private function getFolderIds($email_id){
38 $folder_ids = app()->request('folder_ids',[],['intval','abs']); 28 $folder_ids = app()->request('folder_ids',[],['intval','abs']);
39 29
40 - $udate = app()->request('udate',0,'intval');  
41 -  
42 - $where = ['email_id' => $this->getEmail('id')];  
43 -  
44 foreach ($folder_ids as $k=>$folder_id){ 30 foreach ($folder_ids as $k=>$folder_id){
45 if(!$folder_id){ 31 if(!$folder_id){
46 unset($folder_ids[$k]); 32 unset($folder_ids[$k]);
@@ -55,12 +41,34 @@ class Home extends Base { @@ -55,12 +41,34 @@ class Home extends Base {
55 sprintf( 41 sprintf(
56 "select `id` from `%s` where `email_id` = %d and `origin_folder` = 'INBOX'", 42 "select `id` from `%s` where `email_id` = %d and `origin_folder` = 'INBOX'",
57 folderSql::$table 43 folderSql::$table
58 - ,$where['email_id'] 44 + ,$email_id
59 ) 45 )
60 ); 46 );
  47 +
  48 + $folder_ids = [$folder_ids];
61 } 49 }
  50 +
  51 + return $folder_ids;
  52 + }
  53 +
  54 +
  55 + /**
  56 + * 邮件列表 针对aicc应用那边
  57 + * @author:dc
  58 + * @time 2023/2/17 14:12
  59 + */
  60 + public function lists(){
  61 +
  62 + $limit = app()->request('limit',20,['intval','abs']);
  63 +
  64 + $last_id = app()->request('last_id',0,['intval','abs']);
  65 +
  66 + $udate = app()->request('udate',0,'intval');
  67 +
  68 + $where = ['email_id' => $this->getEmail('id')];
  69 +
62 //目录 70 //目录
63 - $where['folder_id'] = $folder_ids; 71 + $where['folder_id'] = $this->getFolderIds($where['email_id']);
64 72
65 73
66 $sql = "`id` > ".$last_id; 74 $sql = "`id` > ".$last_id;
@@ -83,6 +91,79 @@ class Home extends Base { @@ -83,6 +91,79 @@ class Home extends Base {
83 } 91 }
84 92
85 93
  94 + /**
  95 + * v2 版本
  96 + * 同步规定 时间 之后的邮件
  97 + * @return string
  98 + * @throws \Lib\Err
  99 + * @author:dc
  100 + * @time 2023/8/2 16:19
  101 + */
  102 + public function sync(){
  103 + $emails = web_request_emails();
  104 + $udate = app()->request('udate',0,'intval');
  105 + if(!$udate){
  106 + return '';
  107 + }
  108 +
  109 + // 查询邮箱
  110 + $emails = db()->all(emailSql::all(dbWhere(['email'=>$emails])));
  111 + if(!$emails){
  112 + return '';
  113 + }
  114 +
  115 + // 启用协程来处理
  116 + run(function () use ($emails,$udate){
  117 + foreach ($emails as $email){
  118 + // 读取文件夹
  119 + $fids = $this->getFolderIds($email['id']);
  120 + $folders = db()->all(folderSql::all($email['id']));
  121 + // 循环 文件夹
  122 + foreach ($folders as $folder){
  123 + // 是否在同步请求中
  124 + if(in_array($folder['id'],$fids)){
  125 + // 启动 协程
  126 + go(function () use ($email,$udate,$folder){
  127 + // 实例一个邮箱对象
  128 + $mail = new Mail($email['email'],base64_decode($email['password']),$email['imap']);
  129 + // 登录
  130 + $mail->login();
  131 + // 选择 文件夹
  132 + $mail->client->selectFolder($folder['origin_folder']);
  133 + // 最后的时间
  134 + $maxudate = db()->value(
  135 + sprintf(
  136 + "select max(`udate`) from `%s` where `email_id` = %d and `folder_id` = %d limit 1",
  137 + listsSql::$table,
  138 + $email['id'],
  139 + $folder['id']
  140 + )
  141 + );
  142 + $udate = $udate > $maxudate ? $udate : $maxudate;
  143 +
  144 + // 通过时间来搜索uid
  145 + $uids = $mail->client->search(['ON'=>date('Y-m-d H:i:s',$udate)]);
  146 + // 进行同步
  147 + $mail->syncUidEmail(
  148 + $uids,
  149 + $email['id'],
  150 + $folder['origin_folder'],
  151 + $folder['id'],
  152 + [],
  153 + [],
  154 + db()
  155 + );
  156 +
  157 + });
  158 + }
  159 + }
  160 +
  161 + }
  162 +
  163 + });
  164 +
  165 + }
  166 +
86 } 167 }
87 168
88 169
@@ -239,113 +239,15 @@ class Mail { @@ -239,113 +239,15 @@ class Mail {
239 239
240 // 开始同步 240 // 开始同步
241 if($uids){ 241 if($uids){
242 - $results = $this->client->fetchHeader($uids,true);  
243 -  
244 - if($results && is_array($results)){  
245 - // 表示已存在新邮件  
246 - if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);  
247 -  
248 - // 批量插入  
249 - foreach ($results as $key=>$result){  
250 - $header = $result['HEADER.FIELDS'];  
251 -  
252 - foreach ($result['FLAGS'] as $k=>$FLAG){  
253 - $result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));  
254 - }  
255 - try {  
256 -  
257 - // 没有收件人  
258 - if(!empty($header['To'])){  
259 - $header['To'] = MailFun::toOrFrom($header['To']);  
260 - }else{  
261 - $header['To'] = [];  
262 - }  
263 -  
264 - $header['From'] = MailFun::toOrFrom($header['From']??'');  
265 - // 抄送 ,密送  
266 - $cc = [];  
267 - $bcc = [];  
268 - if($header['Cc']??''){  
269 - $cc = MailFun::toOrFrom($header['Cc']);  
270 - }  
271 - if($header['Bcc']??''){  
272 - $bcc = MailFun::toOrFrom($header['Bcc']);  
273 - }  
274 -  
275 -  
276 - $data = [  
277 - 'uid' => $result['UID'],  
278 - 'subject' => $header['Subject']??'',  
279 - 'cc' => $cc,  
280 - 'bcc' => $bcc,  
281 - 'from' => $header['From'][0]['email']??'',  
282 - 'from_name' => $header['From'][0]['name']??'',  
283 - 'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',  
284 - 'to_name' => json_encode($header['To']),  
285 - 'date' => strtotime(is_array($header['Date']??'') ? $header['Date'][0] : $header['Date']??''),  
286 - 'message_id' => $header['Message-ID']??'',  
287 - 'udate' => strtotime($result['INTERNALDATE']),  
288 - 'size' => $result['RFC822.SIZE']??0,  
289 - 'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,  
290 - 'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,  
291 - 'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,  
292 - 'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,  
293 - 'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,  
294 - 'folder_id' => $folder_id,  
295 - 'email_id' => $email_id,  
296 - 'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件  
297 - ];  
298 - $data['date'] = $data['date'] ? : 0;  
299 -  
300 - // 验证是否存在黑名单中  
301 - if($blacklist){  
302 - // 邮箱是否在黑名单中  
303 - $isBlacklist = false;  
304 - if (!empty($blacklist['emails']) && is_array($blacklist['emails']) && in_array($data['from'],$blacklist['emails'])){  
305 - $isBlacklist = true;  
306 - }  
307 - // 域是否存在  
308 - if (!empty($blacklist['domain']) && is_array($blacklist['domain']) && in_array(explode('@',$data['from'])[1],$blacklist['domain'])){  
309 - $isBlacklist = true;  
310 - }  
311 -  
312 - if($isBlacklist && $blackFolder){  
313 - // 移入垃圾箱  
314 - $this->client->move($result['UID'],$blackFolder);  
315 - continue;  
316 - }  
317 - }  
318 -  
319 -  
320 - }catch (\Throwable $e){  
321 - logs(  
322 - '邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),  
323 - LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'  
324 - );  
325 - unset($results[$key]);  
326 - continue;  
327 - }  
328 -  
329 - // 插入数据库  
330 - try {  
331 - $id = $db->insert(listsSql::$table,$data);  
332 - if($id){  
333 - // 同步body内容  
334 - redis()->rPush('sync_email_body', [  
335 - 'lists_id' => $id,  
336 - 'email_id' => $email_id,  
337 - 'folder_id' => $folder_id,  
338 - 'folder' => $folder,  
339 - 'uid' => $data['uid'],  
340 - ]);  
341 - }  
342 - }catch (\Throwable $e){  
343 -  
344 - }  
345 -  
346 - $results[$key] = [];  
347 - }  
348 - } 242 + $this->syncUidEmail(
  243 + $uids,
  244 + $email_id,
  245 + $folder,
  246 + $folder_id,
  247 + $blacklist,
  248 + $blackFolder,
  249 + $db
  250 + );
349 251
350 } 252 }
351 253
@@ -363,6 +265,129 @@ class Mail { @@ -363,6 +265,129 @@ class Mail {
363 265
364 } 266 }
365 267
  268 + /**
  269 + * 同步邮件 只通过 uid获取
  270 + * @param array $uids
  271 + * @param $email_id
  272 + * @param $folder
  273 + * @param $folder_id
  274 + * @param $blacklist
  275 + * @param $blackFolder
  276 + * @param $db
  277 + * @throws \Exception
  278 + * @author:dc
  279 + * @time 2023/8/2 15:35
  280 + */
  281 + public function syncUidEmail(array $uids,$email_id,$folder,$folder_id,$blacklist,$blackFolder,$db){
  282 + $results = $this->client->fetchHeader($uids,true);
  283 +
  284 + if($results && is_array($results)){
  285 + // 表示已存在新邮件
  286 + if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);
  287 +
  288 + // 批量插入
  289 + foreach ($results as $key=>$result){
  290 + $header = $result['HEADER.FIELDS'];
  291 +
  292 + foreach ($result['FLAGS'] as $k=>$FLAG){
  293 + $result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
  294 + }
  295 + try {
  296 +
  297 + // 没有收件人
  298 + if(!empty($header['To'])){
  299 + $header['To'] = MailFun::toOrFrom($header['To']);
  300 + }else{
  301 + $header['To'] = [];
  302 + }
  303 +
  304 + $header['From'] = MailFun::toOrFrom($header['From']??'');
  305 + // 抄送 ,密送
  306 + $cc = [];
  307 + $bcc = [];
  308 + if($header['Cc']??''){
  309 + $cc = MailFun::toOrFrom($header['Cc']);
  310 + }
  311 + if($header['Bcc']??''){
  312 + $bcc = MailFun::toOrFrom($header['Bcc']);
  313 + }
  314 +
  315 +
  316 + $data = [
  317 + 'uid' => $result['UID'],
  318 + 'subject' => $header['Subject']??'',
  319 + 'cc' => $cc,
  320 + 'bcc' => $bcc,
  321 + 'from' => $header['From'][0]['email']??'',
  322 + 'from_name' => $header['From'][0]['name']??'',
  323 + 'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',
  324 + 'to_name' => json_encode($header['To']),
  325 + 'date' => strtotime(is_array($header['Date']??'') ? $header['Date'][0] : $header['Date']??''),
  326 + 'message_id' => $header['Message-ID']??'',
  327 + 'udate' => strtotime($result['INTERNALDATE']),
  328 + 'size' => $result['RFC822.SIZE']??0,
  329 + 'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,
  330 + 'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,
  331 + 'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,
  332 + 'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,
  333 + 'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,
  334 + 'folder_id' => $folder_id,
  335 + 'email_id' => $email_id,
  336 + 'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件
  337 + ];
  338 + $data['date'] = $data['date'] ? : 0;
  339 +
  340 + // 验证是否存在黑名单中
  341 + if($blacklist){
  342 + // 邮箱是否在黑名单中
  343 + $isBlacklist = false;
  344 + if (!empty($blacklist['emails']) && is_array($blacklist['emails']) && in_array($data['from'],$blacklist['emails'])){
  345 + $isBlacklist = true;
  346 + }
  347 + // 域是否存在
  348 + if (!empty($blacklist['domain']) && is_array($blacklist['domain']) && in_array(explode('@',$data['from'])[1],$blacklist['domain'])){
  349 + $isBlacklist = true;
  350 + }
  351 +
  352 + if($isBlacklist && $blackFolder){
  353 + // 移入垃圾箱
  354 + $this->client->move($result['UID'],$blackFolder);
  355 + continue;
  356 + }
  357 + }
  358 +
  359 +
  360 + }catch (\Throwable $e){
  361 + logs(
  362 + '邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),
  363 + LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'
  364 + );
  365 + unset($results[$key]);
  366 + continue;
  367 + }
  368 +
  369 + // 插入数据库
  370 + try {
  371 + $id = $db->insert(listsSql::$table,$data);
  372 + if($id){
  373 + // 同步body内容
  374 + redis()->rPush('sync_email_body', [
  375 + 'lists_id' => $id,
  376 + 'email_id' => $email_id,
  377 + 'folder_id' => $folder_id,
  378 + 'folder' => $folder,
  379 + 'uid' => $data['uid'],
  380 + ]);
  381 + }
  382 + }catch (\Throwable $e){
  383 +
  384 + }
  385 +
  386 + $results[$key] = [];
  387 + }
  388 + }
  389 + }
  390 +
366 391
367 /** 392 /**
368 * 同步 邮件 内容 body 393 * 同步 邮件 内容 body
@@ -28,6 +28,8 @@ return [ @@ -28,6 +28,8 @@ return [
28 'send' => [\Controller\Home::class, 'send_mail'], 28 'send' => [\Controller\Home::class, 'send_mail'],
29 // 同步请求 29 // 同步请求
30 'sync' => [\Controller\Home::class, 'sync'], 30 'sync' => [\Controller\Home::class, 'sync'],
  31 + // v2 版本的
  32 + 'v2/sync' => [\Controller\v2\Home::class, 'sync'],
31 // 标记为已读 33 // 标记为已读
32 'seen_2_unseen' => [\Controller\Home::class, 'seen_2_unseen'], 34 'seen_2_unseen' => [\Controller\Home::class, 'seen_2_unseen'],
33 // 标记为已回复/未回复 35 // 标记为已回复/未回复