원문 캡처 · github.com
원문 캡처 · github.com

Nuvrail은 AI 에이전트와 실제 메일 서버 사이에서 IMAP/SMTP 요청을 중개한다. 메일 읽기는 통과시키고 이동·삭제·표시 변경·발송은 사용자가 승인할 때까지 보류하며, 영구 삭제 명령 EXPUNGE는 차단한다. 개발팀은 이 프로젝트를 자체 호스팅할 수 있는 오픈소스 승인 계층으로 소개했다.

작동 방식과 범위

에이전트는 Nuvrail을 일반 IMAP/SMTP 서버처럼 사용한다. Nuvrail은 읽기 요청을 즉시 전달하고 쓰기 요청은 보류 상태로 기록한 뒤 OK [STAGED]를 반환한다. 사용자는 휴대전화나 브라우저 알림에서 제목·발신자·대상 폴더 또는 수신자를 확인하고 승인하거나 거절할 수 있다. 승인하면 실제 서버에서 작업을 실행하고, 거절하면 프록시의 로컬 상태를 되돌린다. 거절 결과는 에이전트가 다음 명령을 보낼 때 전달된다. 처리되지 않은 작업은 48시간 뒤 만료되고 거절 처리된다.

승인이 필요한 작업은 메시지 이동·복사, 플래그 변경, SMTP를 통한 메일 발송, 폴더 생성·이름 변경이다. 메시지 조회·검색·폴더 목록 확인·상태 확인은 승인 없이 통과한다. EXPUNGE와 CLOSE는 실제 서버로 전달하지 않으며, \Deleted 표시는 다른 쓰기와 마찬가지로 승인 대기 상태로 둔다. 따라서 에이전트가 메시지 삭제를 요청할 수는 있지만 사용자의 승인 없이 실행할 수 없고 영구 삭제는 허용되지 않는다.

저장소 설명에 따르면 IMAP 프록시는 로컬 SQLite 미러를 사용하고, 보류 작업의 스냅샷을 보관해 거절 시 되돌린다. SMTP 프록시는 발송 데이터(DATA)를 보류한 뒤 승인될 때 전달한다. 웹 앱은 로그인, 대기 중인 작업, 감사 로그, 에이전트 관리를 제공하며 iOS·Android에서 PWA로 설치할 수 있다. 자격 증명은 저장 시 AES-256-GCM으로 암호화하고 전송에는 TLS를 사용한다고 프로젝트는 설명한다. 푸시 알림 내용은 기기에 종단 간 암호화되며 이메일 본문은 알림에 포함하지 않는다. 알림에는 작업 ID, 긴급도, 작업에 대한 짧은 설명이 들어가고, 자세한 내용은 앱을 열어 인증된 HTTPS로 불러온다. 공유 기기의 잠금 화면 미리보기가 걱정되면 운영체제 설정에서 알림 미리보기를 끌 수 있다.

로컬에서 시험하기

로컬 평가에는 Docker와 Compose 플러그인이 필요하다. 도메인·TLS·nginx 없이 localhost에서 실행할 수 있지만, 첫 빌드는 여러 분 걸린다. 저장소는 새로 내려받고 캐시가 없는 경우 첫 실행에 보통 약 5~9분이 걸리며, 이후 실행은 몇 초 안에 시작된다고 안내한다.

sh
git clone https://github.com/agens-field/nuvrail.git
cd nuvrail
cp .env.example .env
docker compose up --build

기본 가입 모드는 closed여서 웹 앱에 계정 생성 버튼이 없다. 컨테이너가 올라온 뒤 CLI에서 첫 계정을 만든다.

sh
docker compose exec gateway python3 scripts/manage_users.py create you@example.com --name "You"

그다음 http://localhost:3000에 로그인한다. API는 http://localhost:8080, IMAP·SMTP 프록시는 각각 localhost:10143, localhost:10587에서 제공된다. 빌드가 끝난 뒤 서비스가 정상 상태가 되기까지 약 10~20초가 걸릴 수 있다. 포트 3000이 사용 중이면 .env의 NUVRAIL_HOST_WEB_PORT를 다른 값으로 바꾸고, 필요하면 NUVRAIL_HOST_API_PORT, NUVRAIL_HOST_IMAP_PORT, NUVRAIL_HOST_SMTP_PORT도 변경한다. 포트 변경은 호스트 쪽에 적용되며 다시 빌드하지 않아도 된다.

원격 호스트에서 시험할 때는 .env에서 NUVRAIL_BIND_ADDR=0.0.0.0을 설정하고 docker compose up -d를 실행한 뒤 http://<host>:3000을 연다. 이 구성은 일반 HTTP로 전달자 토큰을 주고받으므로 신뢰할 수 있는 네트워크에서만 사용해야 한다. 실제 메일 계정을 연결하거나 다른 컴퓨터의 에이전트가 접속하게 하려면 TLS, nginx, 영구 보관되는 마스터 키를 포함한 프로덕션 배포 안내를 따라야 한다. NUVRAIL_MASTER_KEY를 비워 두면 첫 실행 때 키를 자동 생성하지만, 프로젝트는 이를 시험용으로만 쓰고 실제 메일에는 사용하지 말라고 안내한다.

실제 배포와 가입 설정

프로덕션 배포 안내의 전제 조건은 Ubuntu 22.04 LTS 또는 이에 준하는 Debian 계열 배포판, 서버 IP를 가리키는 DNS A 레코드, Git, Docker Engine과 Compose 플러그인, stream 모듈을 포함한 nginx, certbot이다. 외부 TLS는 nginx에서 종료하고, 컨테이너는 기본적으로 127.0.0.1에만 바인딩한다. 인터넷에 공개할 포트는 SSH 22, HTTP 80, HTTPS 443, IMAP SSL 993, SMTPS 465이며, 내부용 10143·10587·8080은 공개하지 말아야 한다.

필수 설정에는 64자리 16진수 NUVRAIL_MASTER_KEY, CORS 허용 주소, 가입 모드, VAPID 연락처 이메일이 포함된다. Gmail OAuth2 연결에는 GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, 리디렉션 URI가 필요하고, Outlook/Microsoft 365에는 MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, 리디렉션 URI와 테넌트 설정이 필요하다. 마스터 키는 데이터베이스에 저장된 모든 상위 메일 자격 증명을 암호화하므로 백업해야 한다. 키를 잃으면 저장된 에이전트 자격 증명을 복구할 수 없다.

가입 모드는 closed, invite, open 중 하나다. 기본값인 closed에서는 공개 가입을 막고 관리자가 CLI로 계정을 만든다. invite에서는 관리자가 만든 1회용 초대 코드가 있어야 가입할 수 있다. open에서는 누구나 가입할 수 있지만 NUVRAIL_ALLOW_OPEN_SIGNUP=1을 함께 설정해야 하며, 그렇지 않으면 API가 시작을 거부한다. 설정이 없거나 인식되지 않는 모드는 closed로 처리된다. 공개 가입은 해당 주소에 접속할 수 있는 누구나 계정을 만들고 메일박스를 프록시할 수 있으므로, 프로젝트는 실제 공개 서비스가 아니라면 사용하지 말고 알려진 사용자 그룹에는 초대 모드를 권한다.

가입 모드는 실행 중에도 .env를 수정한 뒤 gateway 컨테이너를 다시 만들면 바꿀 수 있다. open으로 전환하면 재시작 즉시 접근 범위가 넓어진다. open에서 다른 모드로 바꾸면 새 가입만 막히며 기존 계정은 유지된다. 초대 모드로 바꾸는 것만으로 초대 코드가 만들어지지는 않으므로, 사용자에게 가입을 안내하기 전에 코드를 발급해야 한다. 초대 코드는 1회용이며 선택적으로 일·시간·분 단위 만료 시간을 설정할 수 있다. 원문 코드는 발급 때 한 번만 보여 주고 데이터베이스에는 해시만 저장한다. 만료·철회·이미 사용한 코드나 잘못된 코드의 요청은 모두 같은 403으로 거절해 코드 존재 여부를 드러내지 않는다. 자세한 운영 절차는 가입 모드 안내와 초대 코드 운영 안내에 있다.

배포 안내는 nginx를 먼저 HTTP로 올린 뒤 certbot으로 인증서를 발급하고, 그 다음 IMAP·SMTP TLS 스트림 프록시를 추가하도록 설명한다. 인증서가 생기기 전에 nginx 설정에서 인증서 파일을 참조해 시작이 실패하는 상황을 피하기 위한 순서다. 웹/API 설정에서는 /api/와 /health 경로를 웹 앱 경로보다 먼저 처리한다. 공개 가입을 켤 경우 명시적 확인 설정을 추가하지 않으면 gateway가 시작하지 않는 등, 설정 오류는 기본적으로 닫힌 상태로 처리한다.

메일 계정과 에이전트 연결

Nuvrail은 Gmail(OAuth2), Outlook/Microsoft 365(OAuth2), iCloud(앱 전용 비밀번호), 표준 IMAP/SMTP 계정을 위한 설정 흐름을 제공한다. 다만 모든 공급자를 실제 계정으로 확인한 것은 아니다. 저장소의 상태표에 따르면 Gmail/Google Workspace는 자체 배포에서 2026년 9월 10일부터 사용 중이며, 표준 IMAP/SMTP는 자체 배포의 MXRoute 계정에서 2026년 7월부터 사용 중이고 CI에서 로컬 GreenMail IMAPS 서버로도 검사한다. Outlook/Microsoft 365와 iCloud는 실제 계정 연결이 아직 확인되지 않았다. 이 두 공급자는 설정 코드와 안내서, 일부 단위 테스트가 있지만 실제 메일박스에서 종단 간 연결을 수행하지 않았다고 명시한다. Outlook은 Gmail과 같은 XOAUTH2 경로를 사용하며, 예상되는 실패 지점은 프록시보다 Azure 앱 등록·범위·엔드포인트라고 프로젝트는 설명한다.

Gmail 연결에는 Google Cloud OAuth2 클라이언트를 만들고 관련 환경 변수를 설정한 뒤 웹 앱의 Agents에서 Connect Gmail을 선택해 동의 절차를 마친다. Outlook/Microsoft 365는 Azure AD 앱과 환경 변수를 설정하고 Connect Outlook에서 Microsoft 동의 절차를 거친다. Exchange Online은 2023년에 IMAP/SMTP 기본 인증이 폐지돼 OAuth2가 지원 경로라고 안내한다. 표준 IMAP/SMTP는 웹 앱의 Agents에서 에이전트를 추가하고 서버 주소·포트·사용자 이름·비밀번호를 입력한다. 세 방법 모두 성공 때 표시되는 에이전트 토큰은 한 번만 확인할 수 있으므로 복사해야 한다.

에이전트는 Nuvrail 호스트의 993번 IMAP SSL 포트와 465번 SMTP SSL 포트에 연결한다. 설정에는 발급받은 에이전트 사용자 이름과 토큰을 사용한다. 에이전트 자체를 수정할 필요가 없으며, 어떤 IMAP 클라이언트든 프록시를 통해 동일하게 작동한다고 프로젝트는 설명한다. 보류 작업은 PWA의 승인 화면이나 API에서 승인·거절할 수 있다. 알림을 받으려면 PWA에서 알림을 활성화해야 한다.

검증 범위와 링크

저장소의 3am 데모는 현지 테스트 메일 서버에 대해 CI에서 기록한 실행이다. 데모의 ‘에이전트’는 짧은 스크립트이며, 해당 설명은 프록시를 통과하는 모든 IMAP 클라이언트가 같은 방식으로 동작한다고 밝힌다. 이 시연에서는 새벽 3시에 38개 메일을 지우려는 요청이 사용자 승인 전에는 실제 메일함에 반영되지 않는다. EXPUNGE는 gateway에서 전달되지 않고 OK Noted를 돌려주며, 보류된 삭제는 한 번의 조작으로 거절된다. 재현 안내와 67초 MP4를 제공한다.

프로젝트는 모든 작업·승인·거절·실행을 추가 전용 감사 로그에 기록한다고 설명한다. 에이전트별 자격 증명을 분리하고, 각 에이전트는 자신에게 연결된 상위 계정만 접근할 수 있도록 설계했다. 푸시 알림은 Web Push(RFC 8291) 방식으로 구독 기기에 종단 간 암호화되며, 푸시 중계 서비스는 내용을 읽을 수 없다고 한다. 핵심 통신·보안 코드는 AGPL-3.0으로 공개돼 있다. 네트워크 서비스로 수정본을 운영하면 AGPL의 네트워크 사용 조항에 따라 수정 소스를 사용자에게 제공해야 한다고 저장소는 안내한다.

관련 자료: Nuvrail 저장소, 이메일이 AI 에이전트에 위험한 이유, 에이전트가 메일을 삭제하지 못하게 하는 안내, 발송 전 사람의 승인을 추가하는 안내, LLM 메일 에이전트의 사람 개입 안내, Claude Desktop 연동, Cursor 연동, LangChain 연동.