From a32b1656b045b10c791e79b421a9084b5791d47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=AB=E5=9C=B0=E5=83=A7?= <357099073@qq.com> Date: Thu, 5 Feb 2026 22:27:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=82=AE=E4=BB=B6=E5=8F=91?= =?UTF-8?q?=E9=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/System/EmailController.php | 232 ++++++++++++++++++ app/admin/route/routes/email.php | 12 + app/model/System/SystemEmail.php | 42 ++++ composer.json | 3 +- composer.lock | 84 ++++++- 5 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 app/admin/controller/System/EmailController.php create mode 100644 app/admin/route/routes/email.php create mode 100644 app/model/System/SystemEmail.php diff --git a/app/admin/controller/System/EmailController.php b/app/admin/controller/System/EmailController.php new file mode 100644 index 0000000..0a1671b --- /dev/null +++ b/app/admin/controller/System/EmailController.php @@ -0,0 +1,232 @@ +field('id, from_address, from_name, host, port, password, encryption, timeout, create_time, update_time') + ->select() + ->toArray(); + // 记录操作日志 + $this->logSuccess('邮箱管理', '获取邮箱信息', ['data' => $email]); + return json([ + 'code' => 200, + 'msg' => '获取成功', + 'data' => $email + ]); + } catch (DbException $e) { + // 记录失败日志 + $this->logFail('邮箱管理', '获取邮箱信息', $e->getMessage()); + return json([ + 'code' => 500, + 'msg' => '获取失败:' . $e->getMessage(), + 'data' => [] + ]); + } + } + + /** + * 编辑邮箱信息 + * @return Json + */ + public function editEmailInfo() + { + try { + // 获取原始请求参数(驼峰命名) + $raw = $this->request->post(); + + // 手动映射为下划线命名,便于与数据库字段、验证规则对应 + $data = [ + 'from_address' => $raw['fromAddress'] ?? '', + 'from_name' => $raw['fromName'] ?? '', + 'host' => $raw['host'] ?? '', + 'port' => $raw['port'] ?? '', + 'password' => $raw['password'] ?? '', + 'encryption' => $raw['encryption'] ?? '', + 'timeout' => $raw['timeout'] ?? '', + ]; + + // 验证参数 + $this->validate($data, [ + 'from_address|发件人邮箱' => 'require|max:255', + 'from_name|发件人名称' => 'require|max:255', + 'host|SMTP主机' => 'require|max:255', + 'port|SMTP端口' => 'require|integer', + 'password|密码' => 'require|max:255', + 'encryption|加密方式' => 'require|max:255', + 'timeout|超时时间' => 'require|integer', + ]); + + // 先查一条配置(本表设计为单条配置) + $email = SystemEmail::order('id', 'asc')->find(); + + // 公共字段 + $saveData = [ + 'from_address' => $data['from_address'], + 'from_name' => $data['from_name'], + 'host' => $data['host'], + 'port' => $data['port'], + 'password' => $data['password'], + 'encryption' => $data['encryption'], + 'timeout' => $data['timeout'], + ]; + + if ($email) { + // 已有一条记录,按主键更新 + $saveData['update_time'] = date('Y-m-d H:i:s'); + SystemEmail::update($saveData, ['id' => $email['id']]); + } else { + // 没有记录,插入新记录 + $saveData['create_time'] = date('Y-m-d H:i:s'); + $saveData['update_time'] = $saveData['create_time']; + $model = new SystemEmail(); + $model->save($saveData); + } + + // 获取最新的邮箱信息 + $updatedEmail = SystemEmail::order('id', 'asc')->find(); + + // 记录操作日志 + $this->logSuccess('邮箱管理', '更新邮箱信息', ['data' => $updatedEmail]); + return json([ + 'code' => 200, + 'msg' => '更新成功', + 'data' => $updatedEmail + ]); + } catch (ValidateException $e) { + // 记录失败日志 + $this->logFail('邮箱管理', '更新邮箱信息', $e->getMessage()); + return json([ + 'code' => 400, + 'msg' => $e->getError() + ]); + } catch (DbException $e) { + // 记录失败日志 + $this->logFail('邮箱管理', '更新邮箱信息', $e->getMessage()); + return json([ + 'code' => 500, + 'msg' => '更新失败:' . $e->getMessage() + ]); + } + } + /** + * 发送测试邮件 + * @return Json + */ + public function sendTestEmail() + { + try { + // 获取前端传来的表单数据(驼峰命名) + $raw = $this->request->post(); + + // 映射为下划线命名,便于验证和使用 + $data = [ + 'from_address' => $raw['fromAddress'] ?? '', + 'from_name' => $raw['fromName'] ?? '', + 'host' => $raw['host'] ?? '', + 'port' => $raw['port'] ?? '', + 'password' => $raw['password'] ?? '', + 'encryption' => $raw['encryption'] ?? '', + 'timeout' => $raw['timeout'] ?? 30, + 'test_email' => $raw['testEmail'] ?? '', + ]; + + // 参数验证 + $this->validate($data, [ + 'from_address|发件人邮箱' => 'require|email|max:255', + 'from_name|发件人名称' => 'max:255', + 'host|SMTP主机' => 'require|max:255', + 'port|SMTP端口' => 'require|integer', + 'password|密码' => 'require|max:255', + 'encryption|加密方式' => 'require|max:10', + 'timeout|超时时间' => 'integer', + 'test_email|测试收件邮箱' => 'require|email|max:255', + ]); + + // 使用 PHPMailer 发送测试邮件 + $mail = new PHPMailer(true); + + // 服务器设置 + $mail->CharSet = 'UTF-8'; + $mail->isSMTP(); + $mail->Host = $data['host']; + $mail->SMTPAuth = true; + // 发件人邮箱即为登录用户名 + $mail->Username = $data['from_address']; + $mail->Password = $data['password']; + $mail->Port = (int)$data['port']; + + // 加密方式 + if (in_array(strtolower((string)$data['encryption']), ['ssl', 'tls'], true)) { + $mail->SMTPSecure = strtolower((string)$data['encryption']); + } + + // 超时时间(秒) + if (!empty($data['timeout'])) { + $mail->Timeout = (int)$data['timeout']; + } + + // 收发件配置 + $fromName = $data['from_name'] ?: $data['from_address']; + $mail->setFrom($data['from_address'], $fromName); + $mail->addAddress($data['test_email']); + + // 内容 + $mail->isHTML(false); + $mail->Subject = '测试邮件 - 网站邮箱配置'; + $mail->Body = '这是一封测试邮件,用于验证网站邮箱配置是否正确。发送时间:' . date('Y-m-d H:i:s'); + + // 发送 + $mail->send(); + + // 记录操作日志 + $this->logSuccess('邮箱管理', '发送测试邮件', [ + 'to' => $data['test_email'], + 'host' => $data['host'], + ]); + + return json([ + 'code' => 200, + 'msg' => '测试邮件发送成功', + ]); + } catch (ValidateException $e) { + $this->logFail('邮箱管理', '发送测试邮件', $e->getMessage()); + return json([ + 'code' => 400, + 'msg' => $e->getError() + ]); + } catch (MailException $e) { + $this->logFail('邮箱管理', '发送测试邮件', $e->getMessage()); + return json([ + 'code' => 500, + 'msg' => '发送失败:' . $e->getMessage() + ]); + } catch (\Exception $e) { + $this->logFail('邮箱管理', '发送测试邮件', $e->getMessage()); + return json([ + 'code' => 500, + 'msg' => '发送失败:' . $e->getMessage() + ]); + } + } +} diff --git a/app/admin/route/routes/email.php b/app/admin/route/routes/email.php new file mode 100644 index 0000000..9fcd073 --- /dev/null +++ b/app/admin/route/routes/email.php @@ -0,0 +1,12 @@ + +// +---------------------------------------------------------------------- + +namespace app\model\System; + +use think\Model; +use think\model\concern\SoftDelete; + +/** + * 系统邮箱模型 + */ +class SystemEmail extends Model +{ + + // 数据库表名 + protected $name = 'mete_system_email'; + + // 字段类型转换 + protected $type = [ + 'id' => 'integer', + 'from_address' => 'string', + 'from_name' => 'string', + 'host' => 'string', + 'port' => 'integer', + 'username' => 'string', + 'password' => 'string', + 'encryption' => 'string', + 'timeout' => 'integer', + 'create_time' => 'datetime', + 'update_time' => 'datetime', + ]; + + +} diff --git a/composer.json b/composer.json index cf5bb73..e677309 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "topthink/think-orm": "^3.0|^4.0", "topthink/think-filesystem": "^2.0|^3.0", "topthink/think-multi-app": "^1.1", - "firebase/php-jwt": "^7.0" + "firebase/php-jwt": "^7.0", + "phpmailer/phpmailer": "^7.0" }, "require-dev": { "topthink/think-dumper": "^1.0", diff --git a/composer.lock b/composer.lock index fcab430..8749f47 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ca7c2e934d0d1625582732e674763e2b", + "content-hash": "443a61929bdea69fd539a3088dea886f", "packages": [ { "name": "firebase/php-jwt", @@ -270,6 +270,88 @@ ], "time": "2024-09-21T08:32:55+00:00" }, + { + "name": "phpmailer/phpmailer", + "version": "v7.0.2", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088", + "reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^10.0.0@dev", + "squizlabs/php_codesniffer": "^3.13.5", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", + "directorytree/imapengine": "For uploading sent messages via IMAP, see gmail example", + "ext-imap": "Needed to support advanced email address parsing according to RFC822", + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v7.0.2" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2026-01-09T18:02:33+00:00" + }, { "name": "psr/cache", "version": "1.0.1",