email-amazon/email-worker-nodejs/src/config.ts

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';
}