본문으로 건너뛰기
피드

Remails: 유럽에서 만든 오픈소스 메일 전송 에이전트(MTA)

backend 약 5분
vote
0
댓글
북마크

네덜란드 Tweede Golf가 만든 유럽 호스팅 기반 오픈소스 MTA. 단일 VPS에서 시작해 Kubernetes 고가용성 아키텍처로 진화하면서, BYOIP와 발신자별 IP 제어를 구현한 과정을 상세히 설명함.

  • 1

    유럽 클라우드 기반 MTA로 BYOIP 지원, 발신자별 전용 IP 할당 가능

  • 2

    DaemonSet + 호스트 네트워크로 아웃바운드 IP 제어, best-effort 메시지 버스로 컴포넌트 간 통신

  • 3

    무료 플랜 월 3,000통, GitHub 소스 공개로 셀프 호스팅 가능

  • 네덜란드의 Tweede Golf가 만든 Remails는 유럽 호스팅 기반의 메일 전송 에이전트(MTA)임. 이메일을 안정적으로 전달하기 위해 평판 좋은 IP로 릴레이하고, 적절한 헤더를 세팅하고, 실패 시 자동 재전송해주는 서비스
  • GitHub에 소스코드가 공개되어 있어서 셀프 호스팅 가능하고, remails.net에서 바로 쓸 수 있는 인스턴스도 제공함. 현재는 트랜잭셔널 이메일(비밀번호 리셋, 인증 코드 등) 전용이고, 대량 마케팅 메일은 아직 미지원

MVP에서 고가용성까지

  • 처음엔 유럽 클라우드의 단일 VPS에서 Docker Compose + PostgreSQL로 단일 바이너리 띄우는 구조로 시작했음
  • 이후 매니지드 Kubernetes 클러스터 + 매니지드 Postgres로 전환. 웹 API와 SMTP MTA를 분리해서 각각 여러 레플리카를 노드에 분산 배포하는 고가용성 아키텍처로 진화함
  • 데이터 가용성은 클라우드 프로바이더의 이중 DB 노드 + PITR 백업 + 독립 위치에 일일 풀백업으로 확보. 백업 실패 시 알람이 오도록 모니터링도 걸어둠

IP 주소 관리가 핵심 과제

  • 이메일 발송에서 발신 IP의 평판이 스팸 필터 통과에 결정적인데, 클라우드 퍼블릭 IP로는 좋은 평판 쌓기가 어려움. 그래서 자체 IP 블록을 가져오는 BYOIP(Bring Your Own IP) 방식을 채택
  • 핀란드 클라우드 프로바이더 UpCloud이 BYOIP를 지원해줬고, 여기에 더해 발신자별로 어떤 IP에서 메일을 보낼지 제어하는 기능이 필요했음. 대량 고객에게 전용 IP를 할당해서 다른 고객의 평판 영향을 받지 않게 하려는 것

아키텍처 리팩토링

  • SMTP를 인바운드아웃바운드로 분리함. 인바운드는 일반 Deployment로 노드에 랜덤 분산, 아웃바운드는 DaemonSet으로 각 노드에 정확히 1개씩 실행하면서 호스트 네트워크 접근 권한을 부여
  • Cloud IP Manager라는 컴포넌트를 추가해서 클라우드 API를 통해 각 노드에 필요한 IP를 할당. 하나의 노드에 여러 IP를 붙일 수 있고, 아웃바운드 Pod이 직접 네트워크 인터페이스에 접근해서 발신 IP를 선택
sequenceDiagram
    participant 웹API as 웹 API
    participant 메시지버스 as 메시지 버스
    participant 아웃바운드 as SMTP 아웃바운드 (DaemonSet)
    participant DB as PostgreSQL

    웹API->>DB: 이메일 저장
    웹API->>메시지버스: 발송 알림 (메시지ID + 발신IP)
    메시지버스->>아웃바운드: 브로드캐스트
    아웃바운드->>아웃바운드: 해당 IP 보유 여부 필터링
    아웃바운드->>DB: 발송 상태 업데이트
  • 컴포넌트 간 통신은 경량 브로드캐스트 메시지 버스를 도입. 재미있는 건 이 버스가 전달 보장(deliverability guarantee)이 없는 best-effort 방식이라는 거임
  • 그런데도 고가용성이 유지되는 이유가 기발함 — 모든 액션은 DB에 먼저 저장되고, 메시지 버스 알림이 실패하면 주기적 태스크(Periodic Tasks)가 미발송 메일을 찾아서 재시도함. 버스가 죽어도 약간의 지연만 생길 뿐 메일은 결국 나감

💡

> 현재 퍼블릭 베타 중이고, 무료 플랜으로 월 3,000통까지 발송 가능. 미국 프로바이더 대신 유럽 대안을 찾는다면 한번 써볼 만함.

  • 로드맵에는 DNS 레코드 이상 알림, 쿼타 경고, 감사 로그, 이메일 수신 기능(바운스 메시지/DMARC 리포트용) 등이 예정되어 있음

이메일 인프라를 직접 구축하면서 마주치는 IP 평판 관리와 고가용성 문제를 Kubernetes로 풀어낸 실전 아키텍처 사례. 메시지 버스의 best-effort 설계가 특히 인상적.

댓글

댓글

댓글을 불러오는 중...

backend

클릭하우스가 PgBouncer 처리량을 4배로 끌어올린 방법

ClickHouse Managed Postgres 팀은 단일 스레드인 PgBouncer를 여러 프로세스로 띄우고 `so_reuseport`와 피어링(peering)을 조합해 16 vCPU 머신을 제대로 쓰게 만들었다. 동일한 AWS 환경에서 단일 프로세스는 약 8.7만 TPS 근처에서 막혔지만, 16개 프로세스 구성은 약 33.6만 TPS까지 올라갔다.

backend

SQLite 쓸 거면 STRICT 테이블을 기본값으로 보자는 주장

SQLite의 STRICT 테이블은 INTEGER 컬럼에 문자열이 들어가는 식의 타입 실수를 막아주는 기능이다. 글쓴이는 SQLite 특유의 유연한 타입 시스템보다, 실수는 빨리 터뜨리는 쪽이 실무에서 낫다고 주장한다. 다만 기존 테이블을 바로 STRICT로 바꾸기 어렵고, SQLite 3.37.0 이상에서만 쓸 수 있다는 제약도 있다.

backend

왜 아직도 Lisp를 배워볼 만한가

Lisp는 괄호가 많은 이상한 언어처럼 보이지만, 핵심은 문법이 아니라 언어 자체를 확장할 수 있다는 점에 있음. 매크로, 코드-데이터 동일성, REPL 중심 개발이 합쳐지면 프로그램을 '작성'한다기보다 살아 있는 시스템을 계속 진화시키는 방식으로 개발하게 됨.

backend

EDB 포스트그레스 AI, 포레스터 멀티모델 데이터 플랫폼 리더 선정

EDB의 AI 데이터 플랫폼 EDB 포스트그레스 AI가 2026년 2분기 포레스터 웨이브 멀티모델 데이터 플랫폼 보고서에서 리더로 선정됐음. 트랜잭션, 분석, AI 워크로드를 하나의 플랫폼에서 다루는 흐름이 강해지는 가운데, EDB는 전략과 현재 제공 기능 모두에서 높은 평가를 받았다고 밝힘.

backend

Bun, Zig에서 Rust로 갈아탔다: 11일짜리 초대형 런타임 포팅 실험

Bun 팀이 53만 줄이 넘는 Zig 코드베이스를 Rust로 기계적으로 포팅했고, Bun v1.4.0부터 Rust 기반으로 전환될 예정임. 핵심 이유는 성능보다 안정성이었고, use-after-free, double-free, 메모리 누수 같은 문제를 컴파일러와 타입 시스템으로 더 빨리 잡기 위해서였음. Claude Code 워크플로 64개를 병렬로 돌려 11일 만에 전 플랫폼 테스트 통과까지 밀어붙인 사례라, LLM 기반 대규모 코드 마이그레이션의 꽤 강한 신호탄임.