116 lines
3.9 KiB
TypeScript
116 lines
3.9 KiB
TypeScript
/**
|
|
* Configuration management for unified email worker
|
|
*
|
|
* All settings are read from environment variables with sensible defaults.
|
|
* Domain helpers (bucket name, queue name, internal check) are co-located here
|
|
* so every module can import { config, domainToBucket, ... } from './config'.
|
|
*/
|
|
|
|
import { readFileSync, existsSync } from 'node:fs';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Config object
|
|
// ---------------------------------------------------------------------------
|
|
export const config = {
|
|
// AWS
|
|
awsRegion: process.env.AWS_REGION ?? 'us-east-2',
|
|
|
|
// Domains
|
|
domainsList: process.env.DOMAINS ?? '',
|
|
domainsFile: process.env.DOMAINS_FILE ?? '/etc/email-worker/domains.txt',
|
|
|
|
// Worker
|
|
workerThreads: parseInt(process.env.WORKER_THREADS ?? '10', 10),
|
|
pollInterval: parseInt(process.env.POLL_INTERVAL ?? '20', 10),
|
|
maxMessages: parseInt(process.env.MAX_MESSAGES ?? '10', 10),
|
|
visibilityTimeout: parseInt(process.env.VISIBILITY_TIMEOUT ?? '300', 10),
|
|
|
|
// SMTP delivery (local DMS)
|
|
smtpHost: process.env.SMTP_HOST ?? 'localhost',
|
|
smtpPort: parseInt(process.env.SMTP_PORT ?? '25', 10),
|
|
smtpUseTls: (process.env.SMTP_USE_TLS ?? 'false').toLowerCase() === 'true',
|
|
smtpUser: process.env.SMTP_USER ?? '',
|
|
smtpPass: process.env.SMTP_PASS ?? '',
|
|
smtpPoolSize: parseInt(process.env.SMTP_POOL_SIZE ?? '5', 10),
|
|
|
|
// Internal SMTP port (for OOO / forwards to managed domains)
|
|
internalSmtpPort: parseInt(process.env.INTERNAL_SMTP_PORT ?? '25', 10),
|
|
|
|
// DynamoDB tables
|
|
rulesTable: process.env.DYNAMODB_RULES_TABLE ?? 'email-rules',
|
|
messagesTable: process.env.DYNAMODB_MESSAGES_TABLE ?? 'ses-outbound-messages',
|
|
blockedTable: process.env.DYNAMODB_BLOCKED_TABLE ?? 'email-blocked-senders',
|
|
|
|
// Bounce handling
|
|
bounceLookupRetries: parseInt(process.env.BOUNCE_LOOKUP_RETRIES ?? '3', 10),
|
|
bounceLookupDelay: parseFloat(process.env.BOUNCE_LOOKUP_DELAY ?? '1.0'),
|
|
|
|
// Monitoring
|
|
metricsPort: parseInt(process.env.METRICS_PORT ?? '8000', 10),
|
|
healthPort: parseInt(process.env.HEALTH_PORT ?? '8080', 10),
|
|
} as const;
|
|
|
|
export type Config = typeof config;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Managed domains (populated by loadDomains())
|
|
// ---------------------------------------------------------------------------
|
|
const managedDomains = new Set<string>();
|
|
|
|
/**
|
|
* Load domains from env var and/or file, populate the internal set.
|
|
*/
|
|
export function loadDomains(): string[] {
|
|
const domains: string[] = [];
|
|
|
|
// From env
|
|
if (config.domainsList) {
|
|
for (const d of config.domainsList.split(',')) {
|
|
const trimmed = d.trim();
|
|
if (trimmed) domains.push(trimmed);
|
|
}
|
|
}
|
|
|
|
// From file
|
|
if (existsSync(config.domainsFile)) {
|
|
const content = readFileSync(config.domainsFile, 'utf-8');
|
|
for (const line of content.split('\n')) {
|
|
const trimmed = line.trim();
|
|
if (trimmed && !trimmed.startsWith('#')) {
|
|
domains.push(trimmed);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Deduplicate
|
|
const unique = [...new Set(domains)];
|
|
|
|
managedDomains.clear();
|
|
for (const d of unique) {
|
|
managedDomains.add(d.toLowerCase());
|
|
}
|
|
|
|
return unique;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Domain helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/** Check whether an email address belongs to one of our managed domains */
|
|
export function isInternalAddress(email: string): boolean {
|
|
const atIdx = email.indexOf('@');
|
|
if (atIdx < 0) return false;
|
|
return managedDomains.has(email.slice(atIdx + 1).toLowerCase());
|
|
}
|
|
|
|
/** Convert domain to SQS queue name: bizmatch.net → bizmatch-net-queue */
|
|
export function domainToQueueName(domain: string): string {
|
|
return domain.replace(/\./g, '-') + '-queue';
|
|
}
|
|
|
|
/** Convert domain to S3 bucket name: bizmatch.net → bizmatch-net-emails */
|
|
export function domainToBucketName(domain: string): string {
|
|
return domain.replace(/\./g, '-') + '-emails';
|
|
}
|