101 lines
3.5 KiB
Python
101 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Configuration management for unified email worker
|
|
"""
|
|
|
|
import os
|
|
from dataclasses import dataclass
|
|
from typing import Set
|
|
|
|
|
|
@dataclass
|
|
class Config:
|
|
"""Worker Configuration"""
|
|
# AWS
|
|
aws_region: str = os.environ.get('AWS_REGION', 'us-east-2')
|
|
|
|
# Domains to process
|
|
domains_list: str = os.environ.get('DOMAINS', '')
|
|
domains_file: str = os.environ.get('DOMAINS_FILE', '/etc/email-worker/domains.txt')
|
|
|
|
# Worker Settings
|
|
worker_threads: int = int(os.environ.get('WORKER_THREADS', '10'))
|
|
poll_interval: int = int(os.environ.get('POLL_INTERVAL', '20'))
|
|
max_messages: int = int(os.environ.get('MAX_MESSAGES', '10'))
|
|
visibility_timeout: int = int(os.environ.get('VISIBILITY_TIMEOUT', '300'))
|
|
|
|
# SMTP for delivery
|
|
smtp_host: str = os.environ.get('SMTP_HOST', 'localhost')
|
|
smtp_port: int = int(os.environ.get('SMTP_PORT', '25'))
|
|
smtp_use_tls: bool = os.environ.get('SMTP_USE_TLS', 'false').lower() == 'true'
|
|
smtp_user: str = os.environ.get('SMTP_USER', '')
|
|
smtp_pass: str = os.environ.get('SMTP_PASS', '')
|
|
smtp_pool_size: int = int(os.environ.get('SMTP_POOL_SIZE', '5'))
|
|
|
|
# Internal SMTP (bypasses transport_maps)
|
|
internal_smtp_port: int = int(os.environ.get('INTERNAL_SMTP_PORT', '2525'))
|
|
|
|
# LMTP for local delivery (bypasses Postfix transport_maps)
|
|
lmtp_enabled: bool = os.environ.get('LMTP_ENABLED', 'false').lower() == 'true'
|
|
lmtp_host: str = os.environ.get('LMTP_HOST', 'localhost')
|
|
lmtp_port: int = int(os.environ.get('LMTP_PORT', '24'))
|
|
|
|
# DynamoDB Tables
|
|
rules_table: str = os.environ.get('DYNAMODB_RULES_TABLE', 'email-rules')
|
|
messages_table: str = os.environ.get('DYNAMODB_MESSAGES_TABLE', 'ses-outbound-messages')
|
|
blocked_table: str = os.environ.get('DYNAMODB_BLOCKED_TABLE', 'email-blocked-senders')
|
|
|
|
# Bounce Handling
|
|
bounce_lookup_retries: int = int(os.environ.get('BOUNCE_LOOKUP_RETRIES', '3'))
|
|
bounce_lookup_delay: float = float(os.environ.get('BOUNCE_LOOKUP_DELAY', '1.0'))
|
|
|
|
# Monitoring
|
|
metrics_port: int = int(os.environ.get('METRICS_PORT', '8000'))
|
|
health_port: int = int(os.environ.get('HEALTH_PORT', '8080'))
|
|
|
|
|
|
# Global configuration instance
|
|
config = Config()
|
|
|
|
# Global set of managed domains (populated at startup)
|
|
MANAGED_DOMAINS: Set[str] = set()
|
|
|
|
|
|
def load_domains() -> list[str]:
|
|
"""Load domains from config and populate MANAGED_DOMAINS global"""
|
|
global MANAGED_DOMAINS
|
|
domains = []
|
|
|
|
if config.domains_list:
|
|
domains.extend([d.strip() for d in config.domains_list.split(',') if d.strip()])
|
|
|
|
if os.path.exists(config.domains_file):
|
|
with open(config.domains_file, 'r') as f:
|
|
for line in f:
|
|
domain = line.strip()
|
|
if domain and not domain.startswith('#'):
|
|
domains.append(domain)
|
|
|
|
domains = list(set(domains))
|
|
MANAGED_DOMAINS = set(d.lower() for d in domains)
|
|
|
|
return domains
|
|
|
|
|
|
def is_internal_address(email_address: str) -> bool:
|
|
"""Check if email address belongs to one of our managed domains"""
|
|
if '@' not in email_address:
|
|
return False
|
|
domain = email_address.split('@')[1].lower()
|
|
return domain in MANAGED_DOMAINS
|
|
|
|
|
|
def domain_to_queue_name(domain: str) -> str:
|
|
"""Convert domain to SQS queue name"""
|
|
return domain.replace('.', '-') + '-queue'
|
|
|
|
|
|
def domain_to_bucket_name(domain: str) -> str:
|
|
"""Convert domain to S3 bucket name"""
|
|
return domain.replace('.', '-') + '-emails'
|