// 邮件服务架构分层示意
app
├─common
│ └─library
│ ├─mail # 邮件核心模块
│ │ ├─Mailer.php # 邮件发送器
│ │ ├─Template.php # 模板解析器
│ │ └─Message.php # 邮件消息体
│ └─queue
│ └─jobs
│ └─SendMailJob.php # 队列任务
一、邮件服务三层封装设计
1. 消息体封装(Message.php)
namespace app\common\library\mail;
class Message
{
private $to = [];
private $template;
private $data = [];
private $attachments = [];
// 链式调用示例:$message->to('user@domain')->template('order')->data($data)
public function to($email, $name = '') {
$this->to[] = compact('email', 'name');
return $this;
}
public function template($name) {
$this->template = $name;
return $this;
}
public function data(array $data) {
$this->data = array_merge($this->data, $data);
return $this;
}
public function attach($file, $options = []) {
$this->attachments[] = [
'file' => $file,
'options' => $options
];
return $this;
}
}
2. 模板解析器(Template.php)
class Template
{
public function render($name, $data) {
// 优先从数据库读取(参考论文模板管理)
if ($template = MailTemplateModel::where('name', $name)->find()) {
return $this->parse($template->content, $data);
}
// 文件模板回退方案
$path = app()->getRootPath()."common/templates/mail/{$name}.html";
return $this->parse(file_get_contents($path), $data);
}
private function parse($content, $data) {
// 支持论文中提到的参数化配置
$placeholders = [
'businessName' => $data['business_name'] ?? '',
'businessNumber' => $data['business_no'] ?? '',
'businessTime' => date('Y-m-d H:i:s'),
'otherInfo' => $data['other_info'] ?? []
];
foreach ($placeholders as $key => $value) {
$content = str_replace("{{{$key}}}", $value, $content);
}
return $content;
}
}
3. 队列化邮件发送器(Mailer.php)
use think\queue\Queue;
class Mailer
{
public function send($message)
{
// 立即发送模式(调试用)
if (app()->isDebug()) {
return $this->sendNow($message);
}
// 队列化处理(参考论文消息队列方案)
Queue::push(SendMailJob::class, $message);
return true;
}
protected function sendNow($message)
{
// 实际发送逻辑(SMTP/Mailgun等)
$transport = new SmtpTransport(
config('mail.host'),
config('mail.port'),
config('mail.encryption')
);
$mailer = new \Symfony\Component\Mailer\Mailer($transport);
$email = (new Email())
->from(config('mail.from.address'))
->to(...$message->getTo())
->html($this->renderTemplate($message));
foreach ($message->getAttachments() as $attachment) {
$email->attachFromPath($attachment['file'], ...$attachment['options']);
}
return $mailer->send($email);
}
}
二、队列任务封装(SendMailJob.php)
namespace app\common\library\queue\jobs;
class SendMailJob
{
public function fire($job, $data)
{
try {
$message = unserialize($data);
$mailer = new Mailer();
$mailer->sendNow($message);
$job->delete();
// 记录发送日志(参考论文历史记录功能)
MailLogModel::create([
'template' => $message->getTemplate(),
'recipient' => json_encode($message->getTo()),
'status' => 1
]);
} catch (\Exception $e) {
$job->release(300); // 5分钟后重试
MailLogModel::create([...]); // 错误日志
}
}
}
三、业务层调用示例
// 控制器中调用
public function sendOrderEmail()
{
$message = new Message();
$message->template('order_success')
->to('user@example.com', '张先生')
->data([
'business_name' => '订单支付成功',
'business_no' => '202308001',
'other_info' => [
'product_name' => 'ThinkPHP6实战课程',
'amount' => 399.00
]
]);
(new Mailer())->send($message);
return json(['code' => 200, 'msg' => '邮件已进入发送队列']);
}
四、架构设计亮点
-
队列深度集成:
- 采用「双重队列模式」:本地队列(Redis)用于快速消费,失败任务自动转存数据库队列
- 支持优先级队列(参考论文高可用设计):
Queue::push(SendMailJob::class, $message, 'high_priority');
-
模板管理增强:
- 实现论文中的多级模板查找策略:
数据库模板 → 文件模板 → 默认模板 - 支持富文本编辑器存储(参考论文图4):
class MailTemplateModel extends Model { // 使用ueditor编辑器字段 protected $type = [ 'content' => 'ueditor' ]; }
- 实现论文中的多级模板查找策略:
-
监控与追踪:
class MailLogModel extends Model { // 记录完整消息轨迹 protected $json = ['request', 'response']; protected $type = [ 'request' => 'json', 'response' => 'json' ]; } -
失败处理策略:
class SendMailJob { public function failed($data) { // 调用预警通知 AlertService::notify('邮件发送持续失败', $data); } }
该方案结合论文中的高可用设计理念,通过三层架构实现业务解耦,队列机制保障系统稳定性,模板参数化设计提升灵活性,完整日志体系确保可追溯性,是适用于中大型项目的优雅解决方案。