Nylas를 사용하여 이메일에서 OTP 및 2FA 코드 추출하기
요약
Nylas CLI와 Email API를 사용하여 이메일 내 OTP 및 2FA 코드를 추출하는 두 가지 방법을 설명합니다. 개발자를 위한 CLI 방식과 제품 구축을 위한 API 패턴의 차이점 및 활용법을 다룹니다.
핵심 포인트
- Nylas CLI를 통한 빠른 OTP 코드 추출 및 클립보드 복사 기능
- 스크립트 자동화를 위한 --raw 및 --json 플래그 활용법
- nylas otp watch 명령어를 이용한 실시간 코드 감시 및 폴링 해결
- CLI(풀 기반)와 API(푸시 기반) 패턴의 용도별 차이점
이 포스트는 두 가지 관점에서 인증 코드 추출을 다룹니다. 하나는 단 한 번의 명령으로 이를 수행해 주는 nylas CLI이고, 다른 하나는 더 큰 흐름의 일부일 때 구축하게 되는 Email API 패턴입니다. 저는 CLI를 담당하고 있으므로, 아래의 터미널 명령어들은 제가 단순히 코드가 필요할 때 사용하는 것들입니다.
코드를 가져오는 두 가지 방법
무엇을 구축하느냐에 따라 두 가지 경로가 있습니다. 터미널 워크플로(workflow), 로컬 테스트, 또는 로그인 스크립팅을 위한 경우, CLI에는 편지함에서 최신 코드를 찾아 전달해 주는 전용 nylas otp 명령어가 있습니다. 애플리케이션이나 수신 메일에 반응하는 에이전트(agent)의 경우, 추출 과정을 자체 흐름에 구축해야 합니다. 즉, 메시지가 도착했을 때 이를 포착하고, 본문을 가져와서 코드를 파싱(parsing)하는 방식입니다.
차이점은 누가 주도하느냐에 있습니다. CLI는 풀 기반(pull-based)입니다. 즉, 필요할 때 최신 코드를 요청합니다. API 패턴은 푸시 기반(push-based)입니다. 웹훅(webhook)이 메시지 도착을 알려주면, 작성한 코드가 이를 처리하는 과정의 일부로 값을 추출합니다. 두 방식 모두 결과적으로는 대기 중인 곳에 입력할 숫자 문자열을 얻는다는 점에서는 동일하지만, CLI는 개발자를 위한 빠른 경로이며 API 패턴은 제품을 위한 지속 가능한 경로입니다. 실제로 두 가지를 모두 사용하게 됩니다. 개발 중에는 CLI를 사용하여 어떤 발신자와 코드 형식을 다루고 있는지 파악하고, 그 이해를 바탕으로 프로덕션(production) 환경의 애플리케이션 패턴에 반영합니다.
CLI에서 최신 코드 가져오기
방금 코드를 요청했고 즉시 코드가 필요한 경우, nylas otp get을 사용하면 기본 계정에서 가장 최근의 코드를 찾아 반환합니다. 기본적으로 코드를 클립보드(clipboard)에도 복사하므로, 대화형 사용 시 코드를 전송하도록 트리거한 뒤 명령어를 실행하고 양식에 바로 붙여넣을 수 있습니다. 특정 연결된 계정을 대상으로 하려면 이메일 주소를 전달하세요.
# 기본 계정에서 최신 코드 가져오기
nylas otp get
...
--raw 플래그는 주변 텍스트 없이 코드만 출력하며, 이는 스크립트에서 코드를 캡처할 때 유용합니다. CODE=$(nylas otp get --raw --no-copy)를 사용하면 변수에 순수 값만 담을 수 있습니다. --no-copy 플래그는 클립보드 복사를 건너뛰는데, 이는 클립보드에 쓸 수 없는 자동화 환경이나 부수 효과를 원치 않는 경우에 중요합니다. 대신 읽기 쉽고 스크립트 작성이 가능한 객체를 원한다면 --json을 통해 구조화된 결과를 반환받을 수 있습니다.
코드가 도착하는 것을 감시하기
종종 코드를 먼저 요청한 뒤 잠시 후에 도착하기 때문에, 단 한 번의 폴링 (Polling)은 시점 차이로 인해 실패할 수 있습니다. nylas otp watch는 편지함을 감시하다가 코드가 나타나는 즉시 이를 노출하며, 코드가 도착할 때까지 일정 간격으로 확인하여 이 문제를 해결합니다. 이는 "양식을 제출한 후 이메일을 기다리는" 일반적인 시퀀스에 적합한 명령입니다.
# 5초마다 확인하며 새로운 코드 감시
nylas otp watch user@example.com --interval 5
--interval 플래그는 확인 빈도를 설정하며 기본값은 10초입니다. 이를 5초로 단축하면 제공업체에 과도한 부하를 주지 않으면서도 데모 시 대기 시간이 즉각적인 것처럼 느껴지게 할 수 있습니다. get과 마찬가지로 --no-copy를 전달하지 않으면 코드를 클립보드에 복사합니다. watch 패턴은 수동 로그인 흐름을 매끄럽게 만들어 줍니다. 요청을 시작하고 터미널로 전환하면, 확인하는 순간 코드가 이미 준비되어 있을 것입니다.
애플리케이션에 추출 기능 구축하기
전체 흐름은 세 단계로 이루어집니다. 첫째, 모든 수신 메시지에 대해 웹훅 (Webhook)이 실행되므로, 일반적으로 발신자나 트리거 액션 대비 최신 도착 시간을 기준으로 실제 코드가 포함된 메시지만 필터링합니다. 둘째, GET /v3/grants/{grant_id}/messages/{message_id}를 사용하여 해당 메시지의 본문을 가져옵니다. 셋째, 숫자(Digits)를 추출합니다. 이 방식으로 구축하면 별도의 폴링 루프 (Polling loop)를 만들 필요 없이, 이메일이 도착하는 즉시 코드가 워크플로 (Workflow)에 반영됩니다.
이 단계들을 하나로 묶어주는 웹훅 핸들러 (Webhook handler)는 가볍게 유지됩니다. 전달을 빠르게 확인(Acknowledge)하고, 인증 이메일이 아닌 것은 무시하며, 본문을 가져와 코드를 추출합니다.
app.post("/webhooks/nylas", async (req, res) => {
res.sendStatus(200); // 먼저 확인을 보낸 후 작업을 수행합니다
const msg = req.body.data.object;
...
정규 표현식 (Regex)으로 먼저 추출하고, LLM을 폴백 (Fallback)으로 사용하기
대부분의 인증 이메일은 단순한 패턴으로 찾을 수 있는 어딘가에 코드를 배치하므로, 정규 표현식 (Regular expression)으로 시작하십시오. 표준 6자리 코드에 대한 패턴은 대다수의 OTP 및 2FA 이메일에 충분하며, 빠르고 비용이 들지 않으며 결정론적 (Deterministic)입니다.
// 메시지 본문에서 6자리 코드를 추출합니다
const match = body.match(/\b(\d{6})\b/);
const code = match ? match[1] : null;
패턴을 일반 텍스트 (Plain-text) 본문에 실행하거나, 먼저 HTML을 제거하여 인라인 스타일이나 트래킹 픽셀 (Tracking pixel)에 숨겨진 숫자가 아닌 눈에 보이는 코드가 일치하도록 하십시오. 코드의 길이가 다양하다면, 패턴을 \b(\d{4,8})\b로 넓혀 4자리에서 8자리 사이의 코드를 포착하도록 하고, 메시지에 다른 숫자가 포함되어 있는 경우 "code" 또는 "verification"과 같은 주변 단어에 앵커 (Anchor)를 설정하십시오. 하지만 과도하게 설계하지는 마십시오. 일정 수준을 넘어서면, 아래의 폴백 (Fallback) 방식이 점점 더 복잡해지는 패턴보다 예외 케이스를 더 안정적으로 처리합니다.
정규 표현식은 지저분한 케이스에서는 한계가 있습니다. 공백으로 나뉘어 있는 코드, 특이한 길이, 또는 숫자가 주문 번호와 나란히 있어 실수로 매칭될 수 있는 템플릿 등이 그러합니다. 바로 이 지점에서 LLM 폴백 (Fallback)의 가치가 드러납니다. 정규 표현식이 아무것도 반환하지 않거나 모호한 것을 반환할 때, 본문을 "이 이메일에서 로그인 인증 코드만 추출하세요"와 같은 정교한 프롬프트 (Prompt)와 함께 모델에 전달하여 패턴이 놓친 형식을 처리하도록 합니다. 정규 표현식 우선 (Regex-first) 방식은 일반적인 경로를 저렴하게 유지하며, 모델은 실제로 필요한 이메일에 대해서만 실행됩니다.
올바른 메시지로 필터링하기
가장 어려운 부분은 코드를 읽는 것이 아니라, 올바른 이메일을 읽고 있는지 확인하는 것입니다. 편지함에는 다른 메일들도 들어오며, 한 시간 전의 오래된 코드는 코드가 없는 것보다 더 나쁩니다. 양식 제출에 실패하여 버그처럼 보일 수 있기 때문입니다. 두 가지 필터가 대부분의 작업을 수행합니다. 코드가 발송된 발신자(sender)를 일치시키고, 요청을 트리거한 시점보다 최신인 메시지만 가져오는 것입니다.
두 필터 모두 messages 엔드포인트의 쿼리 파라미터(query parameters)입니다. from은 발신자 주소를 일치시키며, received_after는 Unix 타임스탬프(Unix timestamp)를 사용하여 트리거 이후에 도착한 메일만 볼 수 있게 합니다. 본문을 가져오거나 추출(extraction)을 실행하기 전에, 두 파라미터를 모두 사용한 단일 리스트 호출(list call)을 통해 후보를 중요한 단 하나의 메시지로 좁힐 수 있습니다. 서비스에 가입하는 에이전트(agent)의 경우, 발송 도메인을 미리 알고 있는 경우가 많으므로 발신자 필터는 추측이 아닌 정확한 값이 되며, 코드가 요청 후 몇 초 이내에 도착하기 때문에 최신성 윈도우(recency window)를 좁게 설정할 수 있습니다.
엔드-투-엔드 테스트(End-to-end tests)에서 사용하기
실제 로그인을 수행하는 엔드-투-엔드 테스트(End-to-end tests)는 가짜(fake)를 테스트하지 않고서는 인증 단계를 스텁(stub) 처리할 수 없습니다. nylas otp get --raw --no-copy는 테스트 하네스(test harness)에 끼워 넣을 수 있습니다. 테스트가 로그인 양식을 제출한 다음, 명령어를 호출하여 테스트 편지함에서 코드를 가져와 입력하는 방식입니다. 값이 서비스 제공자가 보낸 실제 값이므로, 테스트는 현실과 동떨어진 모의 객체(mock) 대신 실제 흐름을 다룹니다.
전용 테스트 편지함이나 실행마다 생성되는 Nylas 에이전트 계정(Nylas Agent Account)을 사용하면 이를 결정론적(deterministic)으로 유지할 수 있습니다. 각 테스트는 자신만의 수신함을 가지므로 병렬 실행 시 서로의 코드를 가져가지 않으며, 최신성 필터와 결합하면 테스트가 이전 실행의 오래된 코드를 집어 드는 일도 없습니다. 이러한 조합은 UI 테스트에서 악명 높게 불안정했던(flaky) 부분을 CI에서 안정적으로 통과하는 요소로 바꿔줍니다.
전체 흐름 합치기
이러한 요소들이 모여 인간의 개입(human in the loop) 없이 스스로를 검증하는 에이전트(agent)가 완성됩니다. 에이전트가 자신의 이메일 주소를 사용하여 제3자 서비스에 회원가입 또는 로그인을 시도하면, 서비스가 코드를 이메일로 발송하고, 에이전트는 이를 추출하여 단계를 완료합니다. CLI 환경에서는 회원가입이 진행되는 동안 nylas otp watch를 실행해 두면 되며, 애플리케이션 환경에서는 코드 이메일이 도착하는 즉시 실행되는 웹후크(webhook) 기반 패턴을 사용합니다.
이는 자동 계정 프로비저닝(account provisioning) 및 에이전트 온보딩(onboarding)의 이면에 있는 패턴입니다. 에이전트가 실제 편지함(inbox)을 소유하므로 사람이 받는 것과 동일한 인증 이메일을 수신하며, 추출 단계는 "코드가 이메일로 발송됨"과 "에이전트가 이를 입력함" 사이를 잇는 가교 역할을 합니다. 이 과정 중 어느 것도 누군가가 편지함을 지켜볼 필요를 요구하지 않으며, 이것이 바로 에이전트에게 자체 주소를 부여하는 핵심 목적입니다.
주의 사항
OTP 추출을 안정적이고 안전하게 유지하기 위한 몇 가지 실무 지침입니다.
- 최신성을 사용하여 만료된 코드를 방지하세요. 오래된 코드는 아무런 오류 없이 실패합니다. 단순히 일치하는 것을 찾는 것이 아니라, 트리거 이후에 도착한 가장 최신 메시지를 항상 선택해야 합니다.
- 코드를 절대 로그에 남기지 마세요. 인증 코드는 비밀번호와 마찬가지로 비밀입니다. 로그, 트레이스(trace), 에러 메시지에 포함되지 않도록 관리하세요.
- 코드를 수명이 짧은 것으로 취급하세요. 대부분의 코드는 몇 분 내에 만료되므로, 값을 나중에 사용하기 위해 큐(queue)에 쌓아두기보다는 즉시 추출하여 사용하세요.
- 정규표현식(regex)으로 시작하여 LLM으로 확장하세요. 정규표현식 패턴은 일반적인 케이스를 저렴하게 처리합니다. 모델(LLM)은 정규표현식으로 파싱할 수 없는 템플릿을 처리하는 용도로 아껴두세요.
- 가능하다면 발신자를 고정하세요. 발신 도메인을 미리 알고 있으면 모호한 검색을 정확한 필터링으로 전환할 수 있습니다.
- 자동화 시
--no-copy옵션을 전달하세요. CLI는 기본적으로 코드를 클립보드에 복사합니다. 이는 키보드를 사용하는 작업에는 유용하지만, 스크립트나 CI 실행 시에는 불필요한 부작용입니다.
마치며
이메일에서 인증 코드를 가져오는 방법은 터미널에서 nylas otp get 명령어를 사용하는 한 줄짜리 작업이거나, 코드가 발송되기를 기다리는 동안 nylas otp watch를 사용하여 대기 루프를 실행하는 것입니다. 애플리케이션 내에서는 동일한 작업이 하나의 작은 패턴으로 구현됩니다. message.created 웹훅 (webhook)이 메일 도착을 알려주면, 본문을 가져온 뒤, 복잡한 템플릿에 대응하기 위해 LLM (Large Language Model)의 지원을 받는 정규 표현식 (regex)을 사용하여 코드를 추출합니다. 이때 발신자와 최신성을 기준으로 필터링하여 올바른 메시지를 읽도록 하고, 해당 값을 절대 로그에 남기지 말아야 하며, 만료되기 전에 사용해야 합니다.
다음 단계로 진행하기:
- CLI로 OTP 코드 추출하기 —
nylas otp명령어에 대한 심층 분석 - 에이전트의 편지함에서 OTP 또는 2FA 코드 추출하기 — 정규 표현식 (regex)과 LLM 폴백 (fallback)을 활용한 웹훅 (webhook) 기반 레시피
- 메시지 가져오기 — 파싱을 위한 메시지 본문 가져오기
- message.created 웹훅 (webhook) — 이 패턴을 구동하는 트리거
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기