AgentMail — AI 에이전트용 이메일은(는) 무엇을 하나요?
AgentMail은 AI 에이전트에게 실제 이메일 주소(@theagentmail.net)와 REST API를 제공합니다. 에이전트는 이메일을 보내고 받을 수 있으며, 서비스(GitHub, AWS, Slack 등)에 가입하고, 인증 코드를 수신할 수 있습니다. 카르마 시스템은 스팸을 방지하고 공유 도메인의 평판을 높게 유지합니다.
기본 URL: https://api.theagentmail.net
사용 시기
- AI 에이전트가 가입, 인증 흐름, 또는 트랜잭션 커뮤니케이션을 위해 실제 받은 편지함/보낸 편지함이 필요할 때
- AgentMail 계정을 생성하고, 메시지를 보내고, 받은 편지함 내용을 읽거나, 인바운드 웹훅을 등록해야 할 때
- 카르마 사용량을 모니터링하거나 이메일 이벤트를 에이전트 자동화에 연결해야 할 때
빠른 시작
모든 요청에는 Authorization: Bearer am_... 헤더(대시보드에서 발급받은 API 키)가 필요합니다.
이메일 계정 생성(-10 카르마)
curl -X POST https://api.theagentmail.net/v1/accounts \
-H "Authorization: Bearer am_..." \
-H "Content-Type: application/json" \
-d '{"address": "[email protected]"}'
응답: {"data": {"id": "...", "address": "[email protected]", "displayName": null, "createdAt": 123}}
이메일 보내기(-1 카르마)
curl -X POST https://api.theagentmail.net/v1/accounts/{accountId}/messages \
-H "Authorization: Bearer am_..." \
-H "Content-Type: application/json" \
-d '{
"to": ["[email protected]"],
"subject": "Hello from my agent",
"text": "Plain text body",
"html": "<p>Optional HTML body</p>"
}'
선택적 필드: cc, bcc (문자열 배열), inReplyTo, references (스레딩용 문자열), attachments (base64로 인코딩된 {filename, contentType, content} 배열)
받은 편지함 읽기
# 메시지 목록 조회
curl https://api.theagentmail.net/v1/accounts/{accountId}/messages \
-H "Authorization: Bearer am_..."
# 전체 메시지 조회 (본문 및 첨부 파일 포함)
curl https://api.theagentmail.net/v1/accounts/{accountId}/messages/{messageId} \
-H "Authorization: Bearer am_..."
카르마 확인
curl https://api.theagentmail.net/v1/karma \
-H "Authorization: Bearer am_..."
응답: {"data": {"balance": 90, "events": [...]}}
웹훅 등록 (실시간 인바운드)
curl -X POST https://api.theagentmail.net/v1/accounts/{accountId}/webhooks \
-H "Authorization: Bearer am_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://my-agent.example.com/inbox"}'
웹훅 전달에는 두 가지 보안 헤더가 포함됩니다.
X-AgentMail-Signature-- 요청 본문의 HMAC-SHA256 16진수 다이제스트. 웹훅 시크릿으로 서명됨X-AgentMail-Timestamp-- 전송 시간의 밀리초 타임스탬프
재생 공격을 방지하려면 서명을 확인하고 5분보다 오래된 타임스탬프의 요청을 거부하세요.
import { createHmac } from "crypto";
const verifyWebhook = (body: string, signature: string, timestamp: string, secret: string) => {
if (Date.now() - Number(timestamp) > 5 * 60 * 1000) return false;
return createHmac("sha256", secret).update(body).digest("hex") === signature;
};
첨부 파일 다운로드
curl https://api.theagentmail.net/v1/accounts/{accountId}/messages/{messageId}/attachments/{attachmentId} \
-H "Authorization: Bearer am_..."
응답: {"data": {"url": "https://signed-download-url..."}}
전체 API 레퍼런스
| 메서드 | 경로 | 설명 | 카르마 |
|---|---|---|---|
| POST | /v1/accounts | 이메일 계정 생성 | -10 |
| GET | /v1/accounts | 모든 계정 목록 조회 | |
| GET | /v1/accounts/:id | 계정 세부 정보 조회 | |
| DELETE | /v1/accounts/:id | 계정 삭제 | +10 |
| POST | /v1/accounts/:id/messages | 이메일 보내기 | -1 |
| GET | /v1/accounts/:id/messages | 메시지 목록 조회 | |
| GET | /v1/accounts/:id/messages/:msgId | 전체 메시지 조회 | |
| GET | /v1/accounts/:id/messages/:msgId/attachments/:attId | 첨부 파일 URL 조회 | |
| POST | /v1/accounts/:id/webhooks | 웹훅 등록 | |
| GET | /v1/accounts/:id/webhooks | 웹훅 목록 조회 | |
| DELETE | /v1/accounts/:id/webhooks/:whId | 웹훅 삭제 | |
| GET | /v1/karma | 잔액 및 이벤트 조회 |
카르마 시스템
모든 작업에는 카르마 비용 또는 보상이 있습니다.
| 이벤트 | 카르마 | 이유 |
|---|---|---|
money_paid | +100 | 크레딧 구매 |
email_received | +2 | 신뢰할 수 있는 도메인에서 회신 |
account_deleted | +10 | 주소 삭제 시 카르마 환불 |
email_sent | -1 | 전송 시 카르마 소모 |
account_created | -10 | 주소 생성 시 카르마 소모 |
중요 규칙:
- 신뢰할 수 있는 제공업체(Gmail, Outlook, Yahoo, iCloud, ProtonMail, Fastmail, Hey 등)의 인바운드 이메일에 대해서만 카르마가 적립됩니다. 알 수 없거나 일회용 도메인의 이메일은 카르마를 적립해 주지 않습니다.
- 에이전트가 답장할 때까지 발신자당 한 번만 카르마가 적립됩니다. 발신자 X가 답장 없이 5번 이메일을 보내면 첫 번째 이메일에 대해서만 카르마가 적립됩니다. X에게 답장하면, X의 다음 이메일부터 다시 카르마가 적립됩니다.
- 계정을 삭제하면 생성 시 소모된 10 카르마가 환불됩니다.
카르마가 0에 도달하면 전송 및 계정 생성 시 HTTP 402가 반환됩니다. 카르마가 소모되는 작업을 수행하기 전에 항상 잔액을 확인하세요.
TypeScript SDK
import { createClient } from "@agentmail/sdk";
const mail = createClient({ apiKey: "am_..." });
// 계정 생성
const account = await mail.accounts.create({
address: "[email protected]",
});
// 이메일 보내기
await mail.messages.send(account.id, {
to: ["[email protected]"],
subject: "Hello",
text: "Sent by an AI agent.",
});
// 받은 편지함 읽기
const messages = await mail.messages.list(account.id);
const detail = await mail.messages.get(account.id, messages[0].id);
// 첨부 파일
const att = await mail.attachments.getUrl(accountId, messageId, attachmentId);
// att.url은 서명된 다운로드 URL입니다
// 웹훅
await mail.webhooks.create(account.id, {
url: "https://my-agent.example.com/inbox",
});
// 카르마
const karma = await mail.karma.getBalance();
console.log(karma.balance);
오류 처리
import { AgentMailError } from "@agentmail/sdk";
try {
await mail.messages.send(accountId, { to: ["[email protected]"], subject: "Hi", text: "Hey" });
} catch (e) {
if (e instanceof AgentMailError) {
console.log(e.status); // 402, 404, 401 등
console.log(e.code); // "INSUFFICIENT_KARMA", "NOT_FOUND" 등
console.log(e.message);
}
}
일반적인 패턴
서비스 가입 및 인증 이메일 읽기
const account = await mail.accounts.create({
address: "[email protected]",
});
// 주소를 사용하여 가입 (브라우저 자동화, API 등)
// 인증 이메일 폴링
for (let i = 0; i < 30; i++) {
const messages = await mail.messages.list(account.id);
const verification = messages.find(m =>
m.subject.toLowerCase().includes("verify") ||
m.subject.toLowerCase().includes("confirm")
);
if (verification) {
const detail = await mail.messages.get(account.id, verification.id);
// detail.bodyText 또는 detail.bodyHtml에서 인증 링크/코드 파싱
break;
}
await new Promise(r => setTimeout(r, 2000));
}
이메일 보내기 및 회신 대기
const sent = await mail.messages.send(account.id, {
to: ["[email protected]"],
subject: "Question about order #12345",
text: "Can you check the status?",
});
for (let i = 0; i < 60; i++) {
const messages = await mail.messages.list(account.id);
const reply = messages.find(m =>
m.direction === "inbound" && m.timestamp > sent.timestamp
);
if (reply) {
const detail = await mail.messages.get(account.id, reply.id);
// 회신 처리
break;
}
await new Promise(r => setTimeout(r, 5000));
}
타입
type Account = { id: string; address: string; displayName: string | null; createdAt: number };
type Message = { id: string; from: string; to: string[]; subject: string; direction: "inbound" | "outbound"; status: string; timestamp: number };
type MessageDetail = Message & { cc: string[] | null; bcc: string[] | null; bodyText: string | null; bodyHtml: string | null; inReplyTo: string | null; references: string | null; attachments: AttachmentMeta[] };
type AttachmentMeta = { id: string; filename: string; contentType: string; size: number };
type KarmaBalance = { balance: number; events: KarmaEvent[] };
type KarmaEvent = { id: string; type: string; amount: number; timestamp: number; metadata?: Record<string, unknown> };
제한 사항
- 이 스킬은 작업이 위에 설명된 범위와 명확하게 일치하는 경우에만 사용하세요.
- 출력물을 환경별 검증, 테스트 또는 전문가 검토를 대체하는 용도로 취급하지 마세요.
- 필요한 입력, 권한, 안전 경계 또는 성공 기준이 누락된 경우 중단하고 명확히 요청하세요.