qmail은 다니엘 J. 번스타인(DJB)이 기존 sendmail 의 모놀리식(Monolithic) 구조와 잦은 보안 취약점을 극복하기 위해 설계한 고성능·보안 중심의 메일 전송 에이전트(MTA)입니다. qmail 아키텍처의 핵심은 모듈화(Privilege Separation) , 원자적(Atomic) I/O 처리 , 무잠금(Lock-free) 설계 로 요약됩니다. 1. 설계 철학과 보안 모델 (Privilege Separation) qmail은 하나의 거대한 바이너리가 루트(root) 권한으로 동작하는 것을 배제하고, 단일 기능만 수행하는 작고 독립적인 프로세스들로 쪼개어 상호작용하도록 설계되었습니다. 사용자/그룹 분리 및 최소 권한 원칙 각 프로세스는 자신에게 필요한 최소한의 시스템 계정(UID/GID)으로만 구동되며, 프로세스 간 통신은 주로 파일시스템의 큐(Queue)와 파이프(Pipe)를 통해 이루어집니다. 계정/그룹 주 실행 프로세스 담당 역할 및 보안 경계 qmaild qmail-smtpd 신뢰할 수 없는 외부 네트워크 트래픽(SMTP 수신)을 처리하는 저권한 계정 qmailq qmail-queue , qmail-clean 메일 큐 디렉터리 접근 및 수납/삭제 권한 qmails qmail-send 큐 상태를 감시하고 배달 작업을 스케줄링하는 오케스트레이터 qmailr qmail-rspawn , qmail-remote 외부 원격 서버로 메일을 발송하는 네트워크 클라이언트 qmaill qmail-lspawn 로컬 계정 파일/Maildir에 쓰기 위해 임의의 UID로 전환(setuid) 가능한 프로세스 alias qmail-local root 및 시스템 기본 메일 수신 처리 2. 핵심 프로세스 컴포넌트 [ 외부 네트워크 ] [ 로컬 CLI ] │ │ ▼ ▼ qmail-smtpd qmail-inject │ │ └──────────┬───────────────┘ ▼ qmail-queue (Setuid qmailq) │ ▼ /var/qmail/queue ▲ │ (큐 감시) qmail-send ┌─────┴─────┐ ▼ ▼ qmail-lspawn qmail-rspawn │ │ ▼ ▼ qmail-local qmail-remote │ │ ▼ ▼ [ 로컬 Maildir ] [ 원격 SMTP ] 1) 진입 계층 (Entry Points) qmail-smtpd : 외부 SMTP 연결을 받아 RFC 규격 검증 후 메일 본문을 읽음. ( inetd 나 tcpserver 에 의해 실행) qmail-inject : 터미널 명령어나 로컬 애플리케이션( sendmail 래퍼)이 보낸 메일 헤더를 파싱하고 보정하여 전달. 2) 큐 수납 계층 (Enqueuing) qmail-queue : 진입 계층으로부터 파이프로 메일 본문과 엔벨로프(Envelope) 수신자 목록을 받아 /var/qmail/queue 에 원자적으로 기록. Setuid qmailq 로 동작하여 일반 사용자가 큐 디렉터리를 직접 조작하지 못하도록 통제. 3) 디스패칭 및 배달 계층 (Dispatching & Delivery) qmail-send : qmail의 중추 엔진. 큐를 감시하며 로컬 배달은 qmail-lspawn 에, 원격 배달은 qmail-rspawn 에 작업을 분배. qmail-lspawn / qmail-local : qmail-lspawn 은 root 권한으로 대기하다가 대상 로컬 사용자의 UID/GID로 전환하여 qmail-local 을 실행. qmail-local 은 사용자의 ~/.qmail 설정, Forwarding, Maildir 저장을 수행. qmail-rspawn / qmail-remote : qmail-rspawn 은 저권한( qmailr )으로 동시 발송 한도( concurrencyremote ) 내에서 qmail-remote 를 포크. qmail-remote 는 DNS MX 레코드를 조회하여 원격 호스트로 SMTP 통신을 수행. 4) 정리 계층 (Housekeeping) qmail-clean : qmail-send 의 지시에 따라 배달이 완료되었거나 바운스 처리된 큐 파일들을 안전하게 삭제. 3. 큐(Queue) 아키텍처 및 원자성 메커니즘 qmail은 시스템 크래시나 비정상 종료 시에도 메시지가 유실되거나 큐가 깨지지 않도록 파일시스템의 Inode 번호 와 원자적 이름 변경( rename() )을 활용합니다. 큐 디렉터리 구조 ( /var/qmail/queue/ ) pid/ : qmail-queue 가 현재 작성 중인 임시 파일 (이름: PID.시간.호스트 ). mess/ : 메일의 실제 메시지 본문 저장. intd/ : 엔벨로프(송신자/수신자) 정보가 완전히 기록되기 전 단계의 임시 디렉터리. todo/ : 본문과 엔벨로프가 모두 기록되어 qmail-send 가 읽어갈 준비가 완료된 상태. info/ , local/ , remote/ : qmail-send 가 배달 진행 상황, 남은 수신자, 재시도 시간 등을 기록하는 파일들. bounce/ : 배달 실패 시 바운스 메일 본문 생성용. [메시지 저장 흐름] 1. pid/ 에 본문 기록 2. mess/ 로 link (Inode 번호 확정, 예: Inode 12345) 3. pid/ 에 엔벨로프 기록 4. intd/12345 로 link 5. intd/12345 를 todo/12345 로 rename() <-- 이 시점에 원자적으로 커밋됨 디렉터리 샤딩 (conf-split): 파일시스템의 단일 디렉터리 내 파일 수 한계로 인한 I/O 병목을 막기 위해 mess/0/ , mess/1/ ... mess/22/ 형태로 Inode 번호에 해시 모듈러( Inode % conf-split )를 적용해 분산 저장합니다. 4. Maildir 스토리지 구조 qmail 이전의 표준이었던 mbox 포맷은 단일 파일에 여러 메일을 이어 붙이는 방식이라 동시 접근 시 파일 락(File Locking) 결함으로 인한 데이터 오염이 빈번했습니다. DJB는 이를 대체하기 위해 Maildir 을 개발했습니다. Maildir은 3개의 서브 디렉터리로 구성됩니다. Maildir/ ├── tmp/ # 현재 기록 중인 임시 파일 ├── new/ # 기록이 완료되어 아직 MUA(클라이언트)가 읽지 않은 새 메일 └── cur/ # 클라이언트가 확인했거나 플래그가 변경된 메일 쓰기: 프로세스가 고유한 파일명( 시간.PID.호스트 )을 생성해 tmp/ 에 메일을 씁니다. 커밋: 쓰기가 성공적으로 끝나면 해당 파일을 new/ 디렉터리로 link() 또는 rename() 합니다. 효과: 파일 락( flock , fcntl )을 일절 사용하지 않으므로 NFS 같은 네트워크 파일시스템에서도 데드락이나 충돌 없이 완벽한 동시성(Concurrency)과 무결성을 보장합니다. 5. qmail 아키텍처의 기술적 의의 및 한계 주요 장점 극도의 보안성: 각 프로세스가 격리되어 있어 qmail-smtpd 에 원격 취약점이 발생해도 공격자는 저권한( qmaild ) 샌드박스에 갇히게 됩니다. 안정적인 큐잉: 비동기 I/O와 Inode 기반 큐 처리로 정전이나 커널 패닉 발생 시에도 큐 데이터 손상이 원천 차단됩니다. 낮은 메모리 점유 및 높은 처리량: 불필요한 라이브러리 의존성을 제거하고 최적화된 C 코드로 작성되어 매우 적은 리소스로 대량의 메일을 신속하게 처리합니다. 현대적 관점에서의 한계 모놀리식 패치 의존성: 정적이고 보수적인 설계로 인해 TLS/SSL, ESMTP 인증(AUTH), IPv6, DKIM/SPF와 같은 현대 인터넷 표준이 기본 코드에 포함되어 있지 않아 서드파티 패치(netqmail, notqmail 등) 적용이 필수적입니다. 중앙 집중형 설정의 부재: 대부분의 설정이 /var/qmail/control/ 디렉터리 내의 개별 텍스트 파일(예: me , rcpthosts , locals , concurrencyremote )로 분산 관리됩니다.