392 lines
8.8 KiB
Markdown
392 lines
8.8 KiB
Markdown
# 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` 注册了三个进程
|