...
|
...
|
@@ -2,11 +2,15 @@ |
|
|
|
|
|
namespace Service;
|
|
|
|
|
|
use Event\Event;
|
|
|
use Lib\Imap\ImapConfig;
|
|
|
use Lib\Imap\ImapPool;
|
|
|
use Lib\Imap\Parse\Folder\Folder;
|
|
|
use Lib\Imap\Parse\MessageItem;
|
|
|
use Model\bodySql;
|
|
|
use Model\emailSql;
|
|
|
use Model\folderSql;
|
|
|
use Model\listsSql;
|
|
|
|
|
|
/**
|
|
|
* 同步邮件
|
...
|
...
|
@@ -32,6 +36,9 @@ class SyncMail { |
|
|
*/
|
|
|
protected $email;
|
|
|
|
|
|
|
|
|
protected $isStop = false;
|
|
|
|
|
|
/**
|
|
|
* SyncMail constructor.
|
|
|
* @param int|string|array $email
|
...
|
...
|
@@ -54,12 +61,18 @@ class SyncMail { |
|
|
->setHost($email['imap'])
|
|
|
->setEmail($email['email'])
|
|
|
->setPassword(base64_decode($email['password']))
|
|
|
->debug()
|
|
|
);
|
|
|
|
|
|
$this->login();
|
|
|
|
|
|
}
|
|
|
|
|
|
public function stop(){
|
|
|
$this->isStop = true;
|
|
|
}
|
|
|
|
|
|
|
|
|
protected function emailId(){
|
|
|
return $this->email['id'];
|
|
|
}
|
...
|
...
|
@@ -78,16 +91,16 @@ class SyncMail { |
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 同步文件夹
|
|
|
* @param $folder
|
|
|
* @param int $pid
|
|
|
* @return array
|
|
|
* @throws \Exception
|
|
|
* @author:dc
|
|
|
* @time 2024/9/26 10:22
|
|
|
* @time 2024/9/26 10:46
|
|
|
*/
|
|
|
protected function folders(){
|
|
|
protected function folder($folder,$pid = 0){
|
|
|
$uuids = [];
|
|
|
// 获取文件夹
|
|
|
$folders = $this->imap->getFolders();
|
|
|
|
|
|
$tmp = function ($folder) use ($folders,&$uuids){
|
|
|
foreach ($folder as $item){
|
|
|
/** @var Folder $item*/
|
|
|
|
...
|
...
|
@@ -95,21 +108,13 @@ class SyncMail { |
|
|
$uuids[$uuid] = $uuid;
|
|
|
|
|
|
$folder_name = '';
|
|
|
// 已发送
|
|
|
if(in_array('Send',$item->flags)){
|
|
|
$folder_name = folderAlias('Send');
|
|
|
}
|
|
|
// 草稿
|
|
|
elseif(in_array('Drafts',$item->flags)){
|
|
|
$folder_name = folderAlias('Drafts');
|
|
|
if($item->flags){
|
|
|
// 有些邮箱是把公共的文件夹标记在flag里面的,识别出来
|
|
|
foreach ($item->flags as $flag){
|
|
|
if(in_array($flag,['Send','Drafts','Junk','Trash'])){
|
|
|
$folder_name = folderAlias($flag);
|
|
|
}
|
|
|
// 垃圾
|
|
|
elseif(in_array('Junk',$item->flags)){
|
|
|
$folder_name = folderAlias('Junk');
|
|
|
}
|
|
|
// 回收站
|
|
|
elseif(in_array('Trash',$item->flags)){
|
|
|
$folder_name = folderAlias('Trash');
|
|
|
}
|
|
|
if(!$folder_name){
|
|
|
$fn = explode('/',$item->getParseFolder());
|
...
|
...
|
@@ -120,29 +125,191 @@ class SyncMail { |
|
|
$id = $this->db->value(folderSql::has(['email_id'=>$this->emailId(),'uuid'=>$uuid]));
|
|
|
$data = [
|
|
|
'email_id' => $this->emailId(),
|
|
|
'folder' => folderAlias($folder_name),
|
|
|
'origin_folder' => $folder['folder'],
|
|
|
'folder' => $folder_name,
|
|
|
'origin_folder' => $item->folder,
|
|
|
'uuid' => $uuid,
|
|
|
'pid' => $pid
|
|
|
];
|
|
|
if ($id){
|
|
|
|
|
|
$this->db->update(folderSql::$table,$data,dbWhere(['id'=>$id]),false);
|
|
|
}else{
|
|
|
$id = $this->db->insert(folderSql::$table,$data,false);
|
|
|
if(!$id) abort('文件夹写入异常 '.json_encode($data,JSON_UNESCAPED_UNICODE));
|
|
|
}
|
|
|
// 是否有子级目录
|
|
|
if($id && $item->getChild()){
|
|
|
$uuids = array_merge($uuids,$this->folder($item->getChild(),$id));
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
$tmp($folders->getTopFolder());
|
|
|
return $uuids;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 同步
|
|
|
* @throws \Exception
|
|
|
* @author:dc
|
|
|
* @time 2024/9/26 10:46
|
|
|
*/
|
|
|
public function sync(){
|
|
|
$this->isStop = false;
|
|
|
/*********************************** 同步文件夹 ***************************************/
|
|
|
// 获取文件夹
|
|
|
$folders = $this->imap->getFolders();
|
|
|
$uuids = $this->folder($folders->getTopFolder());
|
|
|
if($uuids){
|
|
|
// 删除以前的
|
|
|
$this->db->delete(folderSql::$table,['uuid.notin'=>$uuids,'email_id'=>$this->emailId()]);
|
|
|
}
|
|
|
|
|
|
return $folders;
|
|
|
if($this->isStop) return;
|
|
|
|
|
|
|
|
|
/********************* 同步邮件 **********************/
|
|
|
|
|
|
// 循环文件夹
|
|
|
foreach ($folders->all() as $f){
|
|
|
if($this->isStop) return;
|
|
|
|
|
|
if($f->isSelect){ // 是否可以选择 只有可以选中的文件夹才有邮件
|
|
|
$folder = $this->imap->folder($f); // 选择文件夹后,有状态
|
|
|
|
|
|
// 这个暂时不要
|
|
|
// $this->db->update(folderSql::$table,[
|
|
|
// 'exsts' => $folder->getTotal(),
|
|
|
// 'unseen' => $folder->getUnseen(),
|
|
|
// 'last_sync_time' => time()
|
|
|
// ],dbWhere(['email_id'=>$this->emailId(),'origin_folder'=>$folder->getName()]),false);
|
|
|
|
|
|
// 是否有邮件 有邮件才继续
|
|
|
if ($folder->getTotal()){
|
|
|
$this->mail($folder);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
public function sync(){
|
|
|
$folders = $this->folders();
|
|
|
/**同步邮件
|
|
|
*
|
|
|
* @param string|\Lib\Imap\Request\Folder $folder
|
|
|
* @param array $uids 固定的uid
|
|
|
* @param false $isBody 是否同时同步body
|
|
|
* @author:dc
|
|
|
* @time 2024/9/26 11:10
|
|
|
*/
|
|
|
public function mail(string|\Lib\Imap\Request\Folder $folder, array $uids = [],$isBody = false){
|
|
|
if(is_string($folder)){
|
|
|
$folder = $this->imap->folder($folder);
|
|
|
}
|
|
|
|
|
|
$folder_id = $this->db->value(folderSql::first([
|
|
|
'email_id'=>$this->emailId(),
|
|
|
'uuid' => md5($this->emailId().$folder->getName())
|
|
|
],'`id`'));
|
|
|
|
|
|
// 选择成功
|
|
|
if($folder->isOk()){
|
|
|
$msg = $folder->msg();
|
|
|
if($uids){
|
|
|
$this->saveMail($folder_id,$msg->uid($uids)->get()->all(),$isBody);
|
|
|
}else{
|
|
|
$p=1;
|
|
|
while (1){
|
|
|
if($this->isStop) return;
|
|
|
|
|
|
$lists = $msg->forPage($p)->get()->all();
|
|
|
// 没有数据就跳出
|
|
|
if(!$lists){
|
|
|
break;
|
|
|
}else{
|
|
|
$p++;
|
|
|
$this->saveMail($folder_id,$lists,$isBody);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 保存邮件列表
|
|
|
* @param int $folder_id
|
|
|
* @param MessageItem[] $lists
|
|
|
* @param bool $isBody
|
|
|
* @author:dc
|
|
|
* @time 2024/9/29 15:14
|
|
|
*/
|
|
|
protected function saveMail(int $folder_id, array $lists, bool $isBody=false){
|
|
|
foreach ($lists as $item){
|
|
|
|
|
|
$data = [
|
|
|
'uid' => $item->uid,
|
|
|
'subject' => mb_substr($item->header->getSubject(),0,1000),// 控制下,有的蛋疼,整tm多长
|
|
|
'cc' => $item->header->getCc(true),
|
|
|
'bcc' => $item->header->getBcc(true),
|
|
|
'from' => $item->header->getFrom()->email,
|
|
|
'from_name' => $item->header->getFrom()->name,
|
|
|
'to' => implode(',',array_column($item->header->getTo(true),'email')),
|
|
|
'to_name' => $item->header->getTo(true),
|
|
|
// 这个是 邮件的时间 就是header里面带的 一般情况就是发件时间
|
|
|
// 'date' => strtotime($item->header->getDate()),
|
|
|
'udate' => strtotime($item->date), // 有这个时间就够了,内部时间,就是收到邮件的时间
|
|
|
'size' => $item->size,
|
|
|
'recent' => $item->isRecent() ? 1 : 0,
|
|
|
'seen' => $item->isSeen() ? 1 : 0,
|
|
|
'draft' => $item->isDraft() ? 1 : 0,
|
|
|
'flagged' => $item->isFlagged() ? 1 : 0,
|
|
|
'answered' => $item->isAnswered() ? 1 : 0,
|
|
|
'folder_id' => $folder_id,
|
|
|
'email_id' => $this->emailId(),
|
|
|
'is_file' => $item->isAttachment() ? 1: 0 //是否附件
|
|
|
];
|
|
|
|
|
|
// 查询是否存在
|
|
|
$id = $this->db->value(listsSql::first(dbWhere([
|
|
|
'email_id'=> $data['email_id'],
|
|
|
'folder_id' => $data['folder_id'],
|
|
|
'uid' => $data['uid']
|
|
|
]),'`id`'));
|
|
|
|
|
|
|
|
|
if(!$id){
|
|
|
$id = $this->db->insert(listsSql::$table,$data);
|
|
|
// 新邮件标记
|
|
|
if($item->getFolderName() == 'INBOX')
|
|
|
redis()->incr('have_new_mail_'.$this->emailId(),120);
|
|
|
// 执行事件
|
|
|
$data['Aicc-Hot-Mail'] = $item->header->get('Aicc-Hot-Mail');
|
|
|
Event::call('mail_sync_list',$id, $data);
|
|
|
|
|
|
}else{
|
|
|
$this->db->update(listsSql::$table,$data,dbWhere(['id'=> $id]));
|
|
|
}
|
|
|
|
|
|
|
|
|
// 是否同步body内容
|
|
|
if($isBody){
|
|
|
|
|
|
$body = [
|
|
|
'lists_id' => $id,
|
|
|
'text_html' => $item->getBody()->getItems()
|
|
|
];
|
|
|
|
|
|
if($this->db->count(bodySql::has($id))){
|
|
|
$this->db->update(bodySql::$table,$body,'`lists_id` = '.$id,false);
|
|
|
}else{
|
|
|
$this->db->insert(bodySql::$table,$body,false);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
...
|
...
|
|