作者 邓超

v2 调整

... ... @@ -12,7 +12,7 @@ use Model\emailSql;
use Model\folderSql;
use Model\listsSql;
use Model\sendJobsSql;
use function Co\run;
/**
... ... @@ -24,23 +24,9 @@ use Model\sendJobsSql;
class Home extends Base {
/**
* 邮件列表 针对aicc应用那边
* @author:dc
* @time 2023/2/17 14:12
*/
public function lists(){
$limit = app()->request('limit',20,['intval','abs']);
$last_id = app()->request('last_id',0,['intval','abs']);
private function getFolderIds($email_id){
$folder_ids = app()->request('folder_ids',[],['intval','abs']);
$udate = app()->request('udate',0,'intval');
$where = ['email_id' => $this->getEmail('id')];
foreach ($folder_ids as $k=>$folder_id){
if(!$folder_id){
unset($folder_ids[$k]);
... ... @@ -55,12 +41,34 @@ class Home extends Base {
sprintf(
"select `id` from `%s` where `email_id` = %d and `origin_folder` = 'INBOX'",
folderSql::$table
,$where['email_id']
,$email_id
)
);
$folder_ids = [$folder_ids];
}
return $folder_ids;
}
/**
* 邮件列表 针对aicc应用那边
* @author:dc
* @time 2023/2/17 14:12
*/
public function lists(){
$limit = app()->request('limit',20,['intval','abs']);
$last_id = app()->request('last_id',0,['intval','abs']);
$udate = app()->request('udate',0,'intval');
$where = ['email_id' => $this->getEmail('id')];
//目录
$where['folder_id'] = $folder_ids;
$where['folder_id'] = $this->getFolderIds($where['email_id']);
$sql = "`id` > ".$last_id;
... ... @@ -83,6 +91,79 @@ class Home extends Base {
}
/**
* v2 版本
* 同步规定 时间 之后的邮件
* @return string
* @throws \Lib\Err
* @author:dc
* @time 2023/8/2 16:19
*/
public function sync(){
$emails = web_request_emails();
$udate = app()->request('udate',0,'intval');
if(!$udate){
return '';
}
// 查询邮箱
$emails = db()->all(emailSql::all(dbWhere(['email'=>$emails])));
if(!$emails){
return '';
}
// 启用协程来处理
run(function () use ($emails,$udate){
foreach ($emails as $email){
// 读取文件夹
$fids = $this->getFolderIds($email['id']);
$folders = db()->all(folderSql::all($email['id']));
// 循环 文件夹
foreach ($folders as $folder){
// 是否在同步请求中
if(in_array($folder['id'],$fids)){
// 启动 协程
go(function () use ($email,$udate,$folder){
// 实例一个邮箱对象
$mail = new Mail($email['email'],base64_decode($email['password']),$email['imap']);
// 登录
$mail->login();
// 选择 文件夹
$mail->client->selectFolder($folder['origin_folder']);
// 最后的时间
$maxudate = db()->value(
sprintf(
"select max(`udate`) from `%s` where `email_id` = %d and `folder_id` = %d limit 1",
listsSql::$table,
$email['id'],
$folder['id']
)
);
$udate = $udate > $maxudate ? $udate : $maxudate;
// 通过时间来搜索uid
$uids = $mail->client->search(['ON'=>date('Y-m-d H:i:s',$udate)]);
// 进行同步
$mail->syncUidEmail(
$uids,
$email['id'],
$folder['origin_folder'],
$folder['id'],
[],
[],
db()
);
});
}
}
}
});
}
}
... ...
... ... @@ -239,113 +239,15 @@ class Mail {
// 开始同步
if($uids){
$results = $this->client->fetchHeader($uids,true);
if($results && is_array($results)){
// 表示已存在新邮件
if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);
// 批量插入
foreach ($results as $key=>$result){
$header = $result['HEADER.FIELDS'];
foreach ($result['FLAGS'] as $k=>$FLAG){
$result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
}
try {
// 没有收件人
if(!empty($header['To'])){
$header['To'] = MailFun::toOrFrom($header['To']);
}else{
$header['To'] = [];
}
$header['From'] = MailFun::toOrFrom($header['From']??'');
// 抄送 ,密送
$cc = [];
$bcc = [];
if($header['Cc']??''){
$cc = MailFun::toOrFrom($header['Cc']);
}
if($header['Bcc']??''){
$bcc = MailFun::toOrFrom($header['Bcc']);
}
$data = [
'uid' => $result['UID'],
'subject' => $header['Subject']??'',
'cc' => $cc,
'bcc' => $bcc,
'from' => $header['From'][0]['email']??'',
'from_name' => $header['From'][0]['name']??'',
'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',
'to_name' => json_encode($header['To']),
'date' => strtotime(is_array($header['Date']??'') ? $header['Date'][0] : $header['Date']??''),
'message_id' => $header['Message-ID']??'',
'udate' => strtotime($result['INTERNALDATE']),
'size' => $result['RFC822.SIZE']??0,
'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,
'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,
'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,
'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,
'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,
'folder_id' => $folder_id,
'email_id' => $email_id,
'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件
];
$data['date'] = $data['date'] ? : 0;
// 验证是否存在黑名单中
if($blacklist){
// 邮箱是否在黑名单中
$isBlacklist = false;
if (!empty($blacklist['emails']) && is_array($blacklist['emails']) && in_array($data['from'],$blacklist['emails'])){
$isBlacklist = true;
}
// 域是否存在
if (!empty($blacklist['domain']) && is_array($blacklist['domain']) && in_array(explode('@',$data['from'])[1],$blacklist['domain'])){
$isBlacklist = true;
}
if($isBlacklist && $blackFolder){
// 移入垃圾箱
$this->client->move($result['UID'],$blackFolder);
continue;
}
}
}catch (\Throwable $e){
logs(
'邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),
LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'
);
unset($results[$key]);
continue;
}
// 插入数据库
try {
$id = $db->insert(listsSql::$table,$data);
if($id){
// 同步body内容
redis()->rPush('sync_email_body', [
'lists_id' => $id,
'email_id' => $email_id,
'folder_id' => $folder_id,
'folder' => $folder,
'uid' => $data['uid'],
]);
}
}catch (\Throwable $e){
}
$results[$key] = [];
}
}
$this->syncUidEmail(
$uids,
$email_id,
$folder,
$folder_id,
$blacklist,
$blackFolder,
$db
);
}
... ... @@ -363,6 +265,129 @@ class Mail {
}
/**
* 同步邮件 只通过 uid获取
* @param array $uids
* @param $email_id
* @param $folder
* @param $folder_id
* @param $blacklist
* @param $blackFolder
* @param $db
* @throws \Exception
* @author:dc
* @time 2023/8/2 15:35
*/
public function syncUidEmail(array $uids,$email_id,$folder,$folder_id,$blacklist,$blackFolder,$db){
$results = $this->client->fetchHeader($uids,true);
if($results && is_array($results)){
// 表示已存在新邮件
if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);
// 批量插入
foreach ($results as $key=>$result){
$header = $result['HEADER.FIELDS'];
foreach ($result['FLAGS'] as $k=>$FLAG){
$result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
}
try {
// 没有收件人
if(!empty($header['To'])){
$header['To'] = MailFun::toOrFrom($header['To']);
}else{
$header['To'] = [];
}
$header['From'] = MailFun::toOrFrom($header['From']??'');
// 抄送 ,密送
$cc = [];
$bcc = [];
if($header['Cc']??''){
$cc = MailFun::toOrFrom($header['Cc']);
}
if($header['Bcc']??''){
$bcc = MailFun::toOrFrom($header['Bcc']);
}
$data = [
'uid' => $result['UID'],
'subject' => $header['Subject']??'',
'cc' => $cc,
'bcc' => $bcc,
'from' => $header['From'][0]['email']??'',
'from_name' => $header['From'][0]['name']??'',
'to' => $header['To']?implode(',',array_column($header['To'],'email')):'',
'to_name' => json_encode($header['To']),
'date' => strtotime(is_array($header['Date']??'') ? $header['Date'][0] : $header['Date']??''),
'message_id' => $header['Message-ID']??'',
'udate' => strtotime($result['INTERNALDATE']),
'size' => $result['RFC822.SIZE']??0,
'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,
'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,
'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,
'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,
'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,
'folder_id' => $folder_id,
'email_id' => $email_id,
'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件
];
$data['date'] = $data['date'] ? : 0;
// 验证是否存在黑名单中
if($blacklist){
// 邮箱是否在黑名单中
$isBlacklist = false;
if (!empty($blacklist['emails']) && is_array($blacklist['emails']) && in_array($data['from'],$blacklist['emails'])){
$isBlacklist = true;
}
// 域是否存在
if (!empty($blacklist['domain']) && is_array($blacklist['domain']) && in_array(explode('@',$data['from'])[1],$blacklist['domain'])){
$isBlacklist = true;
}
if($isBlacklist && $blackFolder){
// 移入垃圾箱
$this->client->move($result['UID'],$blackFolder);
continue;
}
}
}catch (\Throwable $e){
logs(
'邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),
LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'
);
unset($results[$key]);
continue;
}
// 插入数据库
try {
$id = $db->insert(listsSql::$table,$data);
if($id){
// 同步body内容
redis()->rPush('sync_email_body', [
'lists_id' => $id,
'email_id' => $email_id,
'folder_id' => $folder_id,
'folder' => $folder,
'uid' => $data['uid'],
]);
}
}catch (\Throwable $e){
}
$results[$key] = [];
}
}
}
/**
* 同步 邮件 内容 body
... ...
... ... @@ -28,6 +28,8 @@ return [
'send' => [\Controller\Home::class, 'send_mail'],
// 同步请求
'sync' => [\Controller\Home::class, 'sync'],
// v2 版本的
'v2/sync' => [\Controller\v2\Home::class, 'sync'],
// 标记为已读
'seen_2_unseen' => [\Controller\Home::class, 'seen_2_unseen'],
// 标记为已回复/未回复
... ...