initial commit

This commit is contained in:
2026-04-26 13:47:35 -05:00
commit 844c63dd85
27 changed files with 1241 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import { existsSync } from 'node:fs';
import { stat } from 'node:fs/promises';
import { join } from 'node:path';
import { config } from '../config.js';
import { run } from '../utils/shell.js';
import { domainFromEmail, localPartFromEmail, normalizeEmail } from '../utils/email.js';
export interface DmsAccount {
email: string;
localPart: string;
domain: string;
}
function parseAccounts(output: string): DmsAccount[] {
const accounts: DmsAccount[] = [];
for (const line of output.split('\n')) {
const match = line.match(/([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,})/i);
if (!match) continue;
const email = normalizeEmail(match[1]);
accounts.push({ email, localPart: localPartFromEmail(email), domain: domainFromEmail(email) });
}
return [...new Map(accounts.map((a) => [a.email, a])).values()].sort((a, b) => a.email.localeCompare(b.email));
}
export class DmsService {
async listAccounts(): Promise<DmsAccount[]> {
const { stdout } = await run('docker', ['exec', config.dmsContainer, 'setup', 'email', 'list']);
return parseAccounts(stdout);
}
async addMailbox(email: string, password: string): Promise<void> {
const normalized = normalizeEmail(email);
if (config.manageMailUserScript && existsSync(config.manageMailUserScript)) {
await run(config.manageMailUserScript, ['add', normalized, password]);
return;
}
await run('docker', ['exec', config.dmsContainer, 'setup', 'email', 'add', normalized, password]);
}
async deleteMailbox(email: string): Promise<void> {
const normalized = normalizeEmail(email);
if (config.manageMailUserScript && existsSync(config.manageMailUserScript)) {
await run(config.manageMailUserScript, ['del', normalized]);
return;
}
await run('docker', ['exec', config.dmsContainer, 'setup', 'email', 'del', normalized]);
}
async updatePassword(email: string, password: string): Promise<void> {
const normalized = normalizeEmail(email);
// docker-mailserver supports setup email update <email> <password> in current versions.
await run('docker', ['exec', config.dmsContainer, 'setup', 'email', 'update', normalized, password]);
}
async syncSesDomain(domain: string): Promise<void> {
if (config.manageMailUserScript && existsSync(config.manageMailUserScript)) {
await run(config.manageMailUserScript, ['sync', domain.toLowerCase()]);
}
}
async getMailboxUsageBytes(email: string): Promise<number> {
const domain = domainFromEmail(email);
const local = localPartFromEmail(email);
const candidates = [
join(config.mailDataPath, domain, local),
join(config.mailDataPath, domain, `${local}/`),
join(config.mailDataPath, domain, `${local}/Maildir`),
join(config.mailDataPath, email),
];
for (const p of candidates) {
try {
await stat(p);
const { stdout } = await run('du', ['-sb', p], 60000);
const value = parseInt(stdout.trim().split(/\s+/)[0] ?? '0', 10);
return Number.isFinite(value) ? value : 0;
} catch {
// try next path
}
}
return 0;
}
}