Files
kiri-mail-server/GUIDE.md
T

392 lines
8.8 KiB
Markdown
Raw Normal View History

2026-06-28 19:42:35 +08:00
# kiri-mail-server 部署使用指南
## 一、安装
```bash
composer require game-worker/kiri-mail-server
```
---
## 二、创建配置文件
将默认配置复制到你的项目:
```bash
cp vendor/game-worker/kiri-mail-server/config/mail.php config/mail.php
```
编辑 `config/mail.php`
```php
<?php
return [
'smtp' => [
'host' => '0.0.0.0',
'port' => 25,
'hostname' => 'mail.yourdomain.com', // ← 改成你的域名
],
'imap' => [
'host' => '0.0.0.0',
'port' => 143,
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
],
'storage' => [
'path' => '/data/mail', // ← 邮件存储目录,确保可写
],
'domains' => [
'local' => ['yourdomain.com'], // ← 你的域名
],
'database' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'port' => 3306,
'database' => 'mail',
'username' => 'root',
'password' => 'your_mysql_password', // ← 改成你的密码
],
'auth' => [
'type' => 'simple', // 快速测试用 simple,生产用 database(见第五节)
'users' => [ // 仅 simple 模式有效
'admin@yourdomain.com' => 'password123',
],
'require_auth_for_send' => true,
],
];
```
---
## 三、选择认证模式
### 模式 A:简单配置认证(测试用)
```php
'auth' => [
'type' => 'simple',
'users' => [
'user1@yourdomain.com' => 'mypassword',
'user2@yourdomain.com' => 'anotherpassword',
],
],
```
### 模式 B:数据库认证(生产用)
`config/databases.php` 中添加 mail 连接:
```php
// config/databases.php
return [
'connections' => [
// 原有连接...
'db' => [ /* ... */ ],
// 新增邮件数据库连接
'mail' => [
'id' => 'mail',
'cds' => 'mysql:host=127.0.0.1;port=3306;dbname=mail',
'username' => 'root',
'password' => 'yourpassword',
'database' => 'mail',
'tablePrefix' => '',
'driver' => 'mysql',
'charset' => 'utf8mb4',
'pool' => ['min' => 1, 'max' => 10],
],
],
];
```
执行 SQL 迁移:
```bash
mysql -u root -p mail < vendor/game-worker/kiri-mail-server/migrations/001_init.sql
```
`config/mail.php` 中设置:
```php
'auth' => [
'type' => 'database',
],
```
---
## 四、注册进程
编辑 `config/servers.php`
```php
return [
'process' => [
\Kiri\MailServer\SmtpServerProcess::class, // SMTP 收信 :25
\Kiri\MailServer\ImapServerProcess::class, // IMAP 读信 :143
\Kiri\MailServer\OutboundDeliveryProcess::class, // 外发投递
],
];
```
启动服务:
```bash
php kiri.php sw:server start
```
---
## 五、注册 Webmail 路由
创建 `app/Controller/MailWebController.php`
```php
<?php
namespace App\Controller;
use Kiri\Router\Annotate\Get;
use Kiri\Router\Annotate\Post;
use Kiri\Router\Base\Controller;
use Kiri\MailServer\WebmailViews;
use Kiri\MailServer\Controller\MailApiController;
use Kiri\MailServer\Auth\DatabaseAuth;
use Kiri\MailServer\Storage\MaildirStorage;
use Kiri\MailServer\MailQueue;
class MailWebController extends Controller
{
private MailApiController $api;
public function init(): void
{
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$storage = new MaildirStorage('/data/mail');
$mailQueue = new MailQueue($redis);
$auth = new DatabaseAuth();
$this->api = new MailApiController($auth, $storage, $mailQueue);
}
#[Get('/webmail')]
public function index(): string
{
return WebmailViews::loginPage();
}
#[Post('/webmail/login')]
public function login(): string
{
$email = $this->request->post('email');
$password = $this->request->post('password');
if ($this->api->verifyCredentials($email, $password)) {
// 生产环境应使用 Session 或 JWT
$url = '/webmail/inbox?email=' . urlencode($email);
return $this->response->withHeader('Location', $url)->withStatus(302);
}
return WebmailViews::loginPage();
}
#[Get('/webmail/inbox')]
public function inbox(): string
{
$email = $_GET['email'] ?? '';
$data = $this->api->list($email);
return WebmailViews::inboxPage($email, $data['messages'] ?? []);
}
#[Get('/webmail/read')]
public function read(): string
{
$email = $_GET['email'] ?? '';
$id = $_GET['id'] ?? '';
$data = $this->api->read($email, $id);
return WebmailViews::readPage($email, $data);
}
}
```
---
## 六、创建管理面板路由
创建 `app/Controller/MailAdminController.php`
```php
<?php
namespace App\Controller;
use Kiri\Router\Annotate\Get;
use Kiri\Router\Annotate\Post;
use Kiri\Router\Base\Controller;
use Kiri\MailServer\WebmailViews;
use Kiri\MailServer\Controller\AdminApiController;
use Kiri\MailServer\MailQueue;
use Kiri\MailServer\Model\Database;
class MailAdminController extends Controller
{
private AdminApiController $api;
public function init(): void
{
Database::init(config('mail.database'));
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$mailQueue = new MailQueue($redis);
$this->api = new AdminApiController($mailQueue);
}
#[Get('/admin')]
public function dashboard(): string
{
$domains = $this->api->listDomains()['domains'] ?? [];
$queueStats = $this->api->queueStats();
return WebmailViews::adminDashboard($domains, $queueStats);
}
#[Get('/admin/users')]
public function users(): string
{
$domainId = (int)($_GET['domain_id'] ?? 0);
$users = $this->api->listUsers($domainId)['users'] ?? [];
return WebmailViews::adminUsers($users, "Domain #{$domainId}");
}
#[Post('/api/admin/domains/create')]
public function createDomain(): string
{
$result = $this->api->createDomain(
$this->request->post('domain'),
$this->request->post('description', ''),
(int)$this->request->post('max_users', 100),
(int)$this->request->post('max_quota', 0),
);
return json_encode($result);
}
#[Post('/api/admin/users/create')]
public function createUser(): string
{
$result = $this->api->createUser(
$this->request->post('email'),
(int)$this->request->post('domain_id'),
$this->request->post('password'),
);
return json_encode($result);
}
}
```
---
## 七、测试验证
### 测试 SMTP 收信
```bash
# 连接 SMTP 服务器
telnet localhost 25
# 发送测试邮件
EHLO test
MAIL FROM:<sender@external.com>
RCPT TO:<admin@yourdomain.com>
DATA
From: sender@external.com
To: admin@yourdomain.com
Subject: Test Email
Hello, this is a test email.
.
QUIT
```
### 发送外部邮件
```bash
# 使用认证 (AUTH PLAIN)
telnet localhost 25
EHLO test
AUTH PLAIN AG1haWwAMTIzNA== # base64(\0user\0pass)
MAIL FROM:<admin@yourdomain.com>
RCPT TO:<friend@gmail.com>
DATA
From: admin@yourdomain.com
To: friend@gmail.com
Subject: Outbound Test
Hello from my mail server!
.
QUIT
```
检查队列状态:
```bash
redis-cli
> ZCARD mail:queue:outbound # 待发送数
> ZCARD mail:queue:outbound:dead # 死信数
```
### 测试 IMAP 读信
```bash
telnet localhost 143
A001 LOGIN admin@yourdomain.com password123
A002 SELECT INBOX
A003 FETCH 1:* (FLAGS BODY[])
A004 LOGOUT
```
### 测试 Webmail
```bash
# 浏览器访问
open http://localhost:9501/webmail
```
---
## 八、DNS 记录配置(生产环境必须)
在你的 DNS 管理后台添加:
| 类型 | 名称 | 值 | 说明 |
|------|------|-----|------|
| **A** | `mail` | `你的服务器IP` | 邮件服务器主机 |
| **MX** | `@` | `mail.yourdomain.com` | 邮件路由,优先级 10 |
| **TXT** | `@` | `v=spf1 mx -all` | SPF 记录 |
| **TXT** | `mail._domainkey` | `v=DKIM1; k=rsa; p=你的公钥` | DKIM 签名(需先生成密钥) |
生成 DKIM 密钥:
```bash
openssl genrsa -out dkim_private.pem 2048
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem
# 将公钥内容放入 DNS TXT 记录: mail._domainkey.yourdomain.com
```
---
## 九、检查清单
- [ ] `config/mail.php``hostname` 改为真实域名
- [ ] `domains.local` 添加了真实域名
- [ ] `storage.path` 目录存在且可写
- [ ] Redis 服务已启动 (`redis-cli ping`)
- [ ] MySQL 数据库已创建并迁移
- [ ] DNS MX 记录已配置(指向 `mail.yourdomain.com`
- [ ] DNS SPF 记录已配置
- [ ] 防火墙开放端口 25、143、587
- [ ] `config/servers.php` 注册了三个进程