feat: rebuild email platform and operations console

This commit is contained in:
2026-07-25 23:06:15 +08:00
parent c109abc6f5
commit 32e0969ca1
443 changed files with 56446 additions and 1585 deletions
+203
View File
@@ -0,0 +1,203 @@
use serde::Deserialize;
/// SMTP 收信服务配置(临时邮箱核心)
#[derive(Debug, Deserialize, Clone)]
pub struct SmtpConfig {
/// 是否启用 SMTP 收信(监听 25 端口)
#[serde(default = "default_enabled")]
pub enabled: bool,
/// 监听地址
#[serde(default = "default_listen_host")]
pub listen_host: String,
/// 监听端口(默认 25
#[serde(default = "default_listen_port")]
pub listen_port: u16,
/// 本机主机名(SMTP 问候时使用,如 mail.shenjianl.cn
#[serde(default = "default_hostname")]
pub hostname: String,
/// 允许的收件域名白名单(只收这些域名的邮件)
#[serde(default = "default_local_domains")]
pub local_domains: Vec<String>,
/// 单封邮件最大字节数
#[serde(default = "default_max_message_bytes")]
pub max_message_bytes: usize,
/// 单连接超时秒数
#[serde(default = "default_connection_timeout_seconds")]
pub connection_timeout_seconds: u64,
/// 单封邮件最大收件人数
#[serde(default = "default_max_recipients")]
pub max_recipients_per_message: u32,
// ===== 限流(IP 连接 + 发件域 + 收件地址) =====
/// 单 IP 每分钟最大连接数
#[serde(default = "default_ip_connect_per_min")]
pub ip_connect_per_min: u32,
/// 单发件域每分钟最大邮件数
#[serde(default = "default_domain_per_min")]
pub domain_per_min: u32,
/// 单收件地址每分钟最大邮件数
#[serde(default = "default_rcpt_per_min")]
pub rcpt_per_min: u32,
/// 单发件人每分钟最大邮件数
#[serde(default = "default_sender_per_min")]
pub sender_per_min: u32,
/// 单(发件域→收件地址)每 10 分钟最大邮件数
#[serde(default = "default_pair_per_10min")]
pub pair_per_10min: u32,
// ===== PTR 反查 =====
/// 是否要求来源 IP 有有效 PTR 记录
#[serde(default = "default_require_ptr")]
pub require_ptr: bool,
// ===== 灰名单 =====
#[serde(default = "default_greylist_enabled")]
pub greylist_enabled: bool,
#[serde(default = "default_greylist_retry_delay_seconds")]
pub greylist_retry_delay_seconds: i64,
#[serde(default = "default_greylist_entry_ttl_seconds")]
pub greylist_entry_ttl_seconds: i64,
// ===== 滥用评分 =====
/// 达到此分数的邮件进入隔离区
#[serde(default = "default_quarantine_threshold")]
pub quarantine_threshold: i32,
#[serde(default = "default_score_weight_subject_code")]
pub score_weight_subject_code: i32,
#[serde(default = "default_score_weight_spf_fail")]
pub score_weight_spf_fail: i32,
#[serde(default = "default_score_weight_ptr_missing")]
pub score_weight_ptr_missing: i32,
#[serde(default = "default_score_weight_bad_attachment")]
pub score_weight_bad_attachment: i32,
// ===== 保留期与配额 =====
/// 邮件保留天数(超过自动清理)
#[serde(default = "default_email_ttl_days")]
pub email_ttl_days: i64,
/// 新建临时邮箱默认有效期(小时)
#[serde(default = "default_mailbox_ttl_hours")]
pub mailbox_ttl_hours: i64,
/// 单邮箱最大容量(字节)
#[serde(default = "default_mailbox_max_quota_bytes")]
pub mailbox_max_quota_bytes: i64,
/// 随机生成的邮箱本地部分长度
#[serde(default = "default_address_local_part_len")]
pub address_local_part_len: usize,
/// 邮件正文加密密钥(必须恰好 32 字符;留空则不加密)
#[serde(default)]
pub body_encryption_key: String,
}
fn default_enabled() -> bool {
true
}
fn default_listen_host() -> String {
"0.0.0.0".to_string()
}
fn default_listen_port() -> u16 {
25
}
fn default_hostname() -> String {
"mail.shenjianl.cn".to_string()
}
fn default_local_domains() -> Vec<String> {
vec!["mail.shenjianl.cn".to_string(), "shenjianl.cn".to_string()]
}
fn default_max_message_bytes() -> usize {
1024 * 1024
}
fn default_connection_timeout_seconds() -> u64 {
30
}
fn default_max_recipients() -> u32 {
1
}
fn default_ip_connect_per_min() -> u32 {
20
}
fn default_domain_per_min() -> u32 {
10
}
fn default_rcpt_per_min() -> u32 {
10
}
fn default_sender_per_min() -> u32 {
10
}
fn default_pair_per_10min() -> u32 {
5
}
fn default_require_ptr() -> bool {
true
}
fn default_greylist_enabled() -> bool {
true
}
fn default_greylist_retry_delay_seconds() -> i64 {
300
}
fn default_greylist_entry_ttl_seconds() -> i64 {
86400
}
fn default_quarantine_threshold() -> i32 {
60
}
fn default_score_weight_subject_code() -> i32 {
30
}
fn default_score_weight_spf_fail() -> i32 {
20
}
fn default_score_weight_ptr_missing() -> i32 {
15
}
fn default_score_weight_bad_attachment() -> i32 {
25
}
fn default_email_ttl_days() -> i64 {
7
}
fn default_mailbox_ttl_hours() -> i64 {
24
}
fn default_mailbox_max_quota_bytes() -> i64 {
10 * 1024 * 1024
}
fn default_address_local_part_len() -> usize {
10
}
impl Default for SmtpConfig {
fn default() -> Self {
Self {
enabled: default_enabled(),
listen_host: default_listen_host(),
listen_port: default_listen_port(),
hostname: default_hostname(),
local_domains: default_local_domains(),
max_message_bytes: default_max_message_bytes(),
connection_timeout_seconds: default_connection_timeout_seconds(),
max_recipients_per_message: default_max_recipients(),
ip_connect_per_min: default_ip_connect_per_min(),
domain_per_min: default_domain_per_min(),
rcpt_per_min: default_rcpt_per_min(),
sender_per_min: default_sender_per_min(),
pair_per_10min: default_pair_per_10min(),
require_ptr: default_require_ptr(),
greylist_enabled: default_greylist_enabled(),
greylist_retry_delay_seconds: default_greylist_retry_delay_seconds(),
greylist_entry_ttl_seconds: default_greylist_entry_ttl_seconds(),
quarantine_threshold: default_quarantine_threshold(),
score_weight_subject_code: default_score_weight_subject_code(),
score_weight_spf_fail: default_score_weight_spf_fail(),
score_weight_ptr_missing: default_score_weight_ptr_missing(),
score_weight_bad_attachment: default_score_weight_bad_attachment(),
email_ttl_days: default_email_ttl_days(),
mailbox_ttl_hours: default_mailbox_ttl_hours(),
mailbox_max_quota_bytes: default_mailbox_max_quota_bytes(),
address_local_part_len: default_address_local_part_len(),
body_encryption_key: String::new(),
}
}
}