多邮箱处理
This commit is contained in:
@@ -66,7 +66,7 @@ class Mailbox
|
|||||||
|
|
||||||
while ($attempt < $retryTimes) {
|
while ($attempt < $retryTimes) {
|
||||||
$attempt++;
|
$attempt++;
|
||||||
flg("尝试第 {$attempt} 次连接 IMAP...", false);
|
flg("尝试第 {$attempt} 次连接 IMAP...", false,'mailbox');
|
||||||
|
|
||||||
$inbox = @imap_open($mailbox, $username, $password);
|
$inbox = @imap_open($mailbox, $username, $password);
|
||||||
|
|
||||||
@@ -75,11 +75,11 @@ class Mailbox
|
|||||||
}
|
}
|
||||||
|
|
||||||
$error = imap_last_error();
|
$error = imap_last_error();
|
||||||
flg("<comment>{$username}第 {$attempt} 次失败:{$error}</comment>");
|
flg("<comment>{$username}第 {$attempt} 次失败:{$error}</comment>", false,'mailbox');
|
||||||
|
|
||||||
// 若出现 too many login failures 立即暂停一段时间
|
// 若出现 too many login failures 立即暂停一段时间
|
||||||
if (stripos($error, 'Too many login failures') !== false) {
|
if (stripos($error, 'Too many login failures') !== false) {
|
||||||
flg("<error>检测到登录失败次数过多,暂停 60 秒避免封禁</error>");
|
flg("<error>检测到登录失败次数过多,暂停 60 秒避免封禁</error>", false,'mailbox');
|
||||||
sleep(60);
|
sleep(60);
|
||||||
} else {
|
} else {
|
||||||
sleep($retryDelay);
|
sleep($retryDelay);
|
||||||
@@ -87,11 +87,11 @@ class Mailbox
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$inbox) {
|
if (!$inbox) {
|
||||||
flg("{$username}<error>最终仍然连接失败:" . imap_last_error() . "</error>");
|
flg("{$username}<error>最终仍然连接失败:" . imap_last_error() . "</error>", false,'mailbox');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 拉取 UID 并入库
|
// 拉取 UID 并入库
|
||||||
flg("开始拉取 UID 并入库 …", false);
|
flg("开始拉取 UID 并入库 …", false,'mailbox');
|
||||||
$uids = imap_search($inbox, 'ALL', SE_UID) ?: [];
|
$uids = imap_search($inbox, 'ALL', SE_UID) ?: [];
|
||||||
|
|
||||||
$uids = array_filter($uids, function($uid) use ($lastUid) {
|
$uids = array_filter($uids, function($uid) use ($lastUid) {
|
||||||
@@ -110,14 +110,14 @@ class Mailbox
|
|||||||
'email' => $username
|
'email' => $username
|
||||||
]);
|
]);
|
||||||
$count++;
|
$count++;
|
||||||
flg("{$username} UID:".$uid." 已写入数据库", false);
|
flg("{$username} UID:".$uid." 已写入数据库", false,'mailbox');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
flg("{$username} <comment>{$e->getMessage()}</comment>");
|
flg("{$username} <comment>{$e->getMessage()}</comment>", false,'mailbox');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imap_close($inbox);
|
imap_close($inbox);
|
||||||
flg("✔ {$username}获取到新询盘邮件 {$count} 条 ...", false);
|
flg("✔ {$username}获取到新询盘邮件 {$count} 条 ...", false,'mailbox');
|
||||||
|
|
||||||
$mailboxModel->last_uid = max($uids);
|
$mailboxModel->last_uid = max($uids);
|
||||||
$mailboxModel->last_fetch_at = time();
|
$mailboxModel->last_fetch_at = time();
|
||||||
@@ -125,7 +125,7 @@ class Mailbox
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
flg(dpr($th),false);
|
flg(dpr($th), false,'mailbox');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,12 +158,12 @@ class Mailbox
|
|||||||
$password = $mailboxModel['password'];
|
$password = $mailboxModel['password'];
|
||||||
$inbox = @imap_open($mailbox, $username, $password);
|
$inbox = @imap_open($mailbox, $username, $password);
|
||||||
if (!$inbox) {
|
if (!$inbox) {
|
||||||
flg("<error>{$username} IMAP 连接失败:". imap_last_error() ."</error>");
|
flg("<error>{$username} IMAP 连接失败:". imap_last_error() ."</error>", false,'mailbox');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 依次拉取详情并写入 emails 表
|
// 依次拉取详情并写入 emails 表
|
||||||
flg("依次拉取详情并写入 email_pull 表 …", false);
|
flg("依次拉取详情并写入 email_pull 表 …", false,'mailbox');
|
||||||
while (true) {
|
while (true) {
|
||||||
$pending = Db::table('email_pull_uids')
|
$pending = Db::table('email_pull_uids')
|
||||||
->where('email', $username)
|
->where('email', $username)
|
||||||
@@ -173,35 +173,35 @@ class Mailbox
|
|||||||
->get();
|
->get();
|
||||||
|
|
||||||
if (count($pending) === 0) {
|
if (count($pending) === 0) {
|
||||||
flg("邮件UID的详情,已拉取完毕。", false);
|
flg("邮件UID的详情,已拉取完毕。", false,'mailbox');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
flg("处理下一批 " . count($pending) . " 条 …", false);
|
flg("处理下一批 " . count($pending) . " 条 …", false,'mailbox');
|
||||||
|
|
||||||
foreach ($pending as $row) {
|
foreach ($pending as $row) {
|
||||||
$uid = $row->uid;
|
$uid = $row->uid;
|
||||||
|
|
||||||
// 包裹整行处理在 try/catch 中,任何异常都不会中断循环
|
// 包裹整行处理在 try/catch 中,任何异常都不会中断循环
|
||||||
try {
|
try {
|
||||||
flg("---- 开始处理 UID={$uid} ----", false);
|
flg("---- 开始处理 UID={$uid} ----", false,'mailbox');
|
||||||
|
|
||||||
// 1. fetch overview
|
// 1. fetch overview
|
||||||
$ov = @imap_fetch_overview($inbox, $uid, FT_UID)[0] ?? null;
|
$ov = @imap_fetch_overview($inbox, $uid, FT_UID)[0] ?? null;
|
||||||
if (!$ov) {
|
if (!$ov) {
|
||||||
$err = imap_last_error() ?: '未知错误';
|
$err = imap_last_error() ?: '未知错误';
|
||||||
flg("UID={$uid} overview 失败:{$err}");
|
flg("UID={$uid} overview 失败:{$err}", false,'mailbox');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$subject = mb_convert_encoding($ov->subject ?? '', 'UTF-8', 'GBK,UTF-8');
|
$subject = mb_convert_encoding($ov->subject ?? '', 'UTF-8', 'GBK,UTF-8');
|
||||||
$from = $ov->from ?? '';
|
$from = $ov->from ?? '';
|
||||||
$date = $ov->date ?? '';
|
$date = $ov->date ?? '';
|
||||||
|
|
||||||
flg("UID={$uid} overview 成功,subject={$subject}", false);
|
flg("UID={$uid} overview 成功,subject={$subject}", false,'mailbox');
|
||||||
|
|
||||||
// 2. fetch body
|
// 2. fetch body
|
||||||
$body = $this->getMailBody($inbox, $uid, true);
|
$body = $this->getMailBody($inbox, $uid, true);
|
||||||
flg("UID={$uid} body 长度:" . strlen($body), false);
|
flg("UID={$uid} body 长度:" . strlen($body), false,'mailbox');
|
||||||
|
|
||||||
// 3. sanitize & insert
|
// 3. sanitize & insert
|
||||||
$body = $this->sanitizeUtf8($body);
|
$body = $this->sanitizeUtf8($body);
|
||||||
@@ -218,9 +218,9 @@ class Mailbox
|
|||||||
'created_at' => $now,
|
'created_at' => $now,
|
||||||
'updated_at' => $now,
|
'updated_at' => $now,
|
||||||
]);
|
]);
|
||||||
flg($username." UID={$uid} 写入 emails 成功", false);
|
flg($username." UID={$uid} 写入 emails 成功", false,'mailbox');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
flg($username." UID={$uid} 写入失败:{$e->getMessage()}");
|
flg($username." UID={$uid} 写入失败:{$e->getMessage()}", false,'mailbox');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,14 +232,14 @@ class Mailbox
|
|||||||
'status' => 1,
|
'status' => 1,
|
||||||
'processed_at' => $now,
|
'processed_at' => $now,
|
||||||
]);
|
]);
|
||||||
flg($username." UID={$uid} 标记为已处理", false);
|
flg($username." UID={$uid} 标记为已处理", false,'mailbox');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
flg($username." UID={$uid} 标记状态失败:{$e->getMessage()}", false);
|
flg($username." UID={$uid} 标记状态失败:{$e->getMessage()}", false,'mailbox');
|
||||||
// 即使更新 status 失败,也继续下一条
|
// 即使更新 status 失败,也继续下一条
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// 捕获任何非预期错误
|
// 捕获任何非预期错误
|
||||||
flg($username." UID={$uid} 处理异常:{$e->getMessage()}", false);
|
flg($username." UID={$uid} 处理异常:{$e->getMessage()}", false,'mailbox');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,10 +249,10 @@ class Mailbox
|
|||||||
}
|
}
|
||||||
|
|
||||||
imap_close($inbox);
|
imap_close($inbox);
|
||||||
flg($username." ✔ 新邮件详情拉取完成 ...", false);
|
flg($username." ✔ 新邮件详情拉取完成 ...", false,'mailbox');
|
||||||
return true;
|
return true;
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
flg(dpr($th));
|
flg(dpr($th), false,'mailbox');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -386,7 +386,7 @@ class Mailbox
|
|||||||
if ($parsed === null) {
|
if ($parsed === null) {
|
||||||
$row->status = 2; //其他邮件
|
$row->status = 2; //其他邮件
|
||||||
$row->save();
|
$row->save();
|
||||||
flg("<error>{$mailbox['username']} {$row->id} skip: not a contact-form HTML</error>");
|
flg("<error>{$mailbox['username']} {$row->id} skip: not a contact-form HTML</error>", false,'mailbox');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,7 +602,7 @@ class Mailbox
|
|||||||
if ($parsed === null) {
|
if ($parsed === null) {
|
||||||
$row->status = 2; //其他邮件
|
$row->status = 2; //其他邮件
|
||||||
$row->save();
|
$row->save();
|
||||||
flg($mailbox['username']." <error>{$mailbox['username']} {$row->id} skip: not a contact-form HTML</error>");
|
flg($mailbox['username']." <error>{$mailbox['username']} {$row->id} skip: not a contact-form HTML</error>", false,'mailbox');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +832,7 @@ class Mailbox
|
|||||||
// 获取分配的用户信息
|
// 获取分配的用户信息
|
||||||
$recipientInfo = User::where('id', $assignedUid)->where('status', 1)->first();
|
$recipientInfo = User::where('id', $assignedUid)->where('status', 1)->first();
|
||||||
if (!$recipientInfo) {
|
if (!$recipientInfo) {
|
||||||
flg("用户ID=" . $assignedUid . " 已离职 跳过自动分配,需要手动移除 UID");
|
flg("用户ID=" . $assignedUid . " 已离职 跳过自动分配,需要手动移除 UID", false,'mailbox');
|
||||||
|
|
||||||
$assignedUid = $uidRotator->next();
|
$assignedUid = $uidRotator->next();
|
||||||
$recipientInfo = User::where('id', $assignedUid)->where('status', 1)->first();
|
$recipientInfo = User::where('id', $assignedUid)->where('status', 1)->first();
|
||||||
@@ -888,7 +888,7 @@ class Mailbox
|
|||||||
|
|
||||||
// 更新状态
|
// 更新状态
|
||||||
$record->update(['status' => 1]);
|
$record->update(['status' => 1]);
|
||||||
flg('====== 编号:'.$inquiryLogResult->order_no.' 分配给:'.$recipientInfo->name.' email:'.$recipientInfo->email, false);
|
flg('====== 编号:'.$inquiryLogResult->order_no.' 分配给:'.$recipientInfo->name.' email:'.$recipientInfo->email, false,'mailbox');
|
||||||
|
|
||||||
// 每封邮件后延迟
|
// 每封邮件后延迟
|
||||||
if ($delaySeconds > 0) {
|
if ($delaySeconds > 0) {
|
||||||
@@ -898,11 +898,11 @@ class Mailbox
|
|||||||
// 每发送一定数量后额外休息
|
// 每发送一定数量后额外休息
|
||||||
if (++$count % $throttleAfter === 0) {
|
if (++$count % $throttleAfter === 0) {
|
||||||
sleep($throttleSeconds);
|
sleep($throttleSeconds);
|
||||||
flg("已发送 {$count} 封邮件,休息 {$throttleSeconds} 秒", false);
|
flg("已发送 {$count} 封邮件,休息 {$throttleSeconds} 秒", false,'mailbox');
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
flg("邮件发送失败 ID:{$record->id} - " . $e->getMessage());
|
flg("邮件发送失败 ID:{$record->id} - " . $e->getMessage(), false,'mailbox');
|
||||||
// 更新状态
|
// 更新状态
|
||||||
$record->update(['status' => 3]);
|
$record->update(['status' => 3]);
|
||||||
// 失败后也加入延迟,避免快速连续失败
|
// 失败后也加入延迟,避免快速连续失败
|
||||||
@@ -911,7 +911,7 @@ class Mailbox
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
flg(dpr($th));
|
flg(dpr($th), false,'mailbox');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class Emails
|
|||||||
$email->fenpai();
|
$email->fenpai();
|
||||||
});
|
});
|
||||||
|
|
||||||
//-----------多邮箱处理
|
//-------------多邮箱处理----------------
|
||||||
// 拉取新邮件uid - 每小时的第40分钟0秒执行
|
// 拉取新邮件uid - 每小时的第40分钟0秒执行
|
||||||
new Crontab('0 */40 * * * *', function(){
|
new Crontab('0 */40 * * * *', function(){
|
||||||
$email = new Mailbox();
|
$email = new Mailbox();
|
||||||
|
|||||||
Reference in New Issue
Block a user