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` 注册了三个进程
|