diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf1143f --- /dev/null +++ b/README.md @@ -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="` (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 diff --git a/README_cn.md b/README_cn.md index 392de59..b157ccd 100644 --- a/README_cn.md +++ b/README_cn.md @@ -1,19 +1,21 @@ # MailGo +> [English](README.md) | 中文 + Go 语言编写的轻量级邮件系统,集成 SMTP / IMAP / POP3 协议服务和 Web 管理界面。 -Web 前端采用 QQ 邮箱风格的布局:顶部导航 + 左侧文件夹栏 + 邮件列表三栏设计。 +Web 前端的布局:顶部导航 + 左侧文件夹栏 + 邮件列表三栏设计。 ## 功能特性 - **邮件协议**:SMTP(发送)、IMAP(同步)、POP3(收取),均支持 TLS 加密 -- **外部投递**:认证用户可向外部邮箱(QQ/Gmail/Outlook 等)发送邮件,内置外发队列、**并发 worker 池投递**(默认 4 线程 + 每收件域并发上限 2)、MX 直投、STARTTLS、指数退避重试、退信通知与 DKIM 签名 -- **Web 邮箱**:QQ 邮箱风格界面,支持收件箱 / 已发送 / 草稿箱、未读角标与搜索过滤、全选 / 批量删除、发件人头像、富文本编辑(Quill.js)、附件上传/下载 -- **管理后台**:域名管理、用户管理、DKIM 密钥自动生成、DNS 配置提示、全量邮件查看、外发队列管理、IP 封禁管理、仪表盘统计 +- **外部投递**:认证用户可向外部邮箱(Gmail/Outlook 等)发送邮件,内置外发队列、**并发 worker 池投递**(默认 4 线程 + 每收件域并发上限 2)、MX 直投、STARTTLS、指数退避重试、退信通知与 DKIM 签名 +- **Web 邮箱**:文件夹数据驱动(Web 与 IMAP 共享 MailboxService,IMAP LIST 返回什么界面就显示什么),系统文件夹(收件箱 / 已发送 / 草稿箱 / 垃圾箱)与自定义文件夹管理、删除邮件移入垃圾箱(支持恢复 / 彻底删除 / 清空)、未读角标与搜索过滤、全选 / 批量删除、发件人头像、富文本编辑(Quill.js)、附件上传/下载 +- **管理后台**:域名管理、用户管理、DKIM 密钥自动生成、DNS 配置提示、全量邮件查看、外发队列管理、IP 封禁管理、仪表盘统计、时间统一按 Web 时区显示 12 小时制(上午/下午) - **协议调用日志**:SMTP / IMAP / POP3 每次连接自动记录来源 IP、用户名、成功/失败、失败原因与操作摘要,可按协议/状态/IP/用户名/时间筛选,用于分析密码爆破、中继滥用等攻击行为(默认保留 30 天,自动清理) - **IMAP 新邮件推送**:本地投递(SMTP/Web 写信)成功后实时推送,挂起 IDLE 的客户端即时收到新邮件通知(无需轮询);其他客户端造成的已读/星标/删除变化也实时同步(IMAP STORE/EXPUNGE、POP3 删除、Web 标已读/删除) - **当前连接监控**:管理后台实时查看 SMTP/IMAP/POP3 活动连接(来源 IP、用户名、TLS、时长),每 5 秒自动刷新;支持「断开并封禁」一键封禁该 IP 全部在线连接(封禁 180 天,可随时解封) - **外部认证**:OAuth2(Google / GitHub)、LDAP(可选,默认关闭) -- **安全机制**:BCrypt 密码哈希、登录失败自动封禁 IP(**阶段性封禁**:前 3 次达到失败阈值只计数,第 4 次起封禁并按档位递增 30分钟 → 3小时 → 3个月 → 半年,成功登录清零)、外发频率限制(防滥用)、非认证禁止中继(防开放中继)、管理员可解封 +- **安全机制**:BCrypt 密码哈希、登录失败自动封禁 IP(**阶段性封禁**:前 3 次达到失败阈值只计数,第 4 次起封禁并按档位递增 30分钟 → 3小时 → 3个月 → 半年,成功登录清零;**枚举爆破无宽限**:用户名不存在的失败跳过宽限、首次触发即封禁)、外发频率限制(防滥用)、非认证禁止中继(防开放中继)、管理员可解封 - **多数据库**:默认 SQLite,可切换 MySQL - **跨平台**:Linux 生产部署 + Windows 本地调试 @@ -48,9 +50,9 @@ go build -o mailgo . | 项目 | 值 | |------|-----| | 邮箱 | `admin@example.com` | -| 密码 | `admin` | +| 初始密码 | 随机生成(16 位,数字+大小写字母),仅在启动日志中打印一次;也可用环境变量 `MAILGO_ADMIN_PASSWORD` 预先指定 | -> ⚠️ 请在生产环境中立即修改默认密码。 +> ⚠️ 该账户已标记「首次登录必须修改密码」,登录后请在 设置 页面立即改密。 ### 访问 @@ -363,6 +365,18 @@ relay_starttls = true 中继使用 AUTH PLAIN 认证;本地收件人仍走本地投递,不受影响。 +### 8. 指定初始管理员密码 + +首次启动创建管理员账户时,初始密码默认随机生成并仅在启动日志中打印一次; +如需预先指定(例如部署脚本),可设置环境变量 `MAILGO_ADMIN_PASSWORD`: + +```bash +MAILGO_ADMIN_PASSWORD="$(openssl rand -base64 12)" ./mailgo +``` + +该变量仅在首次创建管理员账户时生效(账户已存在则忽略);无论哪种方式, +首次登录都会强制修改密码。 + --- ## 端口速查 @@ -392,6 +406,7 @@ mailgo/ │ │ ├── stores.go # Store 聚合器 │ │ ├── user_store.go # 用户数据操作 │ │ ├── mail_store.go # 邮件数据操作 +│ │ ├── mailbox_store.go # 文件夹(IMAP mailbox)数据操作 │ │ ├── domain_store.go # 域名数据操作 │ │ ├── attachment_store.go # 附件数据操作 │ │ ├── outbound_store.go # 外发队列数据操作 @@ -404,6 +419,7 @@ mailgo/ │ │ └── sign.go # DKIM 签名 │ ├── imap_server/ │ │ ├── server.go # IMAP 服务(监听器/能力/跨会话推送) +│ │ ├── service.go # MailboxService(IMAP 会话与 Web 共享) │ │ └── session.go # IMAP Session 实现(SELECT/FETCH/STORE/EXPUNGE) │ ├── pop3_server/server.go # POP3 服务 │ ├── connhub/hub.go # 协议连接注册中心(当前连接监控) @@ -524,7 +540,7 @@ sudo journalctl -u mailgo -f | IMAP | github.com/emersion/go-imap/v2 | | POP3 | 手工实现 TCP 协议 | | 密码哈希 | golang.org/x/crypto/bcrypt | -| 富文本 | Quill.js (CDN) | +| 富文本 | Quill.js(go:embed 内嵌,离线可用) | | OAuth2 | golang.org/x/oauth2 | | LDAP | github.com/go-ldap/ldap/v3 | | 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