메일 보내기, 회신, 전달 API
POST /v1/messages로 새 메일을, /reply로 회신을, /forward로 전달을 보냅니다. 세 경로 모두 같은 발송 관문을 지납니다.
세 경로 모두 Idempotency-Key 헤더와 보내기(messages:send) 권한이 필요합니다.
새 메일 보내기
POST /v1/messages| 필드 | 필수 | 설명 |
|---|---|---|
agent_id | 예 | 토큰의 에이전트 ID |
from | 예 | 에이전트 주소. 소문자이고 +태그가 없어야 합니다. |
to | 예 | 받는 사람 주소 배열(비어 있으면 안 됨) |
subject | 예 | 제목 |
text | 예 | 텍스트 본문 |
html | 아니요 | HTML 본문 |
trace_id | 아니요 | 내 쪽 추적용 문자열. 감사 기록에 남습니다. |
curl -sS https://api.atmark.ai/v1/messages \
-H "Authorization: Bearer $ATMARK_AGENT_TOKEN" \
-H "Idempotency-Key: 2026-09-27-weekly-report" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "7c21…f5a1",
"from": "scout@atmark.ai",
"to": ["partner@example.com"],
"subject": "Weekly report",
"text": "Hello, here is this week's report."
}'결과
| 상태 코드 | 결과 | 본문 |
|---|---|---|
200 | 나감 | status: "sent", message_id, message_id_header, provider_message_id, decision |
202 | 승인 대기 | status: "pending_approval", message_id, approval_id, expires_at, decision |
403 | 정책 거부 | error: "policy_denied", message_id, decision |
409 | 멱등 키 충돌 | error: "idempotency_key_reused" |
502 | 발송 실패 | error: "send_failed". 메일은 나가지 않았습니다. 새 키로 다시 보낼 수 있습니다. |
| 위와 같음 | 다시 보낸 요청 | replayed: true와 그 메일의 지금 상태. 아래 |
provider_message_id는 메일이 나갈 때 붙는 배달 추적 ID입니다. 나가기 전에는 null입니다.
decision에는 판정(verdict), 사유 배열(reasons), 정책 버전(policy_version), 판정 시각(evaluated_at), 기다릴 시간(retry_after_seconds)이 들어 있습니다.
{
"status": "sent",
"message_id": "0f8a…",
"message_id_header": "<…@atmark.ai>",
"provider_message_id": "…",
"decision": {
"verdict": "allowed",
"reasons": ["allowlist_match"],
"policy_version": 3,
"evaluated_at": "2026-09-27T09:00:00.000Z",
"retry_after_seconds": null
}
}허용된 발송에도 reasons가 옵니다. 위 예의 allowlist_match는 받는 사람이 모두 발신 허용 목록에 있어서 나갔다는 뜻입니다. 모든 코드는 사유 코드에 있습니다.
403은 장애가 아니라 정책이 막은 정상 결과입니다. 같은 키로 다시 보내면 같은 거부가 돌아옵니다. 원인을 고쳤거나 retry_after_seconds만큼 기다린 뒤에는 새 Idempotency-Key로 보냅니다.
다시 보낸 요청의 응답
같은 Idempotency-Key로 같은 요청을 다시 보내면 메일은 또 나가지 않고, 그 메일의 지금 상태가 replayed: true와 함께 옵니다. 본문에는 status, message_id, message_id_header, provider_message_id가 들어 있고, decision·approval_id·expires_at은 없습니다. 판정은 GET /v1/audit?message_id=…, 승인은 GET /v1/approvals/{id}로 읽습니다.
| 상태 코드 | 지금 상태 |
|---|---|
200 | status: "sent" 나감 |
202 | status: "pending" 또는 "dispatching" 아직 나가지 않음(승인 대기 포함) |
403 | status: "denied", error: "policy_denied" |
502 | status: "failed", error: "send_failed" |
회신
POST /v1/threads/{threadId}/replythreadId는 받은 메일의 thread_id입니다.
| 필드 | 필수 | 설명 |
|---|---|---|
agent_id | 예 | 토큰의 에이전트 ID |
in_reply_to | 예 | 회신할 받은 메일의 id |
text | 예 | 텍스트 본문 |
html | 아니요 | HTML 본문 |
to | 아니요 | 생략하면 그 메일을 보낸 사람 |
subject | 아니요 | 생략하면 Re: 원래 제목 |
from | 아니요 | 생략하면 그 메일을 받은 주소 |
받은 메일이 없으면 404 message_not_found입니다. 결과는 새 메일과 같습니다.
전달
POST /v1/messages/{messageId}/forwardmessageId는 받은 메일의 id입니다.
| 필드 | 필수 | 설명 |
|---|---|---|
agent_id | 예 | 토큰의 에이전트 ID |
from | 예 | 에이전트 주소 |
to | 예 | 받는 사람 주소 배열 |
text | 아니요 | 전달 메일 위에 붙일 메모 |
subject | 아니요 | 생략하면 Fwd: 원래 제목 |
- 원 메일의 본문 텍스트만 옮깁니다.
html을 보내면400입니다. 첨부는 전달하지 않고, 응답의attachments_omitted에 빠진 개수가 옵니다. - 받은 메일의
injection_risk가none이 아니면422 forward_refused_injection_risk로 거부합니다. 내용이 필요하면 자기 말로 새 메일을 씁니다.
이 문서에 대한 의견은 support@atmark.ai로 보내 주세요.