ارسال یک ایمیل
`emails.send`: یک پیام، حالا یا بعداً.
emails.send
const email = await openemail.emails.send({ from: { email: '[email protected]', name: 'Acme Billing' }, to: ['[email protected]', 'Grace <[email protected]>'], cc: '[email protected]', bcc: [{ email: '[email protected]' }], replyTo: '[email protected]', subject: 'Your September invoice', html: '<p>Invoice attached.</p>', text: 'Invoice attached.', headers: { 'X-Campaign': 'invoices' }, attachments: [{ filename: 'invoice.pdf', content: pdfBytes }], threadId: 'thread_…', scheduledAt: 'PT1H', tags: { order: '4021' }, tracking: { opens: true, clicks: true },})to، cc و bcc یک گیرنده یا چند گیرنده میگیرند، و اگر یکی تنها بدهید برایتان پیچیده میشود. هرکدام میتواند نشانی خام، Name <addr@host> یا { email, name } باشد.
پارامترها
fromRecipientInputالزامی- فرستنده. یک نشانی خام، `Name <addr@host>` یا یک object. باید نشانیای باشد که این کلید اجازهٔ ارسال با آن را دارد. هیچ فرستندهٔ جایگزینی وجود ندارد، چون جایگزین همان نشانی پیشفرض فضای کاری میشد، که با آمدن و رفتن نشانیها عوض میشود.
toRecipientInput | RecipientInput[]الزامی- یک گیرنده یا چند گیرنده؛ اگر یکی تنها بدهید برایتان پیچیده میشود. حداکثر 50 نشانی روی هم در to، cc و bcc.
ccRecipientInput | RecipientInput[]- به سقف 50 گیرنده شمرده میشود.
bccRecipientInput | RecipientInput[]- هرگز در بایتهایی که دیگران دریافت میکنند نام برده نمیشود، چون به ازای هر گیرنده یک پاکت منتقل میشود.
replyToRecipientInput- یک نشانی تکی، که به شکل هدر Reply-To فرستاده میشود.
subjectstring- حداکثر 998 نویسه، همان حد طول خط RFC 5322. پیشفرض: خالی.
htmlstring- یکی از html، text، draftId یا template الزامی است. وقتی هر دو html و text داده شوند، آنچه گیرندگان میبینند HTML است.
textstring- بخش متن ساده.
template{ id, version?, props?, slots? }- یک قالب ذخیرهشده را سمت سرور رندر میکند. `version` آن را سنجاق میکند؛ ننویسیدش تا هرچه هنگام پذیرش درخواست منتشر شده باشد به کار رود. prop ناشناخته یا نیامده، بهجای جای خالی در پیام، یک 422 است.
draftIdstring- یک پیشنویس ذخیرهشده را زیر این پاکت بفرستید.
headersRecord<string, string>- `X-*`، `List-*`، Reply-To، Precedence، Auto-Submitted، Importance، Priority و Feedback-Id. هر چیزی که خودِ حملونقل تنظیم میکند بهجای حذف بیسروصدا رد میشود.
attachmentsAttachmentInput[]- `{ filename, content, contentType? }`، یا `{ fileId }` که فایلی را نام میبرد که از پیش در workspace هست. برای content بایت بدهید تا برایتان با base64 رمزگذاری شود. 20 فایل، با سقف مجموع 5 MB برای فایلهای درونخطی پس از رمزگشایی. فایل ذخیرهشده میتواند بزرگتر باشد و به شکل پیوند دانلود میرود.
attachmentDeliveryAttachmentDeliveryMode- `mime`، `link` یا `auto`. `auto` فایلها را وقتی روی دامنهای با files domain فعال از 2 MB بگذرند به شکل پیوند دانلود میبرد و در غیر این صورت درون پیام. اگر ننویسید، تنظیم صندوق اعمال میشود، که پیشفرضش `auto` است.
threadIdstring- پاسخدادن درون یک thread موجود. حملونقل In-Reply-To و References را مینویسد.
scheduledAtDate | string- یک Date، یک لحظهٔ ISO-8601، یا مدتی مانند `PT1H`. تا یک سال بعد، هرگز در گذشته. نمیشود با cancellableForSeconds ترکیبش کرد.
cancellableForSecondsnumber- 0 تا 900. پنجرهٔ لغو روی یک ارسال فوری: همان سازوکار لغوِ composer، که بهجای hardcode شدن در دسترس گذاشته شده است.
tagsRecord<string, string>- تا 10 برچسب، که بازتاب داده میشوند و قابل فیلترند. هرگز تفسیر نمیشوند.
signatureboolean- اینکه آیا این پیام امضای نشانیای را که از آن فرستاده میشود حمل کند یا نه، یعنی امضای خودِ آن نشانی وگرنه امضای تنظیمشده برای All addresses. پیشفرض true است، چون امضا به نشانی تعلق دارد نه به هر کلاینتی که پیام را فرستاده. برای نامهای که برنامهای از طرف کسی میفرستد — رسید، بازنشانی گذرواژه یا خلاصهٔ دورهای — که هیچکدام امضای یک آدم را زیر خود نمیخواهند، `false` بگذارید.
tracking{ opens?, clicks? }- اینکه آیا برای این پیام pixel باز شدن افزوده و پیوندها بازنویسی شوند یا نه. روشن است مگر مالک workspace ردیابی را برای نشانیای که پیام از آن میرود یا برای All addresses خاموش کرده باشد، و هر یک از این فیلدها که اینجا بیاید تکلیف همان یک پیام را، هرطور که نشانی تنظیم شده باشد، روشن میکند.
translate{ to, from?, subject?, includeOriginal? }- آن را به زبان گیرنده بفرستید. `to` یک کد، یک نام انگلیسی یا نام خودِ زبان میگیرد؛ `subject` و `includeOriginal` هر دو پیشفرض true دارند. هنگام پذیرفتهشدن درخواست حل میشود، پس پیام زمانبندیشده همان کلماتی را میبرد که تأیید شدهاند. در کنار `draftId` رد میشود.
پاسخ
idstring- شناسهٔ ارسال، `msg_…`. برای `get`، `cancel`، `reschedule` و `getTracking` از آن استفاده کنید.
statusEmailStatus- queued، scheduled، sending، sent، partial، cancelled یا failed. بهجای این واقعیت که promise حل شد، همین را بخوانید. `partial` وضعیتی از آنِ خودش است: بعضی گیرندگان آن را دارند و نمیشود پس گرفت، پس تلاش دوباره اشتباه است و گزارش شکست دروغ.
mode'live' | 'test'- کدام نوع کلید آن را فرستاده. ارسال در حالت test ثبت میشود و هرگز منتقل نمیشود.
fromstring- نشانیای که واقعاً مجاز شمرده و روی سیم گذاشته شد، که همیشه همان نشانی درخواستشده نیست.
subjectstring | null- همانطور که فرستاده شد.
messageIdstring | null- همان Message-ID مربوط به RFC 5322. تا وقتی MIME وجود نداشته باشد null است. سرویس ارسال هدر را در مسیر خروج بازنویسی میکند، پس هیچ bounce یا گزارش تحویلی این مقدار را حمل نمیکند. چیزی که رویداد با آن برمیگردد `id` است.
threadIdstring | null- thread ای که در آن نشست.
transportstring | null- پیام چگونه رفت. تا پیش از ارسال null است.
attemptsnumber- چند بار ارسال تلاش شده است.
lastErrorstring | null- چرا آخرین تلاش شکست خورد، عیناً.
scheduledAtstring | null- لحظهٔ ISO که باید برود.
cancellableUntilstring | null- تا وقتی اکنون پیش از این لحظه است، لغو هنوز کار میکند.
sentAtstring | null- لحظهٔ ISO که رفت.
tagsRecord<string, string>- آنچه فرستادید، بازتابدادهشده.
sourceEmailSource- composer، api، mcp، ai یا queue: کدام سطح درخواست داده است. `api` همین کلاینت است.
createdAtstring- لحظهٔ ISO که رکورد نوشته شد.
replayedboolean- وقتی true است که یک Idempotency-Key با ارسالی که از پیش وجود داشته مطابقت کرده باشد. چیز تازهای فرستاده نشده، و این همان پیام اصلی است.
translationEmailTranslationResource | undefined- فقط روی پیامی حاضر است که ترجمه شده، و تنها جایی که کل درخواست ذخیرهشده حمل میشود: همین پاسخ و `get`. `{ language, languageName, detectedSourceLanguage, subject, includeOriginal }`، همه به شکل کد نه ردیف زبان. ردیف فهرست هرگز آن را ندارد، پس غیابش آنجا به هیچ سمتی چیزی نمیگوید.
به زبان گیرنده
translate پیام را پیش از رفتنش به زبان کسی دیگر مینویسد. بدنه — و موضوع، مگر آن را خاموش کنید — وقتی API درخواست را میپذیرد ترجمه میشود، و آنچه بیرون آمد همان است که بیرون میرود: ترجمهای که نشود تولیدش کرد، بهجای فرستادن پیام به زبانی که نوشتهاید، ارسال را رد میکند.
const email = await openemail.emails.send({ from: '[email protected]', to: '[email protected]', subject: 'Your September invoice', html: '<p>Invoice attached. Payment is due on the 14th.</p>', translate: { to: 'de' },}) console.log(email.translation)// { language: 'de', languageName: 'German', detectedSourceLanguage: 'en', subject: true, includeOriginal: true }کسی پیش از رفتنش آن را نخواند. emails.translate همان رفتوبرگشت است که یک گام زودتر متوقف شده. آن را به یک آدم نشان دهید، بگذارید تغییرش دهد، و بعد آنچه را تأیید کرده بدون هیچ translate ای روی فراخوانی بفرستید. دادن دوبارهٔ آن، متن را بار دوم ترجمه میکرد و ویرایشهایش را دور میریخت.
const preview = await openemail.emails.translate({ subject: 'Your September invoice', html: '<p>Invoice attached. Payment is due on the 14th.</p>', to: 'de',}) console.log(preview.language.native, preview.detectedSourceLanguage) const approved = await showToSomebody(preview) await openemail.emails.send({ from: '[email protected]', to: '[email protected]', subject: approved.subject, html: approved.html,})import { LANGUAGES, isRtlLanguage, languageByCode, openemail, resolveLanguage } from '@openemail/sdk' LANGUAGES.length // 200 const current = await openemail.languages.list() resolveLanguage('Deutsch')?.code // 'de'resolveLanguage('zh-TW')?.code // 'zh-Hant'languageByCode('DE')?.native // 'Deutsch'isRtlLanguage('ar') // trueاین جدول در بسته هست، به ترتیب picker، پس میشود یک picker را پیش از نخستین درخواست پر کرد. languages.list() به همان ردیفها از روی سیم، به شکل آرایهای ساده، حل میشود، برای فراخوانندهای که ردیفهای کنونی را به ردیفهایی که این نسخه با آنها عرضه شده ترجیح میدهد. resolveLanguage یک کد، یک نام انگلیسی، یک نام بومی یا یک نام مستعار میگیرد (zh-TW نام مستعار کدی است که دیگر فهرست نمیشود)، languageByCode کد را دقیقاً و بدون حساسیت به بزرگی و کوچکی حروف تطبیق میدهد، و شانزده ردیف از راست به چپاند. native، label و code را با هم جستوجو کنید، native را اول نشان دهید، و کد را ذخیره کنید.
emails.translate بهطور خودکار دوباره تلاش نمیشود. فراخوانی مدل خرج میکند و چیزی نمینویسد، پس چیزی برای idempotent کردن نیست و تلاش دوباره پس از درخواستی بیپاسخ فقط همان پاسخ را دو بار میخرد.
- زبانی که به هیچچیز حل نشود یک
validation_errorرویtranslate.toاست، پیش از آنکه چیزی فرستاده شود. translation_too_longبرای بیش از 30,000 نویسه،translation_not_configuredوقتی نصب هیچ AI پیکربندیشدهای ندارد،translation_failedوقتی ارائهدهنده پاسخ نداده است. هیچکدام بهعنوان جایگزین، پیام را ترجمهنشده نمیفرستند.- با
templateکار میکند: آنچه ترجمه میشود خروجیِ RENDER شده است، پس یک بدنهٔ ذخیرهشده به هر زبانی که مشتریانتان میخوانند خدمت میکند. قالبی که یک سند کامل رندر میکند، doctype، بلوکهای<style>و قاعدههای@font-faceخود را نگه میدارد: فقط بدنه به مدل میرود و بقیه دوباره دورش گذاشته میشود.<title>آن دستنخورده میماند، که بههرحال چیزی نمایشش نمیدهد. - تلاش دوباره هزینهٔ اضافه ندارد. ترجمه بخشی از اثرانگشت idempotency نیست (خودِ درخواست هست، با
translateو همه)، پس بازفرستادن یک ارسال بیپاسخ با همانIdempotency-Keyپیامی را که از پیش وجود دارد بازپخش میکند، نه اینکه بار دوم ترجمه و ارسال کند. - پیام ترجمهشدهای که queued یا scheduled باشد در برابر تغییر واژهها منجمد است.
emails.rescheduleهنوز جابهجایش میکند؛ تغییر آنچه میگوید یعنی لغو و ارسال دوباره.
پیوستها
content روی سیم base64 است. بایت بدهید تا برایتان رمزگذاری شود.
attachments: [ { filename: 'invoice.pdf', content: pdfBytes, contentType: 'application/pdf' },]اگر جای دیگری لازمش داشتید، toBase64 صادر شده است. تکهتکه کار میکند، کاری که btoa(String.fromCharCode(...bytes)) نمیکند. آن یکی روی هر چیزی بیش از حدود 100 kB شکست میخورد، و روی فایل واقعی شکست میخورد نه روی فایلی که با آن آزمایش کردهاید.