ارسال یک ایمیل
POST /emails: یک پیام، حالا یا بعداً.
فراخوانی واقعی را با کلید خودتان روی فضای کاری شما اجرا میکند.
درخواست
from الزامی است. برخلاف نگارشگر، فرستندهٔ جایگزینی در کار نیست، چون آن جایگزین نشانی پیشفرض فضای کاری است و با آمدن و رفتن نشانیها نامرئی عوض میشود.
| فیلد | الزامی | توضیحات |
|---|---|---|
| from | بله | یک نشانی خالی یا Name <addr>. باید یکی باشد که کلید اجازهٔ ارسال با آن را دارد. |
| to | بله | تا ۵۰ گیرنده روی to، cc و bcc روی هم. |
| cc, bcc | خیر | نام گیرندههای bcc هرگز در بایتهایی که دیگران دریافت میکنند نمیآید. |
| subject | خیر | پیشفرضش خالی است. |
| html, text | یکی از این دو | هر دو هم اشکالی ندارد. آنچه گیرندهها میبینند HTML است. |
| template | یکی از اینها | { id, version?, props?, slots? }. یک بدنهٔ ذخیرهشده، با شناسه یا با slug. در کنار html، text یا draftId رد میشود. به «ارسال با یک قالب» نگاه کنید. |
| replyTo | خیر | یک نشانی یگانه. |
| headers | خیر | X-*، List-*، Reply-To، Precedence، Auto-Submitted، Importance، Priority، Feedback-Id. |
| attachments | خیر | { filename, content, contentType } به شکل base64، در مجموع ۵ مگابایت، یا { fileId } که فایلی را نام میبرد که از پیش در فضای کاری است. ۲۰ فایل. |
| attachmentDelivery | خیر | mime، link یا auto. auto وقتی فایلها روی دامنهای با دامنهٔ فایلهای فعال از ۲ مگابایت بگذرند آنها را پیوند میکند. پیشفرضش تنظیم صندوق پستی است. |
| threadId | خیر | پاسخ در یک رشتهٔ موجود. |
| draftId | خیر | ارسال یک پیشنویس موجود. |
| scheduledAt | خیر | لحظه یا مدت به شکل ISO. به زمانبندی نگاه کنید. |
| cancellableForSeconds | خیر | پنجرهٔ لغوی از ۰ تا ۹۰۰ ثانیه روی یک ارسال فوری. در کنار scheduledAt رد میشود، چون آن تا لحظهٔ ارسال لغوشدنی میماند. به زمانبندی نگاه کنید. |
| signature | خیر | false امضا را از این پیام برمیدارد. در غیر این صورت پیام امضای نشانیای را که از آن فرستاده میشود با خود دارد، که یا امضای خودِ آن نشانی است یا امضایی که برای All addresses تنظیم شده. |
| tags | خیر | تا ۱۰ برچسب از آنِ خودتان. بازتاب داده میشوند و هرگز تفسیر نمیشوند. |
| tracking | خیر | { opens?, clicks? }. هرکدام تنظیم را برای این پیام بازنویسی میکند؛ فیلدی را جا بگذارید و آن نیمه به تنظیم نشانیای که از آن فرستاده میشود برمیگردد، وگرنه به All addresses، و روشن است مگر آنکه یکی از آن دو خاموشش کرده باشد. |
| translate | خیر | { to, from?, subject?, includeOriginal? }. پیام را به زبان گیرنده میفرستد. در لحظهٔ پذیرش درخواست حل میشود، و در کنار draftId رد میشود. |
فیلدهای ناشناخته بهجای نادیدهگرفتهشدن رد میشوند، پس نامی که غلط تایپ شده همین حالا 422 میگیرد بهجای آنکه بعداً غافلگیرتان کند. هدرهایی که مجوز فرستنده را از کار میاندازند (From، Sender، Bcc، Message-ID، Return-Path و دیگران) با reserved_header رد میشوند.
پاسخ
وقتی پیام از پیش رفته باشد 200، و وقتی هنوز باید چیزی بر سرش بیاید 202. فراخوانی که روی کد وضعیت شاخه میزند دربارهٔ هر دو درست میگوید.
{ "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 دستگیرهٔ پایداری است که نگه میدارید، و همان که یک رویداد تحویل روی آن برمیگردد، چون webhook یک bounce آن را emailId مینامد. messageId همان Message-ID مطابق RFC 5322 است و تا وقتی MIME وجود نداشته باشد null است. با آن همبستهسازی نکنید: سرویس ارسال آن هدر را در راه خروج بازنویسی میکند، پس مقدار اینجا در هیچ گزارش bounce یا تحویلی پیدا نمیشود و تطبیق روی آن هرگز شلیک نمیکند.
به زبان گیرنده
translate پیام را پیش از رفتنش به زبان کسی دیگر مینویسد. بدنه، و موضوع مگر آنکه آن را خاموش کنید، در همان لحظهای ترجمه میشود که درخواست پذیرفته میشود، که همان قاعدهای است که template از آن پیروی میکند و به همان دلایل باربر است: پیام زمانبندیشده واژههایی را با خود دارد که تأیید شدهاند، نه هر چیزی که یک مدل در روز سهشنبه تولید میکند، و ترجمهای که نتوانسته تولید شود ارسال را پیش از آنکه ردیفی وجود داشته باشد رد میکند. هیچ چیزی به زبانی که فرستندهاش انتخاب نکرده تحویل نمیشود.
translate
tostringالزامی- زبانی که باید به آن نوشته شود: یک کد BCP-47 (`de`)، یک نام انگلیسی («German») یا نام خودِ زبان («Deutsch»)، ۲ تا ۶۰ نویسه. هر سه پیش از هر چیز دیگری به کد جدول عادیسازی میشوند، پس یک درخواستاند، و این مهم است چون اثرانگشت Idempotency-Key روی درخواستِ تجزیهشده گرفته میشود. نامهای دیگر هم حل میشوند: `zh-TW` به `zh-Hant` بدل میشود. آنچه به هیچ چیز حل نشود روی `translate.to` یک 422 است.
fromstring- زبانی که پیام را به آن نوشتهاید، در هر یک از همان سه شکل. صرفاً یک بهینهسازی است. اگر جا بگذاریدش، بدنه خوانده میشود و زبان درمیآید، که هزینهاش یک فراخوانی کوتاه مدل است. روی مسیری پرحجم ارزش گفتن دارد، و وقتی بدنه بیشتر نام و عدد و پیوند است هم ارزش گفتن دارد: تشخیص بهجای حدسزدن خودداری میکند، و مبدأ نامعلوم چیزی جز نام زبان در زیرنویسِ بالای متن اصلی شما برایتان هزینه ندارد. این همان `from` سطح بالا نیست، که یک نشانی است.
subjectboolean- خط موضوع را هم ترجمه کن. پیشفرضش true است؛ false موضوع را دقیقاً همانطور که نوشتهاید میفرستد.
includeOriginalboolean- آنچه را واقعاً نوشتهاید زیر ترجمه بگذار، پشت یک جداکننده و با زیرنویسی به زبان گیرنده. پیشفرضش true است و ارزش روشنماندن دارد. تنها چیزی است که به کسی که میخواند اجازه میدهد جملهای را که عجیب مینشیند وارسی کند، بهجای آنکه از او خواسته شود به مدلی اعتماد کند که هیچکدامتان خروجیاش را نمیبینید.
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" } }'{ "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}، و هرگز روی ردیف فهرست، چون فهرست درخواست ذخیرهشده را نمیگیرد و سکوتش آنجا هیچ چیزی در هیچ جهتی نمیگوید. بهجای ردیفهای کامل زبان، کد با خود دارد: سندِ کاری است که انجام شده، و GET /languages جایی است که نام بومی زندگی میکند. subject روی پاسخ همان موضوع ترجمهشده است، پس یک کنسول هرگز پیامی را زیر رشتهای فهرست نمیکند که گیرنده هرگز ندیده است.
- با
templateکار میکند، و همین حالت سودمند است: آنچه ترجمه میشود خروجی رندرشده است، پس یک بدنهٔ ذخیرهشده به هر زبانی که مشتریانتان میخوانند خدمت میکند. قالبی که یک سند کامل رندر میکند اول از هم باز میشود: تنها آنچه درون<body>است به مدل میرسد، و doctype، بلوکهای<style>و قاعدههای@font-faceدوباره گرد پاسخ گذاشته میشوند. به همین دلیل هم هست که محدودیت ۳۰٬۰۰۰ نویسهای متن را اندازه میگیرد نه سند را: پیام دوخطیای که در یک شیوهنامهٔ برندشده پیچیده شده، یک پیام دوخطی است. - تنها بخشی از یک قالب که ترجمه نمیشود
<title>آن است، که هیچ کلاینت ایمیلی نشانش نمیدهد. یک<Preview>در react-email درون بدنه رندر میشود و با بقیه ترجمه میشود. - در کنار
draftIdرد میشود: یک 422 رویtranslate، با این متن: «پیشنویس همانطور که نوشته شده فرستاده میشود؛ یا بدنهای را ترجمه کنید یا پیشنویسی را بفرستید، نه هر دو». پیشنویس را یک آدم نوشته و همانطور که رهایش کرده فرستاده میشود. - عمداً بخشی از اثرانگشت ایدمپوتنسی نیست. آنچه هش میشود درخواستی است که فرستادهاید، شاملِ
translate؛ آنچه مدل تولید کرده نه. پس تلاش دوباره برای ارسالی که پاسخ نگرفته با همانIdempotency-Keyپاسخ اصلی را بازپخش میکند. پیامی که از پیش هست برمیگردد، بدون ارسال دوم و بدون ترجمهٔ دوم. هشکردن خودِ واژهها بهجای این، یک تلاش دوبارهٔ صادقانه را هر بار با اثرانگشتی متفاوت میساخت، و همین است که یک پیام را دو بار بیرون میفرستد. - پیام ترجمهشدهای که در صف یا زمانبندیشده است در برابر تغییر واژهها منجمد میشود. جابهجایش کنید یا لغوش کنید؛ عوضکردن آنچه میگوید یعنی لغو و ارسال دوباره، پیش روی کسی که بتواند واژههای تازه را بخواند.
- مقصدی که راستبهچپ است راستبهچپ تولید میشود: ترجمه در
dir="rtl"پیچیده میشود و متن اصلی شما زیر آن با جهت خودش میآید. این ویژگی از پالایشگر خروجی جان سالم به در میبرد، که دقیقاً به همین دلیلdirرا مجاز میداند، پس پیامی که روی سیم میرود همان جهتی را با خود دارد که پیشنمایش نشان داد.
| کد | وضعیت | چه زمانی |
|---|---|---|
| `invalid_parameter` | 422 | translate.to یا translate.from زبانی را نام میبرد که نمیتوانیم جایش بدهیم. پیام میگوید کدام سه شکل پذیرفته میشوند و به GET /languages اشاره میکند. |
| `unknown_language` | 422 | همان شکست، یک گام دیرتر گرفته شده، به دست سرویس بهجای schema. یک پشتیبان، روی translate.to. |
| `translation_too_long` | 422 | بیش از ۳۰٬۰۰۰ نویسه در هر یک از دو سرِ فراخوانی مدل. ردکردن بهجای بریدن: نیمی از یک پیام ترجمهشده هیچ درزی ندارد که نشان دهد کجا ایستاده، و کسی که میخواند بر پایهٔ همان نیمی که گرفته عمل میکند. |
| `translation_not_configured` | 409 | فضای کاری کلید هوش مصنوعی ندارد و هوش مصنوعی پلتفرم خاموش است. یک 409 بهجای 503، چون تلاش دوباره هم دقیقاً همانطور شکست میخورد. چیزی فرستاده نشد. اگر میخواستید پیام را همانطور که نوشتهاید بفرستید، بدون translate بفرستید. |
| `translation_failed` | 503 | ارائهدهنده پاسخ نداد، یا چیزی داد که بهکار نمیآمد. چیزی فرستاده نشد؛ پیام هرگز بهعنوان جایگزین، ترجمهنشده پست نمیشود. این یکی از آنِ ماست و ارزش تلاش دوباره دارد. |
| `unknown_parameter` | 422 | کلیدی ناشناخته درون translate، که مانند بقیهٔ درخواست یک شیء سختگیر است. |
در ارسالی که از کد میآید کسی نیست که اول ترجمه را بخواند. POST /emails/translate همان رفتوبرگشت است که یک گام زودتر متوقف شده، برای نشاندادن به کسی که میخواهد چیزی بفرستد. سپس آنچه را او تأیید کرده بهعنوان یک html/subject معمولی بفرستید، بدون آنکه اصلاً translate روی درخواست باشد.