feat(mailbox): 支持用户自助申请邮箱

- 后端新增邮箱申请配置与接口,限制可申请域名并校验保留前缀。
- 管理后台系统设置增加自助申请邮箱开关、开放域名和禁止前缀配置。
- 个人中心新增申请邮箱入口,并在邮箱页优化当前邮箱切换与空列表处理。
- 补充相关测试与环境变量示例配置。
This commit is contained in:
LanQin
2026-06-16 00:51:41 +08:00
parent b9e43f211d
commit be8cd4be31
11 changed files with 587 additions and 153 deletions
+6
View File
@@ -22,6 +22,7 @@ export type MailRule = { id: string; mailboxId: string; name: string; matchMode:
export type BlockedSender = { id: string; mailboxId: string; email: string; reason: string; createdAt: string }
export type MailStats = { totalMessages: number; unreadMessages: number; starredMessages: number; attachmentCount: number; storageBytes: number; byFolder: { folder: string; role: string; count: number; unread: number; bytes: number }[] }
export type MailTemplate = { key: string; name: string; subject: string; bodyText: string; bodyHtml: string; updatedAt: string }
export type MailboxApplyOptions = { enabled: boolean; domains: Domain[]; reservedPrefixes?: string[] }
export type SystemSettings = {
publicHostname: string
publicBaseUrl: string
@@ -42,6 +43,9 @@ export type SystemSettings = {
catchAllEnabled: boolean
mailAutoRefresh: boolean
mailRefreshSeconds: number
userMailboxApplyEnabled: boolean
userMailboxDomainIds: string[]
reservedMailboxPrefixes: string
}
export type SystemSettingsPayload = Omit<SystemSettings, "smtpPasswordSet" | "turnstileSecretSet"> & { smtpPassword: string; turnstileSecretKey: string }
export type PublicSettings = { openRegistration: boolean; turnstileEnabled: boolean; turnstileSiteKey: string; mailAutoRefresh: boolean; mailRefreshMs: number }
@@ -99,6 +103,8 @@ export const api = {
deleteBlockedSender: (id: string) => request<{ ok: boolean }>(`/api/me/blocked-senders/${id}`, { method: "DELETE" }),
mailStats: (mailboxId?: string) => request<MailStats>(`/api/me/stats${mailboxId ? `?mailboxId=${encodeURIComponent(mailboxId)}` : ""}`),
cleanupMail: (payload: { mailboxId: string; target: "empty-trash" | "empty-spam" | "archive-read-inbox" }) => request<{ ok: boolean; affected: number }>("/api/me/cleanup", { method: "POST", body: JSON.stringify(payload) }),
mailboxApplyOptions: () => request<MailboxApplyOptions>("/api/me/mailbox-apply-options"),
applyMailbox: (payload: { domainId: string; localPart: string; displayName: string }) => request<Mailbox>("/api/me/mailboxes/apply", { method: "POST", body: JSON.stringify(payload) }),
adminOverview: () => request<AdminOverview>("/api/admin/overview"),
users: () => request<ListResponse<AdminUser>>("/api/admin/users"),
createUser: (payload: { email: string; displayName: string; role: "admin" | "user"; password: string; disabled: boolean }) => request<AdminUser>("/api/admin/users", { method: "POST", body: JSON.stringify(payload) }),