Files
kiri-mail-server/GUIDE.md
T
2026-06-28 19:42:35 +08:00

392 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 注册了三个进程