문서로 건너뛰기
API

이메일 보내기

POST /emails: 메시지 하나를 지금 또는 나중에.

POSTapi.openemail.uk/emails

본인 키로 워크스페이스에 실제 호출을 실행합니다.

요청

from은 필수입니다. 작성기와 달리 기본 발신자가 없는데, 그 기본값이 워크스페이스 기본 주소이고 주소가 늘고 줄 때마다 눈에 띄지 않게 바뀌기 때문입니다.

필드필수설명
from주소만 쓰거나 Name <addr> 형식입니다. 키가 발신자로 쓸 수 있는 주소여야 합니다.
toto, cc, bcc를 모두 합쳐 최대 50명입니다.
cc, bcc아니요bcc 수신자는 다른 사람이 받는 바이트에 절대 드러나지 않습니다.
subject아니요기본값은 빈 문자열입니다.
html, text택 1둘 다 보내도 됩니다. 수신자가 보는 것은 HTML입니다.
template택 1{ id, version?, props?, slots? }. 저장된 본문을 id나 slug로 지정합니다. html, text 또는 draftId와 함께 쓰면 거부됩니다. 템플릿으로 발송하기를 참고하세요.
replyTo아니요주소 하나입니다.
headers아니요X-*, List-*, Reply-To, Precedence, Auto-Submitted, Importance, Priority, Feedback-Id.
attachments아니요base64로 담은 { filename, content, contentType }, 총 5 MB까지이거나, 워크스페이스에 이미 있는 파일을 가리키는 { fileId }입니다. 최대 20개입니다.
attachmentDelivery아니요mime, link 또는 auto. auto는 파일 도메인이 활성화된 도메인에서 파일이 2 MB를 넘으면 링크로 보냅니다. 기본값은 메일함 설정입니다.
threadId아니요기존 스레드에 답장으로 넣습니다.
draftId아니요기존 초안을 발송합니다.
scheduledAt아니요ISO 시각 또는 기간입니다. 예약 항목을 참고하세요.
cancellableForSeconds아니요즉시 발송에 0~900초의 취소 가능 시간을 둡니다. scheduledAt과 함께 쓰면 거부되며, 예약 발송은 발송될 때까지 계속 취소 가능합니다. 예약 항목을 참고하세요.
signature아니요false면 이 메시지에 서명을 넣지 않습니다. 그렇지 않으면 발송 주소의 서명이 붙는데, 그 주소 자체의 서명이거나 All addresses에 설정된 서명입니다.
tags아니요직접 붙이는 라벨 최대 10개입니다. 그대로 되돌려 줄 뿐 해석하지 않습니다.
tracking아니요{ opens?, clicks? }. 둘 중 무엇이든 이 메시지에 한해 설정을 덮어씁니다. 필드를 생략하면 그쪽 절반은 발송 주소의 설정으로, 없으면 All addresses의 설정으로 돌아가며, 둘 중 하나가 끄지 않았다면 켜져 있습니다.
translate아니요{ to, from?, subject?, includeOriginal? }. 수신자의 언어로 보냅니다. 요청이 수락되는 시점에 처리되며, draftId와 함께 쓰면 거부됩니다.

알 수 없는 필드는 무시되지 않고 거부되므로, 이름을 잘못 쓰면 나중에 놀라는 대신 지금 422가 납니다. 발신자 인가를 무력화할 수 있는 헤더(From, Sender, Bcc, Message-ID, Return-Path 등)는 reserved_header로 거부됩니다.

응답

메시지가 이미 나갔으면 200, 아직 무언가가 더 일어나야 하면 202입니다. 상태 코드로 분기하는 호출자는 두 경우 모두에서 옳습니다.

200 OK
{  "object": "email",  "id": "msg_c5f21cc6bfec4e848caf905b",  "status": "sent",  "mode": "live",  "from": "[email protected]",  "subject": "Your September invoice",  "messageId": "<2598…@acme.com>",  "transport": "ses",  "sentAt": "2026-08-29T08:19:08.000Z",  "source": "api",  "replayed": false}

id는 계속 보관하는 영속적인 핸들이자, 전달 이벤트가 되돌아올 때 사용하는 값입니다. 반송 웹훅도 이를 emailId로 지칭합니다. messageId는 RFC 5322 Message-ID이며 MIME이 존재하기 전까지는 null입니다. 이 값으로 상관관계를 맺지 마세요. 발송 서비스가 나가는 길에 그 헤더를 다시 쓰기 때문에, 여기 담긴 값은 어떤 반송 보고서나 전달 보고서에도 나타나지 않으며 이 값에 대한 매칭은 절대 성립하지 않습니다.

수신자의 언어로

translate는 메시지가 나가기 전에 다른 사람의 언어로 다시 씁니다. 본문과, 끄지 않았다면 제목까지 요청이 수락되는 순간에 번역됩니다. 이는 template이 따르는 규칙과 동일하며 같은 이유로 중요합니다. 예약된 메시지는 화요일에 모델이 만들어 내는 무언가가 아니라 승인된 문구를 담아야 하고, 번역을 만들어 내지 못하면 행이 생기기 전에 발송이 거부되어야 합니다. 발신자가 선택하지 않은 언어로는 아무것도 전달되지 않습니다.

translate

tostring필수
어떤 언어로 쓸지입니다. BCP-47 코드(`de`), 영어 이름("German"), 또는 그 언어 자신의 이름("Deutsch")이며 2~60자입니다. 셋 다 다른 처리에 앞서 테이블 코드로 정규화되므로 결국 같은 요청이 되는데, Idempotency-Key 지문이 파싱된 요청을 대상으로 계산되기 때문에 이 점이 중요합니다. 별칭도 해석됩니다. `zh-TW`는 `zh-Hant`가 됩니다. 아무것으로도 해석되지 않는 값은 `translate.to`에 대한 422입니다.
fromstring
원문을 어떤 언어로 썼는지이며, 위와 같은 세 가지 형태 모두 가능합니다. 순전히 최적화용입니다. 생략하면 본문을 읽어 언어를 판별하며, 짧은 모델 호출 한 번의 비용이 듭니다. 트래픽이 많은 경로라면 명시할 가치가 있고, 본문이 대부분 이름과 숫자와 링크라면 더욱 그렇습니다. 판별은 추측하는 대신 판단을 보류하며, 원본 언어가 확정되지 않아도 원문 위 캡션에 표시될 언어 이름을 잃는 것 말고는 손해가 없습니다. 주소인 최상위 `from`과는 다릅니다.
subjectboolean
제목 줄도 함께 번역합니다. 기본값은 true이며, false면 제목은 쓴 그대로 나갑니다.
includeOriginalboolean
실제로 쓴 원문을 번역문 아래에, 구분선 뒤에 수신자의 언어로 된 캡션과 함께 넣습니다. 기본값은 true이며, 켜 두는 편이 좋습니다. 이상하게 읽히는 문장을 읽는 사람이 직접 확인할 수 있게 해 주는 유일한 장치이며, 그렇지 않으면 양쪽 모두 출력을 볼 수 없는 모델을 믿으라고 요구하는 셈이 됩니다.
curl
curl -X POST "$OE/emails" -H "$AUTH" -H "Content-Type: application/json" \  -d '{    "from": "[email protected]",    "to": ["[email protected]"],    "subject": "Your September invoice",    "html": "<p>Invoice attached. Payment is due on the 14th.</p>",    "translate": { "to": "de" }  }'
200 OK
{  "object": "email",  "id": "msg_c5f21cc6bfec4e848caf905b",  "status": "sent",  "from": "[email protected]",  "subject": "Ihre Rechnung für September",  "translation": {    "language": "de",    "languageName": "German",    "detectedSourceLanguage": "en",    "subject": true,    "includeOriginal": true  }}

translation은 추가로 붙는 필드이며 번역된 메시지에만 나타납니다. 이 응답과 GET /emails/{id}에는 담기지만 목록 행에는 절대 담기지 않는데, 목록은 저장된 요청을 가져오지 않으므로 목록에서의 부재는 어느 쪽도 의미하지 않기 때문입니다. 여기에는 언어 행 전체가 아니라 코드가 담깁니다. 무엇이 수행되었는지에 대한 기록이며, 자기 이름(endonym)은 GET /languages에 있습니다. 응답의 subject는 번역된 제목이므로, 콘솔이 수신자가 본 적 없는 문자열로 메시지를 나열하는 일은 없습니다.

  • template과 함께 동작하며, 바로 그 경우가 유용합니다. 번역되는 것은 렌더링된 결과이므로, 저장된 본문 하나로 고객이 읽는 모든 언어를 감당할 수 있습니다. 문서 전체를 렌더링하는 템플릿은 먼저 분해됩니다. 모델에 도달하는 것은 <body> 안의 내용뿐이고, doctype과 <style> 블록, @font-face 규칙은 결과 주위에 다시 붙습니다. 30,000자 제한이 문서가 아니라 산문을 재는 이유도 이것입니다. 브랜드 스타일시트로 감싼 두 줄짜리 메시지는 여전히 두 줄짜리 메시지입니다.
  • 템플릿에서 번역되지 않는 유일한 부분은 <title>이며, 이를 표시하는 메일 클라이언트는 없습니다. react-email의 <Preview>는 본문으로 렌더링되므로 나머지와 함께 번역됩니다.
  • draftId와 함께 쓰면 거부됩니다. translate에 대한 422이며, "초안은 쓰인 그대로 발송됩니다. 본문을 번역하거나 초안을 보내되, 둘 다는 안 됩니다"라고 알려 줍니다. 초안은 사람이 쓴 것이고 그 사람이 남긴 그대로 발송됩니다.
  • 의도적으로 멱등성 지문에 포함되지 않습니다. 해시되는 것은 translate를 포함해 보낸 요청이며, 모델이 만들어 낸 결과는 포함되지 않습니다. 따라서 응답을 받지 못한 발송을 같은 Idempotency-Key로 재시도하면 원래 결과가 재생됩니다. 이미 존재하는 메시지가 돌아오고, 두 번째 발송도 두 번째 번역도 없습니다. 대신 문구를 해시한다면 정직한 재시도마다 지문이 달라질 텐데, 그것이 바로 같은 메시지가 두 번 나가는 경로입니다.
  • 큐에 있거나 예약된 번역 메시지는 문구 변경에 대해 잠깁니다. 시각을 옮기거나 취소하세요. 내용을 바꾸는 일은 취소하고 다시 보내는 것을 뜻하며, 새 문구를 읽을 수 있는 사람 앞에서 해야 합니다.
  • 오른쪽에서 왼쪽으로 쓰는 대상 언어는 그 방향으로 생성됩니다. 번역문은 dir="rtl"로 감싸이고, 그 아래의 원문은 원문 나름의 방향을 유지합니다. 이 속성은 발신 위생 처리기를 통과하는데, 정확히 이 이유로 dir을 허용하기 때문입니다. 따라서 전송되는 메시지는 미리보기가 보여 준 방향을 그대로 갖습니다.
코드상태발생 조건
`invalid_parameter`422translate.totranslate.from이 특정할 수 없는 언어를 가리킵니다. 메시지는 허용되는 세 가지 형태를 알려 주고 GET /languages를 가리킵니다.
`unknown_language`422같은 실패를 한 단계 뒤에서, 스키마가 아니라 서비스가 잡은 경우입니다. translate.to에 대한 최후 방어선입니다.
`translation_too_long`422모델 호출의 입력이나 출력이 30,000자를 넘습니다. 잘라 내는 대신 거부합니다. 반쪽짜리 번역문에는 어디서 끊겼는지 보여 줄 이음매가 없고, 읽는 사람은 받은 그 반쪽을 근거로 행동하기 때문입니다.
`translation_not_configured`409워크스페이스에 AI 키가 없고 플랫폼 AI도 꺼져 있습니다. 재시도해도 똑같이 실패하므로 503이 아니라 409입니다. 아무것도 발송되지 않았습니다. 쓴 그대로 보낼 생각이었다면 translate 없이 보내세요.
`translation_failed`503제공자가 응답하지 않았거나, 쓸 수 없는 응답을 돌려주었습니다. 아무것도 발송되지 않았으며, 대체 수단으로 번역되지 않은 메시지를 내보내는 일은 절대 없습니다. 이 오류는 우리 쪽 문제이며 재시도할 가치가 있습니다.
`unknown_parameter`422translate 안에 인식할 수 없는 키가 있습니다. 요청의 나머지 부분과 마찬가지로 이것도 엄격한 객체입니다.

코드에서의 발송에는 번역을 먼저 읽어 볼 사람이 없습니다. POST /emails/translate는 같은 왕복을 한 단계 앞에서 멈춘 것으로, 사람에게 무엇을 보내려 하는지 보여 주기 위한 것입니다. 그런 다음 승인된 내용을 요청에 translate 없이 평범한 html/subject로 보내세요.