up: readme

This commit is contained in:
2026-08-20 11:54:46 +08:00
parent 975fd34f61
commit d1ffd10408
2 changed files with 598 additions and 12 deletions
+570
View File
@@ -0,0 +1,570 @@
# MailGo
> English | [中文](README_cn.md)
A lightweight mail system written in Go, integrating SMTP / IMAP / POP3 protocol servers and a web admin interface.
Web frontend layout: top navigation + left folder sidebar + mail list (three-column design).
## Features
- **Mail protocols**: SMTP (send), IMAP (sync), POP3 (receive), all with TLS support
- **External delivery**: authenticated users can send mail to external addresses (Gmail/Outlook, etc.), with a built-in outbound queue, **concurrent worker pool delivery** (default 4 workers + max 2 concurrent connections per recipient domain), direct MX delivery, STARTTLS, exponential backoff retry, bounce notifications and DKIM signing
- **Web mail**: folder data-driven (Web and IMAP share the same MailboxService — whatever IMAP LIST returns is what the UI shows), system folders (Inbox / Sent / Drafts / Trash) plus custom folder management, delete moves to Trash (with restore / permanent delete / empty Trash), unread badges and search filters, select-all / batch delete, sender avatars, rich text editing (Quill.js), attachment upload/download
- **Admin console**: domain management, user management, automatic DKIM key generation, DNS configuration hints, full mail browsing, outbound queue management, IP ban management, dashboard statistics, all timestamps displayed as 12-hour format (AM/PM) in the web timezone
- **Protocol call logs**: every SMTP/IMAP/POP3 connection automatically records source IP, username, success/failure, failure reason and operation summary; filterable by protocol/status/IP/user/time for analyzing password brute-force, relay abuse and other attacks (kept 30 days by default, auto-cleaned)
- **IMAP new-mail push**: real-time push after local delivery (SMTP/Web compose) — clients hanging on IDLE receive new-mail notifications instantly (no polling); read/star/delete changes made by other clients are also synced in real time (IMAP STORE/EXPUNGE, POP3 delete, Web mark-read/delete)
- **Live connection monitoring**: admin console shows active SMTP/IMAP/POP3 connections (source IP, username, TLS, duration), auto-refreshing every 5 seconds; "Disconnect and ban" one-click bans all connections of that IP (ban for 180 days, unban anytime)
- **External auth**: OAuth2 (Google / GitHub), LDAP (optional, disabled by default)
- **Security**: BCrypt password hashing, automatic IP ban on login failures (**tiered bans**: the first 3 times reaching the failure threshold only count without banning, from the 4th time on it bans with escalating durations 30 min → 3 h → 3 months → 6 months, cleared on successful login; **no grace for enumeration attacks**: failures with a non-existent username skip the grace period and are banned on first trigger), outbound rate limiting (anti-abuse), relay denied to unauthenticated users (anti-open-relay), admins can unban
- **Multiple databases**: SQLite by default, switchable to MySQL
- **Cross-platform**: Linux production deployment + Windows local debugging
## Screenshots
| Inbox | Mail view |
|-------|-----------|
| ![Inbox](docs/screenshots/inbox.png) | ![Mail view](docs/screenshots/view.png) |
| Compose | Settings | Login |
|---------|----------|-------|
| ![Compose](docs/screenshots/compose.png) | ![Settings](docs/screenshots/settings.png) | ![Login](docs/screenshots/login.png) |
> Screenshots are rendered with demo data; the actual UI may differ from your deployment.
## Quick Start
### Build
```bash
go build -o mailgo .
```
### Start
```bash
./mailgo
```
On first start the config file and database are created automatically, along with the default admin account:
| Item | Value |
|------|-------|
| Email | `admin@example.com` |
| Initial password | Randomly generated (16 chars, digits + upper/lowercase letters), printed once in the startup log; or pre-set via the `MAILGO_ADMIN_PASSWORD` environment variable |
> ⚠️ This account is flagged "must change password on first login" — change it immediately on the Settings page.
### Access
| Page | URL |
|------|-----|
| User mailbox | `http://localhost:8080/` |
| Admin console | `http://localhost:8080/admin` |
---
## Configuration File
Config file path (TOML format):
| System | Path |
|--------|------|
| Linux | `/etc/mail_go/mail_go.toml` |
| Windows | `./win/etc/mail_go/mail_go.toml` |
Auto-generated on first start; missing fields are auto-filled. A restart is required for changes to take effect.
### Full Configuration Reference
```toml
[database]
driver = "sqlite" # sqlite | mysql
dsn = "/srv/mail_go/mail.db" # SQLite: file path; MySQL: DSN string
[storage]
base_dir = "/srv/mail_go" # data root directory
attach_dir = "/srv/mail_go/attachments" # attachment storage directory
[web]
addr = ":8080" # listen address; TCP port or Unix socket
secret_key = "" # web session signing key; if empty, a random
# key is generated on first start and written
# to this file (back it up: leaking it allows
# forging sessions, losing it invalidates all)
cookie_secure = true # session cookie sent over HTTPS only (Secure
# flag); set to false only for local HTTP debug
protocol_log_keep_days = 30 # retention days for SMTP/IMAP/POP3 protocol
# call logs; expired entries are cleaned up by a
# background task; 0 disables cleanup
[smtp]
addr = ":25" # SMTP plaintext port
tls_addr = ":465" # SMTPS port (requires TLS certs)
domain = "example.com" # mail domain
tls_cert = "" # TLS certificate path (empty = TLS disabled)
tls_key = "" # TLS private key path
max_message_bytes = 67108864 # max 64MB per message
[imap]
addr = ":143" # IMAP plaintext port
tls_addr = ":993" # IMAPS port
tls_cert = ""
tls_key = ""
[pop3]
addr = ":110" # POP3 plaintext port
tls_addr = ":995" # POP3S port
tls_cert = ""
tls_key = ""
[auth]
oauth2_enabled = false # enable OAuth2 login
oauth2_provider = "" # google | github
oauth2_client_id = ""
oauth2_client_secret = ""
oauth2_redirect_url = ""
ldap_enabled = false # enable LDAP login
ldap_server = "" # e.g. ldap://localhost:389
ldap_bind_dn = "" # e.g. cn=admin,dc=example,dc=com
ldap_bind_password = ""
ldap_search_base = "" # e.g. ou=users,dc=example,dc=com
ldap_search_filter = "" # e.g. (uid=%s)
ldap_use_tls = false
[ban]
max_fail_attempts = 5 # login failure threshold
ban_duration_min = 30 # 1st ban duration (minutes); then escalates:
# 2nd 3h → 3rd 3 months → 4th+ 6 months (cap)
# first 3 threshold hits only count, no ban;
# cleared on successful login
[caddy]
data_dir = "" # Caddy data directory (the one containing
# certificates/), used for one-click cert import
# in the admin console; auto-detected when empty
# (e.g. /var/lib/caddy/.local/share/caddy)
[outbound]
hostname = "" # EHLO hostname; defaults to [smtp] domain
poll_interval = 15 # outbound queue scan interval (seconds)
workers = 4 # concurrent delivery workers (parallel sends,
# improves throughput for bulk mail; 0/1 serial)
batch_size = 50 # max messages picked per scan
max_concurrent_per_domain = 2 # max concurrent connections to one recipient
# domain (or relay), prevents spam-lookalike
# bursts; 0 = unlimited
max_attempts = 12 # max delivery attempts per message
retry_base_min = 5 # retry backoff base (minutes), exponential:
# 5/10/20/40...
max_recipients = 50 # max external recipients per message
max_per_min = 30 # max outgoing messages per user per minute
max_per_day = 500 # max outgoing messages per user per day;
# 0 disables external delivery
connect_timeout = 30 # remote MX connect timeout (seconds)
relay_host = "" # smarthost; empty = direct MX delivery
relay_port = 587 # 465 = implicit TLS, other ports use STARTTLS
relay_user = "" # relay auth username (AUTH PLAIN)
relay_password = "" # relay auth password
relay_starttls = true # use STARTTLS on non-465 ports
relay_tls_insecure = false # skip relay TLS certificate verification; certs
# are verified by default (protects relay
# credentials); only set to true for self-signed
# intranet relays when you accept the risk
ip_family = "ipv4" # outbound address family: ipv4 (default) | ipv6 | auto
source_ip = "" # outbound source IP binding (e.g. static IPv6);
# empty = kernel picks
```
---
## Common Configuration Scenarios
### 1. Switching to MySQL
```toml
[database]
driver = "mysql"
dsn = "mailgo:YourPassword@tcp(127.0.0.1:3306)/mailgo?charset=utf8mb4&parseTime=True&loc=Local"
```
MySQL DSN format: `user:password@tcp(host:port)/dbname?params`
> The database and user must be created in MySQL first:
> ```sql
> CREATE DATABASE mailgo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
> CREATE USER 'mailgo'@'localhost' IDENTIFIED BY 'YourPassword';
> GRANT ALL PRIVILEGES ON mailgo.* TO 'mailgo'@'localhost';
> FLUSH PRIVILEGES;
> ```
### 2. Web over Unix Socket
```toml
[web]
addr = "/run/mail_go/web.sock"
```
When `addr` starts with `/`, Gin listens on a Unix socket automatically.
### 3. Setting the Session Key (Container / Multi-Instance)
The session signing key can be overridden via the `MAILGO_SECRET_KEY` environment variable (takes precedence over the config file and is never written to disk):
```bash
MAILGO_SECRET_KEY="$(openssl rand -hex 32)" mail_go
```
Requirement: at least 16 bytes; when empty, the value from the config file is used (auto-generated on first start). After changing the key, all logged-in sessions are invalidated immediately and users must log in again.
Nginx reverse proxy configuration:
```nginx
server {
listen 80;
server_name mail.example.com;
location / {
proxy_pass http://unix:/run/mail_go/web.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
> Make sure the socket directory exists and is writable:
> ```bash
> mkdir -p /run/mail_go
> chown mailgo:mailgo /run/mail_go
> ```
### 4. Enabling TLS Encryption
Enable TLS for SMTP/IMAP/POP3 (all three protocols can share one certificate, or be configured separately):
```toml
[smtp]
tls_cert = "/etc/mail_go/certs/server.crt"
tls_key = "/etc/mail_go/certs/server.key"
[imap]
tls_cert = "/etc/mail_go/certs/server.crt"
tls_key = "/etc/mail_go/certs/server.key"
[pop3]
tls_cert = "/etc/mail_go/certs/server.crt"
tls_key = "/etc/mail_go/certs/server.key"
```
Once TLS is configured, the corresponding encrypted ports (465/993/995) start automatically. Checking the TLS box when adding a domain in the admin console switches the ports automatically.
> You can get free certificates from Let's Encrypt:
> ```bash
> certbot certonly --standalone -d mail.example.com
> # Certificate: /etc/letsencrypt/live/mail.example.com/fullchain.pem
> # Private key: /etc/letsencrypt/live/mail.example.com/privkey.pem
> ```
#### One-Click Certificate Import from Caddy
If this machine already serves HTTPS for the domain via [Caddy](https://caddyserver.com/) (Caddy issues and renews certificates automatically),
you can click **"Fetch certificate from Caddy"** on the **Domain Management → Edit Domain** page in the admin console
to import the certificate and private key from Caddy's storage into the mail server (automatically enabling TLS for that domain), without manually copying PEM files.
Wildcard certificates are supported (e.g. `*.example.com` matches `mail.example.com`).
Certificates support **hot reload**: they take effect immediately after import (or manual upload) without restarting the service — SMTP/IMAP/POP3
re-check and reload changed certificate files on every TLS handshake.
Because Caddy's certificate directory is only readable by the `caddy` user, install.sh installs a root-privileged certificate sync job
(`mailgo-caddy-sync.{path,timer}`) that mirrors Caddy's certificate tree to `/srv/mail_go/tls/caddy`,
so mail_go can always read it after renewals; an ACL grant is also applied as a fallback for direct reads.
This is configured automatically during installation, or can be run manually:
```bash
sudo ./install.sh setup-caddy-cert # auto-detect Caddy data dir, configure sync + ACL
sudo ./install.sh setup-caddy-cert /path/to/caddy/data # or specify the data dir manually
```
If Caddy's data directory is not in a common location, specify it explicitly in the config file:
```toml
[caddy]
data_dir = "/var/lib/caddy/.local/share/caddy"
```
### 5. Enabling OAuth2 Login (Google Example)
```toml
[auth]
oauth2_enabled = true
oauth2_provider = "google"
oauth2_client_id = "your-client-id.apps.googleusercontent.com"
oauth2_client_secret = "your-client-secret"
oauth2_redirect_url = "https://mail.example.com/auth/oauth2/callback"
```
> You need to create an OAuth 2.0 client in the [Google Cloud Console](https://console.cloud.google.com/) and set the authorized redirect URI to `https://your-domain/auth/oauth2/callback`.
### 6. Enabling LDAP Authentication
```toml
[auth]
ldap_enabled = true
ldap_server = "ldap://ldap.example.com:389"
ldap_bind_dn = "cn=admin,dc=example,dc=com"
ldap_bind_password = "ldap_admin_password"
ldap_search_base = "ou=users,dc=example,dc=com"
ldap_search_filter = "(uid=%s)"
ldap_use_tls = true
```
### 7. Sending Mail to External Recipients (External Delivery)
Authenticated users (Web mail / SMTP submission) can send mail to external addresses. The system
delivers directly via the recipient domain's MX records, handling STARTTLS and exponential backoff
retries automatically, and DKIM-signs outgoing mail (using the key generated in the admin domain management).
```toml
[smtp]
domain = "example.com" # must be the real mail domain (EHLO/bounce address)
[outbound]
hostname = "mail.example.com" # recommended to match the mail hostname
poll_interval = 15
max_attempts = 12
max_per_day = 500 # set to 0 to disable external delivery entirely
```
Required DNS / server prerequisites (see `todo.md` and the admin DNS hints page for details):
| Item | Description |
|------|-------------|
| MX | `example.com MX 10 mail.example.com` |
| SPF | `example.com TXT "v=spf1 mx -all"` |
| DKIM | `default._domainkey.example.com TXT "v=DKIM1; k=rsa; p=<public key>"` (auto-generated in the admin console) |
| DMARC | `_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:postmaster@example.com"` |
| PTR | Server IP reverse-resolves to the mail hostname (request from your hosting provider) |
| Network | Port 25 outbound is not blocked by the cloud provider |
Security policy: external recipients are only accepted from authenticated users; `MAIL FROM` must match
the logged-in user; per-user per-minute/day outbound limits apply; failed mail bounces back to the
sender's inbox; admins can view delivery status in the **Outbound Queue** and manually retry or cancel.
> **IPv4/IPv6**: Only IPv4 outbound is used by default (`ip_family = "ipv4"`), because many recipients
> (e.g. Gmail) reject IPv6 addresses without PTR, while IPv4 usually has matching forward/reverse PTR.
> To use IPv6: ask your provider to configure PTR for the static address (pointing to `mail.example.com`),
> then set `ip_family = "ipv6"` and bind `source_ip` to that static address
> (to avoid the kernel picking rotating temporary privacy addresses).
### 8. Relaying Outbound Mail Through a Smarthost
When the server IP is on a residential/dynamic IP range, it is often listed in policy lists such as Spamhaus PBL,
and recipients like Microsoft (Outlook/Hotmail) reject the mail outright. In that case, it is recommended to hand
outbound mail to a third-party SMTP relay (Mailgun / SendGrid / Amazon SES / Aliyun Direct Mail, etc.),
configured in `[outbound]` — all external delivery automatically routes through the relay:
```toml
[outbound]
relay_host = "smtp.example-relay.com"
relay_port = 587 # 465 = implicit TLS
relay_user = "your-api-user"
relay_password = "your-api-key"
relay_starttls = true
```
The relay uses AUTH PLAIN authentication; local recipients still use local delivery, unaffected.
### 9. Setting the Initial Admin Password
When the admin account is created on first start, the initial password is randomly generated by default
and printed once in the startup log; to pre-set it (e.g. for deployment scripts), use the `MAILGO_ADMIN_PASSWORD`
environment variable:
```bash
MAILGO_ADMIN_PASSWORD="$(openssl rand -base64 12)" ./mailgo
```
This variable only takes effect when the admin account is first created (ignored if the account already exists);
either way, the password must be changed on first login.
---
## Port Quick Reference
| Protocol | Plaintext port | TLS port | Description |
|----------|----------------|----------|-------------|
| SMTP | 25 | 465 | Mail sending |
| IMAP | 143 | 993 | Mailbox sync |
| POP3 | 110 | 995 | Mail retrieval |
| Web | 8080 | — | Web UI (Unix socket supported) |
---
## Directory Structure
```
mailgo/
├── main.go # program entry
├── config/
│ ├── config.go # config loading and merging
│ └── defaults.go # default constants
├── internal/
│ ├── db/
│ │ ├── db.go # database initialization (SQLite/MySQL)
│ │ └── models.go # GORM model definitions
│ ├── store/
│ │ ├── stores.go # Store aggregator
│ │ ├── user_store.go # user data operations
│ │ ├── mail_store.go # mail data operations
│ │ ├── mailbox_store.go # folder (IMAP mailbox) data operations
│ │ ├── domain_store.go # domain data operations
│ │ ├── attachment_store.go # attachment data operations
│ │ ├── outbound_store.go # outbound queue data operations
│ │ ├── ban_store.go # ban data operations
│ │ └── protocol_log_store.go # protocol call log data operations
│ ├── smtp_server/server.go # SMTP server
│ ├── outbound/
│ │ ├── mailer.go # MX lookup and SMTP outbound client
│ │ ├── manager.go # outbound queue, retry, rate limiting, bounces
│ │ └── sign.go # DKIM signing
│ ├── imap_server/
│ │ ├── server.go # IMAP server (listener/capabilities/cross-session push)
│ │ ├── service.go # MailboxService (shared by IMAP sessions and Web)
│ │ └── session.go # IMAP Session implementation (SELECT/FETCH/STORE/EXPUNGE)
│ ├── pop3_server/server.go # POP3 server
│ ├── connhub/hub.go # protocol connection registry (live connection monitoring)
│ ├── storage/attachment.go # attachment file storage
│ ├── dkim/keys.go # DKIM key generation
│ ├── auth/
│ │ ├── provider.go # auth interface
│ │ ├── oauth2.go # OAuth2 authentication
│ │ └── ldap.go # LDAP authentication
│ └── web/
│ ├── server.go # web routing and template loading
│ ├── handlers/
│ │ ├── auth.go # login/logout/OAuth2/LDAP
│ │ ├── mail.go # mailbox operations
│ │ └── admin.go # admin console
│ ├── middleware/
│ │ ├── auth.go # session authentication
│ │ ├── admin.go # admin authorization
│ │ └── ban.go # IP ban check
│ └── templates/ # HTML templates
│ ├── *.html # user pages
│ └── admin/*.html # admin pages
└── .gitignore
```
### Runtime Data Directories (Linux)
| Path | Description |
|------|-------------|
| `/etc/mail_go/` | config file |
| `/srv/mail_go/` | database + attachment storage |
### Runtime Data Directories (Windows Debug)
| Path | Description |
|------|-------------|
| `./win/etc/mail_go/` | config file |
| `./win/srv/mail_go/` | database + attachment storage |
---
## Linux Service Deployment
### systemd Unit File
Create `/etc/systemd/system/mailgo.service`:
```ini
[Unit]
Description=MailGo Mail Server
After=network.target mysql.service
[Service]
Type=simple
User=mailgo
Group=mailgo
WorkingDirectory=/opt/mailgo
ExecStart=/opt/mailgo/mailgo
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/srv/mail_go /run/mail_go /etc/mail_go
[Install]
WantedBy=multi-user.target
```
### Starting the Service
```bash
# Create the system user
sudo useradd -r -s /sbin/nologin -d /srv/mail_go mailgo
# Set directory ownership
sudo chown -R mailgo:mailgo /srv/mail_go /etc/mail_go
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable mailgo
sudo systemctl start mailgo
# View logs
sudo journalctl -u mailgo -f
```
---
## DNS Configuration
The mail service requires the following DNS records (the admin console → DNS hints page shows the full configuration):
| Type | Name | Value | Description |
|------|------|-------|-------------|
| A | mail | server IP | mail server address |
| MX | @ | mail.example.com | mail routing |
| TXT | @ | `v=spf1 mx ~all` | SPF anti-spam |
| TXT | default._domainkey | DKIM public key (auto-generated in the admin console) | DKIM signature verification |
| TXT | _dmarc | `v=DMARC1; p=none; rua=mailto:admin@example.com` | DMARC policy |
---
## Tech Stack
| Component | Technology |
|-----------|------------|
| Language | Go 1.25+ |
| Web framework | Gin |
| Template engine | html/template |
| ORM | GORM |
| Database | SQLite (default) / MySQL |
| Config format | TOML |
| SMTP | github.com/emersion/go-smtp |
| IMAP | github.com/emersion/go-imap/v2 |
| POP3 | hand-implemented TCP protocol |
| Password hashing | golang.org/x/crypto/bcrypt |
| Rich text | Quill.js (embedded via go:embed, works offline) |
| OAuth2 | golang.org/x/oauth2 |
| LDAP | github.com/go-ldap/ldap/v3 |
| DKIM | RSA 2048 auto-generated |
---
## Default Account
| Role | Email | Initial password | Default quota |
|------|-------|------------------|---------------|
| Admin | admin@example.com | Randomly generated (printed once in the startup log) or set via `MAILGO_ADMIN_PASSWORD` | 5 GB |
> ⚠️ Password change is mandatory on first login (also triggered when an admin resets the password); change it immediately after production deployment.
## License
MIT
+28 -12
View File
@@ -1,19 +1,21 @@
# MailGo # MailGo
> [English](README.md) | 中文
Go 语言编写的轻量级邮件系统,集成 SMTP / IMAP / POP3 协议服务和 Web 管理界面。 Go 语言编写的轻量级邮件系统,集成 SMTP / IMAP / POP3 协议服务和 Web 管理界面。
Web 前端采用 QQ 邮箱风格的布局:顶部导航 + 左侧文件夹栏 + 邮件列表三栏设计。 Web 前端的布局:顶部导航 + 左侧文件夹栏 + 邮件列表三栏设计。
## 功能特性 ## 功能特性
- **邮件协议**:SMTP(发送)、IMAP(同步)、POP3(收取),均支持 TLS 加密 - **邮件协议**:SMTP(发送)、IMAP(同步)、POP3(收取),均支持 TLS 加密
- **外部投递**:认证用户可向外部邮箱(QQ/Gmail/Outlook 等)发送邮件,内置外发队列、**并发 worker 池投递**(默认 4 线程 + 每收件域并发上限 2)、MX 直投、STARTTLS、指数退避重试、退信通知与 DKIM 签名 - **外部投递**:认证用户可向外部邮箱(Gmail/Outlook 等)发送邮件,内置外发队列、**并发 worker 池投递**(默认 4 线程 + 每收件域并发上限 2)、MX 直投、STARTTLS、指数退避重试、退信通知与 DKIM 签名
- **Web 邮箱**QQ 邮箱风格界面,支持收件箱 / 已发送 / 草稿箱、未读角标与搜索过滤、全选 / 批量删除、发件人头像、富文本编辑(Quill.js)、附件上传/下载 - **Web 邮箱**文件夹数据驱动(Web 与 IMAP 共享 MailboxServiceIMAP LIST 返回什么界面就显示什么),系统文件夹(收件箱 / 已发送 / 草稿箱 / 垃圾箱)与自定义文件夹管理、删除邮件移入垃圾箱(支持恢复 / 彻底删除 / 清空)、未读角标与搜索过滤、全选 / 批量删除、发件人头像、富文本编辑(Quill.js)、附件上传/下载
- **管理后台**:域名管理、用户管理、DKIM 密钥自动生成、DNS 配置提示、全量邮件查看、外发队列管理、IP 封禁管理、仪表盘统计 - **管理后台**:域名管理、用户管理、DKIM 密钥自动生成、DNS 配置提示、全量邮件查看、外发队列管理、IP 封禁管理、仪表盘统计、时间统一按 Web 时区显示 12 小时制(上午/下午)
- **协议调用日志**SMTP / IMAP / POP3 每次连接自动记录来源 IP、用户名、成功/失败、失败原因与操作摘要,可按协议/状态/IP/用户名/时间筛选,用于分析密码爆破、中继滥用等攻击行为(默认保留 30 天,自动清理) - **协议调用日志**SMTP / IMAP / POP3 每次连接自动记录来源 IP、用户名、成功/失败、失败原因与操作摘要,可按协议/状态/IP/用户名/时间筛选,用于分析密码爆破、中继滥用等攻击行为(默认保留 30 天,自动清理)
- **IMAP 新邮件推送**:本地投递(SMTP/Web 写信)成功后实时推送,挂起 IDLE 的客户端即时收到新邮件通知(无需轮询);其他客户端造成的已读/星标/删除变化也实时同步(IMAP STORE/EXPUNGE、POP3 删除、Web 标已读/删除) - **IMAP 新邮件推送**:本地投递(SMTP/Web 写信)成功后实时推送,挂起 IDLE 的客户端即时收到新邮件通知(无需轮询);其他客户端造成的已读/星标/删除变化也实时同步(IMAP STORE/EXPUNGE、POP3 删除、Web 标已读/删除)
- **当前连接监控**:管理后台实时查看 SMTP/IMAP/POP3 活动连接(来源 IP、用户名、TLS、时长),每 5 秒自动刷新;支持「断开并封禁」一键封禁该 IP 全部在线连接(封禁 180 天,可随时解封) - **当前连接监控**:管理后台实时查看 SMTP/IMAP/POP3 活动连接(来源 IP、用户名、TLS、时长),每 5 秒自动刷新;支持「断开并封禁」一键封禁该 IP 全部在线连接(封禁 180 天,可随时解封)
- **外部认证**OAuth2Google / GitHub)、LDAP(可选,默认关闭) - **外部认证**OAuth2Google / GitHub)、LDAP(可选,默认关闭)
- **安全机制**:BCrypt 密码哈希、登录失败自动封禁 IP(**阶段性封禁**:前 3 次达到失败阈值只计数,第 4 次起封禁并按档位递增 30分钟 → 3小时 → 3个月 → 半年,成功登录清零)、外发频率限制(防滥用)、非认证禁止中继(防开放中继)、管理员可解封 - **安全机制**:BCrypt 密码哈希、登录失败自动封禁 IP(**阶段性封禁**:前 3 次达到失败阈值只计数,第 4 次起封禁并按档位递增 30分钟 → 3小时 → 3个月 → 半年,成功登录清零;**枚举爆破无宽限**:用户名不存在的失败跳过宽限、首次触发即封禁)、外发频率限制(防滥用)、非认证禁止中继(防开放中继)、管理员可解封
- **多数据库**:默认 SQLite,可切换 MySQL - **多数据库**:默认 SQLite,可切换 MySQL
- **跨平台**Linux 生产部署 + Windows 本地调试 - **跨平台**Linux 生产部署 + Windows 本地调试
@@ -48,9 +50,9 @@ go build -o mailgo .
| 项目 | 值 | | 项目 | 值 |
|------|-----| |------|-----|
| 邮箱 | `admin@example.com` | | 邮箱 | `admin@example.com` |
| 密码 | `admin` | | 初始密码 | 随机生成(16 位,数字+大小写字母),仅在启动日志中打印一次;也可用环境变量 `MAILGO_ADMIN_PASSWORD` 预先指定 |
> ⚠️ 请在生产环境中立即修改默认密码 > ⚠️ 该账户已标记「首次登录必须修改密码」,登录后请在 设置 页面立即改密
### 访问 ### 访问
@@ -363,6 +365,18 @@ relay_starttls = true
中继使用 AUTH PLAIN 认证;本地收件人仍走本地投递,不受影响。 中继使用 AUTH PLAIN 认证;本地收件人仍走本地投递,不受影响。
### 8. 指定初始管理员密码
首次启动创建管理员账户时,初始密码默认随机生成并仅在启动日志中打印一次;
如需预先指定(例如部署脚本),可设置环境变量 `MAILGO_ADMIN_PASSWORD`
```bash
MAILGO_ADMIN_PASSWORD="$(openssl rand -base64 12)" ./mailgo
```
该变量仅在首次创建管理员账户时生效(账户已存在则忽略);无论哪种方式,
首次登录都会强制修改密码。
--- ---
## 端口速查 ## 端口速查
@@ -392,6 +406,7 @@ mailgo/
│ │ ├── stores.go # Store 聚合器 │ │ ├── stores.go # Store 聚合器
│ │ ├── user_store.go # 用户数据操作 │ │ ├── user_store.go # 用户数据操作
│ │ ├── mail_store.go # 邮件数据操作 │ │ ├── mail_store.go # 邮件数据操作
│ │ ├── mailbox_store.go # 文件夹(IMAP mailbox)数据操作
│ │ ├── domain_store.go # 域名数据操作 │ │ ├── domain_store.go # 域名数据操作
│ │ ├── attachment_store.go # 附件数据操作 │ │ ├── attachment_store.go # 附件数据操作
│ │ ├── outbound_store.go # 外发队列数据操作 │ │ ├── outbound_store.go # 外发队列数据操作
@@ -404,6 +419,7 @@ mailgo/
│ │ └── sign.go # DKIM 签名 │ │ └── sign.go # DKIM 签名
│ ├── imap_server/ │ ├── imap_server/
│ │ ├── server.go # IMAP 服务(监听器/能力/跨会话推送) │ │ ├── server.go # IMAP 服务(监听器/能力/跨会话推送)
│ │ ├── service.go # MailboxServiceIMAP 会话与 Web 共享)
│ │ └── session.go # IMAP Session 实现(SELECT/FETCH/STORE/EXPUNGE │ │ └── session.go # IMAP Session 实现(SELECT/FETCH/STORE/EXPUNGE
│ ├── pop3_server/server.go # POP3 服务 │ ├── pop3_server/server.go # POP3 服务
│ ├── connhub/hub.go # 协议连接注册中心(当前连接监控) │ ├── connhub/hub.go # 协议连接注册中心(当前连接监控)
@@ -524,7 +540,7 @@ sudo journalctl -u mailgo -f
| IMAP | github.com/emersion/go-imap/v2 | | IMAP | github.com/emersion/go-imap/v2 |
| POP3 | 手工实现 TCP 协议 | | POP3 | 手工实现 TCP 协议 |
| 密码哈希 | golang.org/x/crypto/bcrypt | | 密码哈希 | golang.org/x/crypto/bcrypt |
| 富文本 | Quill.js (CDN) | | 富文本 | Quill.jsgo:embed 内嵌,离线可用) |
| OAuth2 | golang.org/x/oauth2 | | OAuth2 | golang.org/x/oauth2 |
| LDAP | github.com/go-ldap/ldap/v3 | | LDAP | github.com/go-ldap/ldap/v3 |
| DKIM | RSA 2048 自动生成 | | DKIM | RSA 2048 自动生成 |
@@ -533,11 +549,11 @@ sudo journalctl -u mailgo -f
## 默认账户 ## 默认账户
| 角色 | 邮箱 | 密码 | 默认配额 | | 角色 | 邮箱 | 初始密码 | 默认配额 |
|------|------|------|---------| |------|------|---------|---------|
| 管理员 | admin@example.com | admin | 5 GB | | 管理员 | admin@example.com | 随机生成(启动日志打印一次)或 `MAILGO_ADMIN_PASSWORD` 指定 | 5 GB |
> ⚠️ 部署到生产环境后请立即修改管理员密码 > ⚠️ 首次登录强制修改密码(管理员重置密码同样触发);部署到生产环境后请立即完成改密
## License ## License