Ugrás a dokumentációra
API

E-mail küldése

POST /emails: egy üzenet, most vagy később.

POSTapi.openemail.uk/emails

A valódi hívást futtatja le a munkaterületén, a saját kulcsával.

A kérés

A from kötelező. A szerkesztővel ellentétben itt nincs tartalék feladó, mert az a tartalék a munkaterület alapértelmezett címe, és láthatatlanul változik, ahogy a címek jönnek-mennek.

MezőKötelezőMegjegyzések
fromigenPuszta cím vagy Name <addr>. Olyannak kell lennie, amellyel a kulcs küldhet.
toigenÖsszesen legfeljebb 50 címzett a to, a cc és a bcc mezőkben.
cc, bccnemA bcc címzettek soha nem szerepelnek névvel azokban a bájtokban, amelyeket bárki más megkap.
subjectnemAlapértelmezetten üres.
html, textaz egyikMindkettő is mehet. A HTML az, amit a címzettek látnak.
templateaz egyik{ id, version?, props?, slots? }. Tárolt törzs, azonosító vagy slug alapján. A html, a text vagy a draftId mellett elutasítjuk. Lásd a Küldés sablonnal részt.
replyTonemEgyetlen cím.
headersnemX-*, List-*, Reply-To, Precedence, Auto-Submitted, Importance, Priority, Feedback-Id.
attachmentsnem{ filename, content, contentType } base64 formában, összesen 5 MB, vagy { fileId }, amely a munkaterületen már meglévő fájlt nevez meg. 20 fájl.
attachmentDeliverynemmime, link vagy auto. Az auto linkeli a fájlokat, amint 2 MB fölé érnek egy aktív fájldomainnel rendelkező domainen. Alapértelmezetten a postafiók beállítása.
threadIdnemVálasz egy meglévő üzenetszálba.
draftIdnemMeglévő piszkozat küldése.
scheduledAtnemISO időpont vagy időtartam. Lásd az Ütemezés részt.
cancellableForSecondsnem0 és 900 másodperc közötti visszavonási ablak az azonnali küldésnél. A scheduledAt mellett elutasítjuk, mert az amúgy is visszavonható marad az elküldéséig. Lásd az Ütemezés részt.
signaturenemA false lehagyja az aláírást erről az üzenetről. Egyébként annak a címnek az aláírását viszi, amelyről küldik, vagyis a cím sajátját, vagy ha nincs, az Összes címhez beállítottat.
tagsnemLegfeljebb 10 saját címke. Visszaadjuk őket, de soha nem értelmezzük.
trackingnem{ opens?, clicks? }. Bármelyik felülírja a beállítást erre az üzenetre; ha egy mezőt kihagysz, az a fél visszaesik annak a címnek a beállítására, amelyről küldik, vagy az Összes címre, és bekapcsolt állapotú, hacsak valamelyik ki nem kapcsolta.
translatenem{ to, from?, subject?, includeOriginal? }. A címzett nyelvén küldi el. A kérés elfogadásakor oldódik fel, és a draftId mellett elutasítjuk.

Az ismeretlen mezőket elutasítjuk, nem figyelmen kívül hagyjuk, így egy elgépelt név most 422, nem később meglepetés. Azokat a fejléceket, amelyek kijátszanák a feladó engedélyezését (From, Sender, Bcc, Message-ID, Return-Path és mások), reserved_header hibával utasítjuk el.

A válasz

200, ha az üzenet már elment, 202, ha még történnie kell vele valaminek. A státuszkódra elágazó hívó mindkettőben helyesen jár el.

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}

Az id a tartós fogantyú, amit megtartasz, és ezen érkezik vissza egy kézbesítési esemény is, hiszen egy visszapattanási webhook emailId néven nevezi meg. A messageId az RFC 5322 Message-ID, és addig null, amíg a MIME nem létezik. Ne erre korrelálj: a küldő szolgáltatás kimenet közben átírja ezt a fejlécet, így az itteni érték egyetlen visszapattanási vagy kézbesítési jelentésben sem jelenik meg, és az illesztés rá soha nem sül el.

A címzett nyelvén

A translate valaki más nyelvén írja meg az üzenetet, mielőtt elmegy. A törzset, és ha ezt ki nem kapcsolod, a tárgyat is, a kérés ELFOGADÁSÁNAK pillanatában fordítjuk le, ugyanazzal a szabállyal, amelyet a template követ, és ugyanazokból az okokból teherviselő: az ütemezett üzenet azokat a szavakat viszi, amelyeket jóváhagytak, nem azt, amit egy modell kedden előállít, a le nem fordítható fordítás pedig elutasítja a küldést, mielőtt sor jönne létre. Semmit nem kézbesítünk olyan nyelven, amelyet a feladója nem választott.

translate

tostringkötelező
A nyelv, amelyen írni kell: BCP-47 kód (`de`), angol név („German”) vagy a nyelv saját neve („Deutsch”), 2 és 60 karakter között. Mindhármat a táblázatbeli kódra normalizáljuk, mielőtt bármi más történne, tehát egy kérésnek számítanak, ami azért fontos, mert az Idempotency-Key ujjlenyomatát a feldolgozott kérésen vesszük. Az aliasok is feloldódnak: a `zh-TW` `zh-Hant` lesz. Az, amelyik semmire nem oldódik fel, 422 a `translate.to` mezőn.
fromstring
Az, amelyen írtad, ugyanabban a három formában. Tisztán optimalizáció. Ha kihagyod, beolvassuk a törzset és kikövetkeztetjük a nyelvet, ami egy rövid modellhívásba kerül. Nagy forgalmú útvonalon érdemes megadni, és akkor is, ha a törzs főleg nevekből, számokból és linkekből áll: a felismerés inkább tartózkodik, mint találgat, a meghatározatlan forrás pedig semmibe nem kerül azon kívül, hogy az eredetid fölötti feliratban nem szerepel nyelv. Nem azonos a felső szintű `from` mezővel, amely egy cím.
subjectboolean
A tárgysor lefordítása is. Alapértelmezetten igaz; a false pontosan úgy küldi a tárgyat, ahogy megírtad.
includeOriginalboolean
Tedd oda azt, amit valójában írtál, a fordítás alá, elválasztó mögé, a címzett nyelvén feliratozva. Alapértelmezetten igaz, és érdemes bekapcsolva hagyni. Egyedül ez teszi lehetővé az olvasónak, hogy ellenőrizzen egy furcsán ható mondatot, ahelyett hogy egy olyan modellben kellene bíznia, amelynek kimenetét egyikőtök sem látja.
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  }}

A translation kiegészítő mező, és csak lefordított üzeneten jelenik meg: ezen a válaszon és a GET /emails/{id} válaszán, listasoron soha, mert a lista nem kéri le a tárolt kérést, így az ottani hallgatása egyik irányba sem mond semmit. Kódokat visz, nem teljes nyelvsorokat: arról szóló feljegyzés, mi történt, az endonim pedig a GET /languages válaszában él. A válaszon a subject a lefordított tárgy, így egy konzol soha nem listáz üzenetet olyan szöveg alatt, amelyet a címzett nem látott.

  • Működik a template mezővel, és ez a hasznos eset: a MEGJELENÍTETT kimenetet fordítjuk le, így egyetlen tárolt törzs minden nyelvet kiszolgál, amelyen az ügyfeleid olvasnak. A teljes dokumentumot megjelenítő sablont előbb szétszedjük: csak a <body> belseje jut el a modellhez, a doctype, a <style> blokkok és az @font-face szabályok pedig visszakerülnek a válasz köré. Ezért is a prózát méri a 30 000 karakteres korlát, nem a dokumentumot: a márkás stíluslapba csomagolt kétsoros üzenet kétsoros üzenet.
  • Egy sablonból egyedül a <title> marad lefordítatlanul, amelyet egyetlen levelezőkliens sem jelenít meg. A react-email <Preview> eleme a törzsbe rendereli magát, és a többivel együtt lefordul.
  • A draftId mellett elutasítjuk: 422 a translate mezőn, ezzel a szöveggel: „A draft is sent as it was written; translate a body or send a draft, not both”. A piszkozatot ember írta, és úgy megy el, ahogy hagyta.
  • Szándékosan nem része az idempotencia-ujjlenyomatnak. Az általad küldött kérést hasheljük, a translate mezővel együtt; azt, amit a modell előállított, nem. Így egy megválaszolatlan küldés újrapróbálása ugyanazzal az Idempotency-Key kulccsal visszajátssza az eredetit. A már létező üzenet jön vissza, második küldés és második fordítás nélkül. A szöveg hashelése ezzel szemben minden alkalommal más ujjlenyomatot adna egy becsületes újrapróbálkozásnak, és így megy ki kétszer ugyanaz az üzenet.
  • A sorban álló vagy ütemezett lefordított üzenet be van fagyasztva a szövegváltoztatás ellen. Helyezd át vagy vond vissza; a tartalmának megváltoztatása annyit tesz, hogy visszavonod és újraküldöd, olyasvalaki előtt, aki el tudja olvasni az új szöveget.
  • A jobbról balra író célnyelvet jobbról balra állítjuk elő: a fordítás dir="rtl" attribútumba csomagolva, alatta az eredetid a saját irányában. Az attribútum túléli a kimenő tisztítót, amely pontosan ezért engedélyezi a dir attribútumot, így a hálózatra kerülő üzenet azt az irányt viszi, amelyet az előnézet mutatott.
KódStátuszMikor
`invalid_parameter`422A translate.to vagy a translate.from olyan nyelvet nevez meg, amelyet nem tudunk elhelyezni. Az üzenet megmondja, melyik három forma elfogadott, és a GET /languages hívásra mutat.
`unknown_language`422Ugyanaz a hiba egy lépéssel később elkapva, a séma helyett a szolgáltatás által. Védőháló, a translate.to mezőn.
`translation_too_long`422Több mint 30 000 karakter a modellhívás bármelyik végén. Elutasítás, nem csonkolás: a fél lefordított üzeneten nincs varrat, amely megmutatná, hol állt meg, az olvasó pedig a kapott feléből cselekszik.
`translation_not_configured`409A munkaterületnek nincs AI kulcsa, és a platform AI ki van kapcsolva. 409, nem 503, mert az újrapróbálkozás ugyanígy bukna el. Semmit nem küldtünk el. Küldd translate nélkül, ha úgy akartad küldeni, ahogy megírtad.
`translation_failed`503A szolgáltató nem válaszolt, vagy használhatatlan választ adott. Semmit nem küldtünk el; az üzenetet soha nem tesszük ki tartalékként lefordítatlanul. Ez a mienk, és érdemes újrapróbálni.
`unknown_parameter`422Ismeretlen kulcs a translate objektumon belül, amely a kérés többi részéhez hasonlóan szigorú objektum.

A kódból indított küldésnél senki nem olvassa el előbb a fordítást. A POST /emails/translate ugyanaz a körút, egy lépéssel korábban megállítva, arra, hogy megmutasd valakinek, mit készül elküldeni. Utána azt küldd el, amit jóváhagytak, közönséges html/subject formában, a kérésen translate nélkül.