Skip to content

Repository files navigation

Relay Webmail

Relay는 기존 Roundcube Webmail을 대체하기 위한 Next.js 기반 Webmail 프로젝트입니다.

메일 원본은 기존 Dovecot/IMAP 서버에 그대로 두고, 메일 발송도 기존 Postfix/SMTP 서버를 사용합니다. Relay를 설치한다고 해서 Maildir이나 기존 사용자 메일을 복사·이동·삭제하지 않습니다.

현재 구현된 기능

  • 반응형 3단 메일 화면, 접을 수 있는 메일 목록과 모바일 레이아웃
  • IMAP 서버 전체 검색, 50개 단위 페이지 이동, 필터, 중요 표시, 읽음/읽지 않음
  • 답장·전체답장·전달과 In-Reply-To/References 스레드 헤더
  • HTML 메일 작성기, 굵게·기울임·목록·인용·링크 서식과 본문 이미지 붙여넣기
  • 첨부파일 드래그 앤 드롭 업로드, 스트리밍 다운로드, 첨부 포함 전달
  • IMAP 임시보관함 자동 저장과 저장된 초안 다시 편집
  • 보관, 휴지통 이동과 서버 특수 폴더 자동 탐색
  • 보관함·휴지통·스팸함에서 받은편지함 복원
  • 휴지통 단일·일괄 영구삭제와 휴지통 비우기 확인 절차
  • 메일 다중 선택, 일괄 읽음·중요·보관·삭제·복원
  • 이동 작업 실행 취소, 폴더별 상황에 맞는 작업 버튼과 아이콘 툴팁
  • 모바일 폴더 메뉴와 / 검색 단축키
  • IMAP 계정 인증과 실제 폴더/메일 목록 조회 API
  • 세션별 IMAP 연결 재사용, IMAP IDLE 실시간 갱신과 브라우저 새 메일 알림
  • 같은 제목의 관련 메일 모아보기, 최근 수신자 자동완성과 서버 메일함 용량 표시
  • 메일 본문 MIME 파싱과 정화된 HTML·인라인 이미지·HTTPS 외부 이미지 표시
  • 신뢰한 메일 서버의 SPF·DKIM·DMARC 인증 결과 표시
  • 인증 실패와 From/Reply-To 불일치 경고
  • 안전한 이미지·PDF·텍스트 첨부 미리보기, EML 원본 다운로드와 인쇄 화면
  • J/K 이동, R 답장, E 보관과 / 검색 단축키
  • 세션별 SMTP 연결 재사용, 메일 발송 후 IMAP 보낸편지함 저장
  • Redis 기반 로그인 세션과 AES-256-GCM 자격증명 암호화
  • 애플리케이션·IMAP·SMTP 상태 확인 API와 Docker Compose healthcheck

/는 로그인 세션이 없으면 /login으로 이동합니다. 로그인 후에는 실제 IMAP 폴더, 메일 목록과 본문을 불러옵니다.

준비 사항

로컬에서 실행하려면 다음이 필요합니다.

  • Node.js 20.9 이상
  • npm
  • Redis
  • 실제 연결을 시험할 IMAP/SMTP 테스트 계정
  • Docker 방식으로 실행할 경우 Docker와 Docker Compose

운영 계정을 바로 사용하지 말고 별도의 테스트 계정으로 먼저 확인하세요.

1. 환경변수 파일 만들기

Windows PowerShell:

Copy-Item .env.example .env

Linux/macOS:

cp .env.example .env

생성된 .env 파일을 열어 실제 환경에 맞게 값을 수정합니다. .env에는 비밀번호와 secret이 들어가므로 Git에 커밋하면 안 됩니다.

화면에 표시되는 서비스 이름과 문구도 배포 환경마다 바꿀 수 있습니다. 변경 후 애플리케이션을 다시 시작하면 로그인 화면, 상단바, 브라우저 제목과 공유 이미지에 함께 반영됩니다.

WEBMAIL_NAME=Example Mail
WEBMAIL_TAGLINE=Your private webmail

2. 메일 서버 정보 설정

가장 일반적인 설정은 다음과 같습니다.

IMAP_HOST=mail.example.com
IMAP_PORT=993
IMAP_SECURE=true
IMAP_POOL_IDLE_SECONDS=120

SMTP_HOST=mail.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_POOL_IDLE_SECONDS=120

# 아이디만 입력했을 때 자동으로 붙일 도메인
MAIL_DOMAIN=example.com
MAIL_AUTH_AUTHSERV_ID=mail.example.com
  • IMAP 993 포트는 일반적으로 처음부터 TLS를 사용하므로 IMAP_SECURE=true입니다.
  • IMAP_POOL_IDLE_SECONDS 동안 사용하지 않은 IMAP 연결은 자동으로 종료되며 다음 요청에서 다시 연결합니다.
  • SMTP 587 포트는 일반적으로 STARTTLS를 사용하므로 SMTP_SECURE=false입니다.
  • SMTP 465 포트를 사용한다면 일반적으로 SMTP_SECURE=true입니다.
  • SMTP_POOL_IDLE_SECONDS 동안 발송이 없으면 세션별 SMTP 연결을 자동으로 종료합니다.
  • 로그인 화면은 아이디와 전체 이메일 주소를 모두 허용합니다. MAIL_DOMAIN=example.com이면 gildong과 gildong@example.com 모두 Dovecot에는 gildong으로 인증하고, 화면 표시와 발신 주소에는 gildong@example.com을 사용합니다.
  • MAIL_AUTH_AUTHSERV_ID는 Postfix/Rspamd가 Authentication-Results에 기록하는 수신 서버 식별자입니다. 발신자 허용 목록이 아니며, 비워두면 IMAP_HOST를 사용합니다. 신뢰 ID가 같은 헤더가 여러 개면 SPF·DKIM·DMARC 결과가 가장 완전한 헤더를 화면 판정에 사용합니다.
  • 사설 인증서를 사용 중이라도 운영 환경에서 IMAP_TLS_REJECT_UNAUTHORIZED=false로 두는 것은 권장하지 않습니다. 신뢰할 수 있는 CA 인증서를 먼저 구성하세요.

Docker 컨테이너에서 호스트 서버의 메일 서비스에 연결할 때 127.0.0.1은 컨테이너 자신을 의미합니다. Windows/macOS Docker Desktop에서는 보통 host.docker.internal을 사용하고, Linux에서는 실제 호스트 IP 또는 별도 Docker 네트워크 구성이 필요합니다.

3. 세션 Secret 만들기

다음 명령으로 충분히 긴 임의 값을 생성합니다.

node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"

출력된 값을 .env의 SESSION_SECRET에 입력합니다. 이 값이 변경되면 기존 로그인 세션은 모두 무효화됩니다. 예시 파일의 안내 문구를 그대로 사용하면 안 되며, 실제 생성 결과는 최소 32자 이상이어야 합니다.

운영에서는 REDIS_URL을 반드시 설정하세요. 운영 빌드에서 이 값을 생략하면 안전하지 않은 메모리 세션으로 대체하지 않고 요청을 거부합니다. 개발 환경에서만 Redis 없이 단일 프로세스 메모리 저장소를 사용할 수 있습니다.

4-A. npm으로 운영 실행하기

Redis를 로컬에서 실행 중이라면 .env를 다음 형태로 설정합니다.

REDIS_URL=redis://127.0.0.1:6379

의존성을 설치하고 운영 빌드 후 서버를 실행합니다. npm start는 먼저 빌드가 완료되어 있어야 합니다.

npm install
npm run build
npm start

브라우저에서 다음 주소를 확인합니다.

  • Webmail 화면: http://localhost:3001
  • 실제 IMAP 로그인: http://localhost:3001/login

코드를 수정하면서 확인할 때만 개발 서버를 사용합니다.

npm run dev

4-B. Docker Compose로 실행하기(선택)

Docker Compose는 Webmail과 Redis만 실행합니다. Compose 설정이 컨테이너 내부 Redis 주소를 자동으로 적용하므로 별도의 애플리케이션 DB 설정은 필요하지 않습니다.

REDIS_URL=redis://127.0.0.1:6379

실행:

docker compose up -d --build

상태 확인:

docker compose ps
docker compose logs -f webmail

Docker 환경에서는 보안을 위해 Webmail 포트가 127.0.0.1:3001에만 열립니다. 외부 서비스는 Nginx를 통해 HTTPS로 연결하는 구성을 권장합니다. 실제 도메인·인증서·다른 서비스 경로가 포함된 nginx/는 서버 전용 설정이므로 Git에서 제외됩니다.

실시간 알림 SSE 경로에는 프록시 버퍼링과 압축을 끄고 충분한 읽기 제한 시간을 설정해야 합니다. 일반 요청보다 이 location을 먼저 선언하고, 적용 전 sudo nginx -t로 검사하세요.

location = /api/mail/events {
    proxy_pass http://127.0.0.1:3001;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
    proxy_cache off;
    gzip off;
    proxy_read_timeout 1h;
}

5. 실제 메일 연결 확인 순서

  1. /login에서 테스트 이메일 계정으로 로그인합니다.
  2. 로그인 성공 여부와 Redis 세션 생성을 확인합니다.
  3. Inbox, Sent, Drafts, Junk, Trash 폴더가 실제 서버와 맞는지 확인합니다.
  4. 메일 목록의 보낸 사람, 제목, 날짜, 읽음 상태를 비교합니다.
  5. 테스트 메일을 열어 HTML/텍스트 본문과 첨부파일 정보를 확인합니다.
  6. 내부 계정으로 테스트 메일을 발송한 뒤 Sent 폴더와 수신 결과를 확인합니다.
  7. 답장·전체답장의 스레드 연결과 전달 메일의 원본 첨부파일을 확인합니다.
  8. 작성 중 2초 뒤 Drafts 폴더에 자동 저장되고 다시 열어 편집되는지 확인합니다.
  9. 50개가 넘는 폴더에서 다음 페이지와 서버 검색 결과를 확인합니다.
  10. 외부 계정 발송, 한글 제목과 첨부파일은 별도로 검증합니다.

상태 확인과 운영 백업

  • GET /api/health: 로그인 없이 애플리케이션과 세션 저장소 준비 상태만 확인합니다.
  • GET /api/mail/health: 로그인 세션으로 IMAP NOOP와 SMTP 연결 검증을 실행하고 각각의 지연 시간을 반환합니다.
  • Docker Compose는 /api/health를 30초마다 확인합니다.
  • 운영 로그의 imap_operation_timing, smtp_send_timing, smtp_send_failed 이벤트로 작업별 대기·처리 시간을 확인할 수 있습니다.

메일 원본 백업은 이 애플리케이션이 아니라 Dovecot 저장소를 기준으로 구성해야 합니다. Maildir 또는 실제 mail_location, /etc/dovecot, /etc/postfix, /etc/rspamd, DKIM 개인 키를 권한과 함께 백업하고 별도 환경에서 정기적으로 복원 시험을 하세요. Redis에는 로그인 세션만 있으므로 Redis 백업만으로 메일은 복구되지 않습니다.

자주 발생하는 문제

로그인이 실패하는 경우

  • IMAP 호스트와 포트가 서버에서 접근 가능한지 확인합니다.
  • 아이디만 입력했다면 .env의 MAIL_DOMAIN이 실제 메일 도메인과 같은지 확인합니다.
  • 전체 이메일 주소를 입력했다면 해당 주소가 실제 IMAP 사용자명인지 확인합니다.
  • Dovecot 인증 방식이 일반 비밀번호 로그인을 허용하는지 확인합니다.
  • TLS 인증서의 호스트명이 IMAP_HOST와 일치하는지 확인합니다.

로그인은 되지만 발송이 실패하는 경우

  • SMTP 인증 계정이 IMAP 계정과 동일한지 확인합니다.
  • 587/STARTTLS와 465/SMTPS 설정을 혼동하지 않았는지 확인합니다.
  • Postfix가 현재 Webmail 서버 또는 Docker 호스트의 연결을 허용하는지 확인합니다.

Docker에서 메일 서버에 연결할 수 없는 경우

  • .env의 IMAP_HOST와 SMTP_HOST에 127.0.0.1을 사용하지 않았는지 확인합니다.
  • 호스트 방화벽과 Dovecot/Postfix listen 주소를 확인합니다.
  • 운영 서비스 설정이나 방화벽을 변경하기 전에는 반드시 영향 범위를 검토하세요.

운영 전 필수 확인

다음 항목은 서버 환경마다 달라 자동 적용하지 않으며 운영 환경에서 확인해야 합니다.

  • 실제 Roundcube 버전과 DB 스키마 확인
  • 실제 IMAP special-use 폴더 매핑
  • 주소록·identity·사용자 설정 마이그레이션
  • 25MB보다 큰 첨부파일을 위한 완전한 스트리밍 업로드 전환
  • 다중 Webmail 인스턴스 운영 시 IMAP IDLE 전용 worker와 Redis 이벤트 팬아웃
  • Dovecot/Postfix/Rspamd 설정 및 Maildir 백업·복원 시험
  • MIME fixture, IMAP/SMTP 통합, E2E, 보안 테스트 확대

About

기존 Roundcube를 대체하기 위해 새롭게 만든 Next.js 기반 웹메일 서비스

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages