AI 에이전트가 스스로 가입할 수 있도록 전용 편지함을 제공하세요
요약
AI 에이전트가 서비스 가입 및 인증 과정을 스스로 수행할 수 있도록 휘발성 전용 편지함을 제공하는 Nylas Agent Account 활용법을 소개합니다. 개인 계정 대신 실행마다 생성되고 삭제되는 일회용 계정을 통해 보안과 격리 문제를 해결하는 방법을 다룹니다.
핵심 포인트
- AI 에이전트의 자율적 가입을 위한 휘발성(Ephemeral) 편지함 필요성
- 개인 Gmail 사용 시 발생하는 보안 및 데이터 혼선 문제 해결
- Nylas Agent Account를 통한 자동화된 인증 및 OTP 처리
- grant_id 추상화 모델을 활용한 기존 API 엔드포인트와의 호환성
대부분의 "AI 이메일" 데모는 OAuth를 통해 모델을 사람의 편지함에 연결합니다. Gmail을 연결하면 에이전트가 스레드를 읽고, 답장을 초안하고, 어쩌면 전송까지 합니다. 에이전트가 당신을 대신하여(on your behalf) 행동할 때, 즉 당신의 편지함에 동승한 부조종사(copilot) 역할을 할 때는 괜찮습니다.
하지만 에이전트가 자신만의 참여자가 되기를 원하는 순간 문제가 발생합니다. 매 CI 실행 시 SaaS에 테스트 테넌트(tenant)를 등록하는 온보딩 에이전트, 데이터 소스에 대한 개발자 계정이 필요한 리서치 에이전트, 또는 각 테스트를 위해 새로운 계정을 가입, 인증 및 삭제하는 QA 봇을 상상해 보세요. 이 모든 흐름은 동일한 벽에 부딪힙니다. 서비스가 인증 링크나 일회용 코드(one-time code)를 이메일로 보내는데, 이를 받을 사람의 편지함이 없다는 점입니다. 이를 위해 당신의 개인 Gmail을 빌려 쓰는 것은 보안, 격리, 정리, 그리고 수천 개의 일회용 가입 메일이 당신의 실제 편지함에 쌓이는 것을 원치 않는다는 단순한 사실 등 모든 측면에서 잘못된 방식입니다.
에이전트에게 실제로 필요한 것은 자신이 완전히 제어할 수 있는 실제의, 일회용 편지함입니다. 휘발성(Ephemeral)이어야 하며, 실행당 하나씩 생성되어야 합니다. 작업 시작 시 프로비저닝(Provisioned)되고 작업 종료 시 삭제되어야 합니다. 그것이 바로 Nylas Agent Account가 제공하는 것이며, 이 포스트에서 구축할 내용이기도 합니다. 즉, 서비스에 스스로 가입하고 자체 인증 이메일이나 OTP(One-Time Password)를 처음부터 끝까지 읽는 에이전트입니다.
저는 Nylas CLI를 다루기 때문에, 아래의 터미널 명령어들은 제가 실제로 사용하는 것들입니다. 모든 단계에 대해 두 가지 관점, 즉 가공되지 않은 curl HTTP 호출과 그에 상응하는 nylas CLI 명령어를 모두 보여드리겠습니다. 실제로는 에이전트가 API를 호출하지만, 당신은 터미널에서 디버깅을 하기 때문입니다.
Agent Account란 실제로 무엇인가
이 모든 것을 다루기 쉽게 만드는 핵심은 다음과 같습니다. Agent Account는 단순한 **권한 부여 (grant)**입니다. 여러분이 이미 모든 OAuth 연결 메일함에 사용하고 있는 것과 동일한 grant_id 추상화 모델입니다. 지원되는 엔드포인트(endpoints)에 대해서는 데이터 평면 (data plane) 상에서 새로 배울 것이 없습니다. 일단 grant_id를 확보하면 메시지 (Messages), 초안 (Drafts), 스레드 (Threads), 폴더 (Folders), 첨부 파일 (Attachments), 연락처 (Contacts), 캘린더 (Calendars), 이벤트 (Events) 모두 연결된 Gmail이나 Microsoft 계정에서 작동하는 방식과 정확히 동일하게 작동하며, 표준 웹훅 (webhooks)도 지원됩니다.
하지만 이것이 권한 부여 (grant)의 전체 기능 범위는 아니며, 이를 기반으로 설계를 하기 전에 이 점을 알아두는 것이 중요합니다. 스마트 작성 (Smart Compose), 템플릿 (Templates), 워크플로우 (Workflows), 스케줄러 (Scheduler), 노트 작성기 (Notetaker), 그리고 커스텀 메타데이터 (custom metadata)는 Agent Account 권한 부여에서 지원되지 않습니다. 자율적인 가입 (autonomous signup) 과정—메일 수신, 본문 읽기, 코드 파싱—에는 이 기능들이 필요하지 않으므로 문제가 되지 않지만, 특정 엔드포인트가 OAuth 권한 부여에서 작동한다고 해서 Agent Account에서도 당연히 작동할 것이라고 가정해서는 안 됩니다.
차이점은 권한 부여 (grant)가 생성되는 방식에 있습니다. OAuth 인증 과정 (OAuth dance)도, 리프레시 토큰 (refresh token)도, 사용자가
- OAuth 없음. 사람 뒤에 존재하지 않는 편지함에는 OAuth로 로그인할 수 없습니다. 에이전트 계정 (Agent Accounts)은 전체 동의 흐름 (consent flow)을 건너뜁니다.
- 실제 전달 가능한 주소. 인증 이메일이 실제로 도착합니다. 이것은 단순히 모든 메일을 받는 별칭 (catch-all alias)이나 본인 도메인의 플러스 트릭 (plus-trick)이 아닙니다. 이는 일급 객체인 편지함 (first-class mailbox)입니다.
- 완전한 제어권. 귀하의 애플리케이션이 권한 부여 (grant)를 소유합니다. API를 통해 편지함을 읽으며, 그 누구의 허락도 구할 필요가 없습니다.
- 사용 후 폐기. 실행이 끝나면 권한 부여를 삭제하여 편지함을 없앨 수 있습니다. 좀비 계정 (zombie accounts)이 쌓이지 않습니다.
시작하기 전에
두 가지가 필요합니다:
- Nylas API 키. 키가 없다면,
nylas init명령 하나로 계정을 생성하고 키를 발급받을 수 있으며, 또는 대시보드 (Dashboard)에서 직접 가져올 수 있습니다. - 등록된 도메인. 모든 에이전트 계정은 도메인 상에 존재합니다. 프로토타이핑 (prototyping)을 위해 Nylas는 체험용
*.nylas.email서브도메인을 제공하므로, 즉시signup-agent@your-app.nylas.email을 생성할 수 있습니다. 프로덕션 (production) 환경을 위해서는 귀하의 서브도메인(예:agents.yourcompany.com)을 등록하고 Nylas가 제공하는 MX 및 TXT 레코드를 게시해야 합니다. 새 도메인은 약 4주에 걸쳐 워밍업 (warm up)이 필요하므로, 출시 당일 아침에 등록하지 마십시오.
아래 모든 예제의 API 베이스 호스트 (API base host)는 https://api.us.nylas.com이며, 인증은 베어러 토큰 (bearer token) 방식을 사용합니다: Authorization: Bearer <NYLAS_API_KEY>.
일회용 편지함 프로비저닝 (Provision)
이 단계는 에이전트 계정 (Agent Accounts)에만 특화된 유일한 단계입니다. CLI에서는 한 줄로 실행됩니다:
nylas agent account create signup-agent@agents.yourcompany.com
이 명령은 새로운 권한 부여 (grant)의 id, 상태, 커넥터 (connector) 상세 정보를 출력합니다. 해당 id를 AGENT_GRANT_ID로 저장하세요. 이는 이후의 모든 작업에 대한 핸들 (handle)이 됩니다. 생성 명령은 또한 발신 메일에 표시될 이름을 위한 --name 옵션과, 디버깅 중에 사람이 일반 메일 클라이언트에서 편지함을 확인할 수 있도록 IMAP/SMTP 액세스를 허용하는 --app-password 옵션을 지원합니다:
nylas agent account create signup-agent@agents.yourcompany.com \
--name "Onboarding Agent" \
--app-password "MySecureP4ssword!2024"
생성 시에는 의도적으로 --workspace 플래그를 포함하지 않았습니다. API가 해당 계정에 대한 기본 워크스페이스 (workspace) 및 정책 (policy)을 자동으로 생성하며, 더 엄격한 사용자 정의 정책을 연결하고 싶다면 이후에 nylas workspace update <workspace-id> --policy-id <policy-id> 명령을 통해 수행하면 됩니다.
CLI는 POST /v3/connect/custom에 대한 얇은 래퍼 (thin wrapper)입니다. 다음은 에이전트가 직접 호출하는 것과 동일한 호출 방식입니다. 표시 이름 (display name)은 최상위 name이며, 앱 비밀번호 (app password)가 필요한 경우 settings 내부에 들어갑니다 (18~40자의 출력 가능한 ASCII 문자로 구성되며, 최소 하나의 대문자, 하나의 소문자, 하나의 숫자를 포함해야 합니다. 아래 예시는 이 조건을 충족합니다):
curl --request POST \
--url "https://api.us.nylas.com/v3/connect/custom" \
--header "Authorization: Bearer <NYLAS_API_KEY>" \
...
앱 비밀번호는 선택 사항입니다. 이를 제외하면 API 전용 편지함 (API-only mailbox)을 얻게 되며, 이는 자율 에이전트 (autonomous agent)가 실제로 필요로 하는 전부입니다. 사람이 메일 클라이언트를 연결하여 에이전트가 수신하는 내용을 모니터링해야 하는 경우에만 포함하세요.
"provider": "nylas"는 API에 이것이 OAuth 권한 부여 (OAuth grant)가 아닌 에이전트 계정 (Agent Account)임을 알려주는 역할을 합니다. 이것이 본문에 리프레시 토큰 (refresh token)이 없는 이유입니다. 응답에는 다음과 같이 권한 부여 (grant) 정보가 포함됩니다:
{
"request_id": "5967ca40-a2d8-4ee0-a0e0-6f18ace39a90",
"data": {
...
data.id가 귀하의 grant_id입니다. 실행당 하나의 에이전트 (per-run agent)를 사용하는 경우, 이 모든 단계는 작업의 시작 단계에서 발생합니다. 즉, 새로운 편지함을 프로비저닝 (provision)하고, 작업을 수행한 뒤, 마지막에 삭제합니다. 실행당 하나의 받은 편지함 (inbox)을 사용합니다.
가입 트리거하기
이 단계는 전적으로 귀하의 코드 내에서 이루어지므로, 개념적인 수준에서 설명하겠습니다. 귀하의 에이전트는 에이전트 계정 (Agent Account)의 주소를 이메일로 사용하여 대상 서비스의 가입 양식을 작성합니다. 서비스가 API를 노출하고 있다면 직접적인 API 호출(API call)을, 실제 양식을 처리해야 한다면 Playwright를 사용한 헤드리스 브라우저 (headless browser) 단계, 또는 단순한 fetch POST 방식 등 어떤 형태를 취하든 여기서 중요한 것은 이메일 필드가 signup-agent@agents.yourcompany.com이어야 한다는 점입니다.
await fetch("https://saas-you-care-about.example.com/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
...
서비스는 평소와 같이 동작합니다. 즉, 해당 주소로 인증 이메일을 보냅니다. 이제 이 주소는 귀하의 에이전트가 실제로 읽을 수 있는 주소가 되었습니다.
인증 이메일 수신하기
수신된 메시지를 가져오는 방법에는 두 가지가 있으며, 어떤 방법을 사용할지는 귀하의 에이전트가 어떤 구조로 설계되었는지에 따라 달라집니다.
메시지 엔드포인트 폴링 (Poll)
만약 귀하의 에이전트가 양식 제출, 대기, 받은 편지함 읽기 순으로 진행되는 직선형 스크립트 (straight-line script)라면, 폴링 (polling) 방식이 가장 간단하고 효과적입니다. 편지함 목록을 나열하고 발신자(sender)와 제목(subject)으로 필터링하여, 실수로 "Welcome" 이메일을 파싱하지 않도록 하세요. 권한 범위가 지정된 메시지 엔드포인트 (grant-scoped Messages endpoint)는 GET /v3/grants/{grant_id}/messages이며, from 및 subject와 같은 표준 쿼리 필터(query filters)를 지원합니다 (값은 URL 인코딩해야 합니다):
curl --request GET \
--url "https://api.us.nylas.com/v3/grants/<AGENT_GRANT_ID>/messages?limit=5&from=no-reply@saas-you-care-about.example.com&subject=verify" \
--header "Authorization: Bearer <NYLAS_API_KEY>"
한 가지 알아두어야 할 점은, 제공업체별 네이티브 검색 구문 (search_query_native)은 에이전트 계정 (Agent Accounts)에 적용되지 않으며, 본문 전체 텍스트 검색 (full-text body search) 기능도 아직 지원되지 않는다는 것입니다. 따라서 from, subject 등과 같은 구조화된 필터 파라미터 (structured filter params)를 사용하고, 본문을 가져온 후 세부적인 매칭(정확한 코드나 링크 등)은 직접 수행하십시오.
터미널에서 nylas email list와 nylas email search는 더 친숙한 플래그(flags)를 사용하여 동일한 기능을 수행합니다. 디버깅하는 동안 에이전트의 편지함을 모니터링하려면 다음을 사용하십시오:
# 편지함의 모든 항목을 최신순으로 나열
nylas email list signup-agent@agents.yourcompany.com --limit 5
...
제목(subject)까지 매칭하고 싶을 때는 nylas email search가 더 적합하며, 이는 인증 메일을 식별하기 위해 원하는 정확한 판별자(discriminator)가 됩니다:
nylas email search "verify" signup-agent@agents.yourcompany.com \
--from no-reply@saas-you-care-about.example.com \
--subject "verify your email"
list와 search 모두 권한 ID (grant ID, 또는 계정 이메일)를 위치 인자(positional argument)로 받으므로, 동일한 명령어를 여러분이 프로비저닝(provisioned)한 모든 에이전트 계정(Agent Account)에 사용할 수 있습니다. 출력을 다른 곳으로 파이핑(piping)하려면 --json을 추가하십시오.
nylas webhook create \
--url https://youragent.example.com/webhooks/signup \
--triggers message.created
동일한 API 호출:
--url "https://api.us.nylas.com/v3/webhooks" \
--header "Authorization: Bearer <NYLAS_API_KEY>" \
...
Nylas는 메일이 도착한 후 1~2초 이내에 message.created 이벤트를 발생시킵니다. 페이로드(payload)에는 메시지의 요약 필드인 id, grant_id, from, subject, snippet, date가 포함되지만, 전체 본문(full body)은 포함되지 않습니다. 따라서 핸들러(handler)에서 요약 정보를 바탕으로 필터링한 다음, 관심 있는 메시지의 본문을 가져와야 합니다. (에이전트 계정은 또한 message.delivered, message.bounced, message.complaint와 같은 전달 가능성(deliverability) 웹훅을 발생시키는데, 이는 외부로 발송되는(outbound) 메일을 디버깅할 때 유용하지만, 가입(signup) 프로세스에서는 message.created만 있으면 됩니다.)
app.post("/webhooks/signup", async (req, res) => {
// 무엇이든 신뢰하기 전에 여기서 X-Nylas-Signature 헤더를 검증하십시오.
res.status(200).end();
...
웹훅에 즉시 200으로 응답(Ack)한 다음 작업을 수행하십시오. 웹훅 핸들러는 수명이 짧은 프로세스에서 실행되므로, 본문을 가져오는 작업 때문에 응답이 차단(block)되지 않도록 주의하십시오.
OTP 또는 인증 링크 추출하기
이제 실제 메시지를 읽으십시오. 웹훅(webhook)은 요약된 필드만 제공하므로, GET /v3/grants/{grant_id}/messages/{message_id}를 통해 전체 본문(full body)을 가져오십시오:
curl --request GET \
--url "https://api.us.nylas.com/v3/grants/<AGENT_GRANT_ID>/messages/<MESSAGE_ID>" \
--header "Authorization: Bearer <NYLAS_API_KEY>"
터미널에서 nylas email read를 실행하면 전체 메시지가 출력됩니다. 저는 정규 표현식(regex)을 구축하는 동안 이 기능을 끊임없이 활용하는데, 인증 이메일의 실제 본문을 직접 확인하는 것이 파싱(parsing)할 내용을 알 수 있는 유일하고 신뢰할 수 있는 방법이기 때문입니다. --raw 플래그는 HTML 처리 없이 본문을 보여주며, 이는 파서(parser)가 원시 콘텐츠(raw content)에서 작동할 때 필요한 방식입니다:
nylas email read <MESSAGE_ID> signup-agent@agents.yourcompany.com --raw
링크든 코드든, 추출 작업은 본문에 대한 정규 표현식(regex)을 사용하는 것입니다. 확인 링크의 경우:
async function handleVerification(messageId) {
const resp = await fetch(
`https://api.us.nylas.com/v3/grants/${AGENT_GRANT_ID}/messages/${messageId}`,
...
정규 표현식(regex)을 우선적으로 사용하는 것이 올바른 기본값입니다. 몇 가지 패턴만으로도 대다수의 인증 이메일을 커버할 수 있으며, 비용이 저렴하고 환각(hallucination) 현상이 발생하지 않습니다. CLI에는 두 가지 AI 이메일 기능이 포함되어 있지만, 둘 다 코드를 추출하지는 않습니다. nylas email ai analyze는 최근 메일 묶음을 요약하고 분류(triage)하며, nylas email smart-compose는 프롬프트(prompt)를 기반으로 새 메일을 초안(draft) 작성합니다. 하나는 받은 편지함을 높은 수준에서 읽고, 다른 하나는 발신 메시지를 작성할 뿐입니다. 둘 다 본문에서 인증 코드를 추출하지 않으므로, 여기서는 정규 표현식(regex)이 여전히 적절한 도구입니다. 만약 템플릿이 정규 표현식으로 처리하기에 정말로 너무 복잡한 서비스에 직면한다면, 그때가 바로 정제된 본문을 좁은 범위의 프롬프트("인증 코드를 JSON으로 반환하거나, 없으면 null을 반환하세요")와 함께 작은 LLM(대규모 언어 모델)에 전달할 시점입니다. 이를 기본 경로가 아닌 폴백(fallback, 대비책)으로 유지하십시오. 아래에 링크된 동반 쿡북(cookbook) 레시피에서 LLM 폴백 과정을 자세히 설명합니다.
가입 완료
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기