ارسال یک ایمیل
`emails.send`: یک پیام، حالا یا بعداً.
emails.send
email = client.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: Pathname("invoice.pdf")}], threadId: "CAHk7pQ2x9LmZ4-mail.example.com", scheduledAt: "PT1H", tags: {order: "4021"}, tracking: {opens: true, clicks: true}) puts email[:id], email[:status]to، cc و bcc یک گیرنده یا یک Array از گیرندگان میگیرند، و اگر یکی تنها بدهید برایتان در Array پیچیده میشود. هرکدام میتواند نشانی خام، Name <addr@host> یا یک Hash با email و name باشد.
پیام بهصورت آرگومانهای کلیدواژهای یا بهصورت یک Hash داده میشود. آرگومانهای کلیدواژهای که کنار یک Hash بیایند در آن ادغام میشوند و جایی که هر دو یک فیلد را نام ببرند مقدماند، پس client.emails.send(message, subject: "Re: your invoice") یک فیلد از پیامی را که پیشتر ساختهاید تغییر میدهد. کلیدها نامهای API را نگه میدارند، و به همین دلیل replyTo و scheduledAt به شکل camelCase میمانند، در حالی که idempotency_key: و api_key: گزینههای فراخوانیاند و هرگز بخشی از پیام نیستند.
پارامترها
fromString or Hashالزامی- فرستنده. یک نشانی خام، `Name <addr@host>` یا یک Hash با `email` و `name`. باید نشانیای باشد که این کلید اجازهٔ ارسال با آن را دارد، وگرنه فراخوانی یک 403 `from_address_forbidden` را raise میکند. هیچ فرستندهٔ جایگزینی وجود ندارد، پس هر ارسال همیشه نشانیای را که از آن فرستاده میشود نام میبرد.
toString, Hash or Arrayالزامی- یک گیرنده یا یک Array از گیرندگان، و اگر یکی تنها بدهید برایتان در Array پیچیده میشود. حداکثر 50 نشانی روی هم در `to`، `cc` و `bcc`، و بیشتر از آن یک 422 `too_many_recipients` است.
ccString, Hash or Array- به سقف 50 گیرنده شمرده میشود.
bccString, Hash or Array- هرگز در بایتهایی که دیگران دریافت میکنند نام برده نمیشود، چون به ازای هر گیرنده یک پاکت منتقل میشود. در شمار همان 50 هم حساب میشود.
replyToString or Hash- یک نشانی تکی، که به شکل هدر Reply-To فرستاده میشود.
subjectString- حداکثر 998 نویسه، همان حد طول خط RFC 5322. پیشفرض خالی است، و موضوع خالی به موضوع قالب یا پیشنویس بازمیگردد.
htmlString- یکی از `html`، `text`، `draftId` یا `template` الزامی است. وقتی هر دو `html` و `text` داده شوند، آنچه گیرندگان میبینند HTML است. حداکثر 1,000,000 نویسه.
textString- بخش متن ساده، حداکثر 1,000,000 نویسه.
templateHash- یک قالب ذخیرهشده را سمت سرور رندر میکند: یک Hash با `id`، که شناسه یا slug میگیرد، و `version` اختیاری (یک Integer)، `props` و `slots`. `version` یک نسخه را سنجاق میکند. آن را ننویسید تا هرچه هنگام پذیرش درخواست منتشر شده باشد به کار رود. prop ناشناخته یا نیامده، بهجای جای خالی در پیام، یک 422 است.
draftIdString- یک پیشنویس ذخیرهشده را همانطور که نوشته شده، زیر این پاکت بفرستید. نمیتوان آن را با `template` یا `translate` ترکیب کرد.
headersHash- نام سرآیند به مقدار String، محدود به `X-*`، `List-*`، Reply-To، Precedence، Auto-Submitted، Importance، Priority و Feedback-ID. هر چیزی که خودِ لایهٔ انتقال تنظیم میکند، بهجای حذف بیسروصدا، با یک 422 `reserved_header` رد میشود.
attachmentsArray<Hash>- هرکدام یک Hash با `filename`، `content` و `contentType` اختیاری، یا یک Hash فقط با `fileId` که فایلی را نام میبرد که از پیش در فضای کاری هست، مثلاً فایلی از `files.upload`. برای `content` بایت بدهید تا برایتان با base64 رمزگذاری شود. 20 فایل، با سقف مجموع 5 MB برای فایلهای درونخطی پس از رمزگشایی. فایل ذخیرهشده میتواند بزرگتر باشد و به شکل پیوند دانلود میرود.
attachmentDeliveryString- `mime`، `link` یا `auto`. `auto` فایلها را وقتی روی دامنهای با files domain فعال از 2 MB بگذرند به شکل پیوند دانلود میبرد و در غیر این صورت درون پیام. اگر ننویسید، تنظیم صندوق اعمال میشود، که پیشفرضش `auto` است.
threadIdString- پاسخدادن درون یک thread موجود. حملونقل In-Reply-To و References را مینویسد.
scheduledAtTime, DateTime or String- یک Time یا DateTime که بهصورت یک لحظهٔ ISO 8601 با UTC فرستاده میشود، یک لحظهٔ ISO 8601 بهصورت String، یا مدتی مانند `PT1H`. تا یک سال بعد، هرگز در گذشته. نمیتوان آن را با `cancellableForSeconds` ترکیب کرد. یک Date در Ruby بهصورت تاریخ خالی فرستاده میشود که API آن را نیمهشب UTC همان روز میخواند، پس وقتی ساعت مهم است یک Time بدهید.
cancellableForSecondsInteger- 0 تا 900. پنجرهٔ لغو روی یک ارسال فوری: همان سازوکار لغوِ composer، که بهجای hardcode شدن در دسترس گذاشته شده است.
tagsHash- حداکثر 10 برچسب، با کلیدهای 1 تا 64 نویسه از حروف، ارقام، `_` یا `-` و مقدارهای String تا 256 نویسه. در هر خواندن همانطور بازگردانده میشوند و هرگز تفسیر نمیشوند.
signatureBoolean- اینکه این پیام امضای نشانی فرستنده را داشته باشد یا نه: امضای خودِ آن نشانی، وگرنه امضای catch-all برای نشانیای که catch-all دریافت کرده، وگرنه پانویس OpenEmail، مگر اینکه آن نشانی خاموشش کرده باشد. اگر مشخص نشود، بدنهٔ `html` دقیقاً همانطور که نوشته شده و بدون امضا میرود و بدنهٔ فقط `text` آن را دارد. برای نامهای که برنامهای از طرف کسی میفرستد، مثل رسید، بازنشانی گذرواژه یا خلاصه، `false` بگذارید، چون هیچکدام امضای یک شخص را زیر خود نمیخواهند. ارسالهای قالبی و ارسالهای رمزگذاریشده هرگز امضا ندارند.
trackingHash- یک Hash با `opens` و `clicks` بولی و اختیاری: اینکه آیا برای این پیام pixel باز شدن افزوده و پیوندها بازنویسی شوند یا نه. خاموش است مگر ردیابی برای نشانیای که پیام از آن میرود (یا catch-allی که آن را گرفته) روشن شده باشد، و هر یک از این دو کلید که اینجا بیاید تکلیف همان یک پیام را، هرطور که نشانی تنظیم شده باشد، روشن میکند.
translateHash- آن را به زبان گیرنده بفرستید: یک Hash با `to` و `from`، `subject` و `includeOriginal` اختیاری. `to` یک کد، یک نام انگلیسی یا نام خودِ زبان میگیرد، و `subject` و `includeOriginal` هر دو پیشفرض true دارند. هنگام پذیرفتهشدن درخواست تعیین میشود، پس پیام زمانبندیشده همان کلماتی را میبرد که تأیید شدهاند. در کنار `draftId` رد میشود.
idempotency_keyString- کلید خودتان برای این ارسال، 1 تا 255 نویسه از حروف، ارقام، `_`، `.`، `:` یا `-`. بدون آن، کلاینت برای هر فراخوانی کلیدی تولید میکند، پس تلاشهای دوبارهٔ خودش هرگز دو بار نمیفرستند، و با آن، ارسالی که در فرایندی دیگر دوباره اجرا شود بهجای تکرار، بازپخش میشود.
api_keyString- بهجای کلید کلاینت با این کلید میفرستد، برای فرایندی که از طرف چند فضای کاری ارسال میکند.
پاسخ
یک Hash با کلیدهای Symbol، پس email[:status] وضعیت را میخواند.
idString- شناسهٔ ارسال، `msg_` و به دنبالش 24 نویسهٔ hex. برای `get`، `cancel`، `reschedule` و `get_tracking` از آن استفاده کنید.
statusString- queued، scheduled، sending، sent، partial، bounced، cancelled یا failed. بهجای این واقعیت که فراخوانی بازگشت، همین را بخوانید: ارسال فوری درون همان درخواست روانه میشود و معمولاً با `sent`، `partial` یا `failed` برمیگردد، و ارسالی که نگه داشته شده با `queued` یا `scheduled` برمیگردد. `partial` وضعیتی از آنِ خودش است: بعضی گیرندگان آن را دریافت کردهاند و نمیشود پس گرفت، پس تلاش دوباره اشتباه است و گزارش شکست دروغ.
modeString- `live` یا `test`: کدام نوع کلید آن را فرستاده. ارسال در حالت test ثبت میشود و هرگز منتقل نمیشود. وضعیتش `sent` است و `transport` برابر `test`، پس روی پاسخ assert کنید نه روی یک صندوق ورودی.
fromString- نشانیای که واقعاً مجاز شمرده و روی سیم گذاشته شد، که همیشه همان نشانی درخواستشده نیست.
subjectString or nil- همانطور که فرستاده شد.
messageIdString or nil- همان Message-ID مربوط به RFC 5322. تا وقتی MIME وجود نداشته باشد nil است. سرویس ارسال سرآیند را در مسیر خروج بازنویسی میکند، پس هیچ bounce یا گزارش تحویلی این مقدار را حمل نمیکند. چیزی که رویداد با آن برمیگردد `id` است.
threadIdString or nil- thread ای که در آن نشست.
transportString or nil- پیام چگونه رفت. تا پیش از ارسال nil است.
attemptsInteger- چند بار ارسال تلاش شده است.
lastErrorString or nil- چرا آخرین تلاش شکست خورد، عیناً.
scheduledAtString or nil- لحظهٔ ISO 8601 که قرار است برود.
cancellableUntilString or nil- تا وقتی اکنون پیش از این لحظه است، `cancel` هنوز کار میکند.
sentAtString or nil- لحظهٔ ISO 8601 که رفت.
tagsHash- آنچه فرستادید، بازتابدادهشده.
sourceString- composer، api، mcp، ai یا queue: کدام سطح درخواست داده است. `api` همین کلاینت است.
createdAtString- لحظهٔ ISO 8601 که رکورد نوشته شد.
replayedBoolean- وقتی true است که یک Idempotency-Key با ارسالی که از پیش وجود داشته مطابقت کرده باشد. چیز تازهای فرستاده نشده، و این همان پیام اصلی در وضعیت کنونیاش است.
translationHash- فقط روی پیامی حاضر است که ترجمه شده، و تنها جایی که کل درخواست ذخیرهشده حمل میشود: همین پاسخ و `get`. شامل `language`، `languageName`، `detectedSourceLanguage`، `subject` و `includeOriginal` است، به شکل کد نه ردیف کامل زبان. ردیف فهرست هرگز آن را ندارد، پس غیابش آنجا به هیچ سمتی چیزی نمیگوید.
به زبان گیرنده
translate پیام را پیش از رفتنش به زبان کسی دیگر مینویسد. بدنه (و موضوع، مگر آن را خاموش کنید) وقتی API درخواست را میپذیرد ترجمه میشود، و آنچه بیرون آمد همان است که بیرون میرود: ترجمهای که نشود تولیدش کرد، بهجای فرستادن پیام به زبانی که نوشتهاید، ارسال را رد میکند.
email = client.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"}) p email[:translation]آنگاه email[:translation] این را میخواند: {language: "de", languageName: "German", detectedSourceLanguage: "en", subject: true, includeOriginal: true}.
کسی پیش از رفتنش آن را نخواند. emails.translate همان رفتوبرگشت است که یک گام زودتر متوقف شده. آن را به یک آدم نشان دهید، بگذارید تغییرش دهد، و بعد آنچه را تأیید کرده بدون هیچ translateای روی فراخوانی بفرستید. دادن دوبارهٔ آن، متن را بار دوم ترجمه میکرد و ویرایشهایش را دور میریخت.
preview = client.emails.translate( subject: "Your September invoice", html: "<p>Invoice attached. Payment is due on the 14th.</p>", to: "de") puts preview.dig(:language, :native), preview[:subject], preview[:html]print "Send it as it is? [y/N] " if $stdin.gets.to_s.strip.casecmp?("y") client.emails.send( from: "[email protected]", to: "[email protected]", subject: preview[:subject], html: preview[:html] )endp OpenEmail::LANGUAGES.size current = client.languages.listp current.size p OpenEmail.resolve_language("Deutsch")&.fetch(:code)p OpenEmail.resolve_language("zh-TW")&.fetch(:code)p OpenEmail.language_by_code("DE")&.fetch(:native)p OpenEmail.rtl_language?("ar")این خطها 200 را چاپ میکنند، یعنی ردیفهایی که این نسخه با آنها عرضه میشود، سپس تعدادی که API اکنون دارد، سپس "de"، "zh-Hant"، "Deutsch" و true. این جدول به ترتیب picker، به شکل OpenEmail::LANGUAGES در بسته هست، یک Array منجمد از Hashهایی با code، label، native، flag و rtl، پس میشود یک picker را پیش از نخستین درخواست پر کرد. languages.list همان ردیفها را از روی سیم به شکل یک Array ساده برمیگرداند، برای فراخوانندهای که ردیفهای کنونی را به ردیفهایی که این نسخه با آنها عرضه شده ترجیح میدهد. OpenEmail.resolve_language یک کد، یک نام انگلیسی، یک نام بومی یا یک نام مستعار میگیرد (zh-TW نام مستعار کدی است که دیگر فهرست نمیشود) و وقتی چیزی مطابقت نکند nil برمیگرداند، OpenEmail.language_by_code کد را دقیقاً و بدون حساسیت به بزرگی و کوچکی حروف تطبیق میدهد، و شانزده ردیف از راست به چپاند. native، label و code را با هم جستوجو کنید، native را اول نشان دهید، و کد را ذخیره کنید.
emails.translate بهطور خودکار دوباره تلاش نمیشود. فراخوانی مدل خرج میکند و چیزی نمینویسد، پس چیزی برای idempotent کردن نیست و تلاش دوباره پس از درخواستی بیپاسخ فقط همان پاسخ را دو بار میخرد.
- زبانی که API نتواند تطبیقش دهد یک
validation_errorرویtranslate.toاست، پیش از آنکه چیزی فرستاده شود. translation_too_longبرای بیش از 30,000 نویسه،translation_not_configuredوقتی نصب هیچ AI پیکربندیشدهای ندارد، یک 429ai_quota_exceededوقتی آن فضای کاری کنشهای هوش مصنوعی امروز را مصرف کرده باشد (در نیمهشب UTC بازنشانی میشود و دوباره تلاش نمیشود)،translation_failedوقتی ارائهدهنده پاسخ نداده است. هیچکدام بهعنوان جایگزین، پیام را ترجمهنشده نمیفرستند.- با
templateکار میکند: آنچه ترجمه میشود خروجیِ RENDER شده است، پس یک بدنهٔ ذخیرهشده به هر زبانی که مشتریانتان میخوانند خدمت میکند. قالبی که یک سند کامل رندر میکند، doctype، بلوکهای<style>و قاعدههای@font-faceخود را نگه میدارد: فقط بدنه به مدل میرود و بقیه دوباره دورش گذاشته میشود.<title>آن دستنخورده میماند، که بههرحال چیزی نمایشش نمیدهد. - تلاش دوباره هزینهٔ اضافه ندارد. ترجمه بخشی از اثرانگشت idempotency نیست (خودِ درخواست هست، با
translateو همه)، پس بازفرستادن یک ارسال بیپاسخ با همانIdempotency-Keyپیامی را که از پیش وجود دارد بازپخش میکند، نه اینکه بار دوم ترجمه و ارسال کند. - پیام ترجمهشدهای که queued یا scheduled باشد متن تأییدشدهاش را نگه میدارد.
emails.rescheduleهنوز جابهجایش میکند، در حالی کهemails.updateمتن تازه را با یک 409translation_lockedرد میکند، پس تغییر آنچه میگوید یعنی لغو و ارسال دوباره.
پیوستها
content روی سیم base64 است. بایتها را بدهید تا برایتان رمزگذاری شوند: یک String دودویی مانند آنچه File.binread برمیگرداند، یک IO مانند یک File باز، یا یک Pathname که برایتان خوانده میشود.
attachments = [ {filename: "invoice.pdf", content: File.binread("invoice.pdf"), contentType: "application/pdf"}, {filename: "report.pdf", content: Pathname("report.pdf")}, {fileId: "file_6bb640f5b99e47deb758f1f5"}] client.emails.send( from: "[email protected]", to: "[email protected]", subject: "Your documents", text: "Both are attached.", attachments:)Stringی که بهعنوان متن برچسب خورده، مانند آنچه File.read برمیگرداند، از پیش base64 فرض میشود، و اگر base64 نباشد پیش از فرستادن هر چیزی ArgumentError را raise میکند. فایلها را با File.binread بخوانید، یا روی بایتهایی که با برچسب متن رسیدهاند .b را فراخوانی کنید.
اگر همین رمزگذاری را جای دیگری لازم دارید، OpenEmail.to_base64 هست. یک String دودویی، یک IO یا یک Pathname میگیرد و base64 سختگیرانه (strict)، بدون شکست خط، برمیگرداند.