تخطَّ إلى المستندات
Ruby

إرسال رسالة

`emails.send`: رسالة واحدة، الآن أو لاحقًا.

emails.send

send_email.rb
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 منهم، والمستلم المنفرد يُغلَّف لك. وكل منهم قد يكون عنوانًا مجرّدًا، أو 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`. ولا يوجد مُرسِل احتياطي، فكل إرسال يسمّي دائمًا العنوان الذي يخرج منه.
toString, Hash or Arrayمطلوب
مستلم واحد أو Array منهم، والمستلم المنفرد يُغلَّف لك. بحد أقصى 50 في `to` و`cc` و`bcc` مجتمعة، وما زاد يعطي 422 `too_many_recipients`.
ccString, Hash or Array
تُحسب ضمن حد الخمسين مستلمًا.
bccString, Hash or Array
لا يُسمّى أبدًا في البايتات التي يتلقاها أي شخص آخر، لأن مُغلَّفًا واحدًا يُبثّ لكل مستلم. ويُحتسب ضمن الخمسين أيضًا.
replyToString or Hash
عنوان واحد، يُرسل كترويسة Reply-To.
subjectString
بحد أقصى 998 حرفًا، وهو حد السطر في RFC 5322. والافتراضي فارغ، والموضوع الفارغ يُستعاض عنه بموضوع القالب أو المسودة.
htmlString
يلزم واحد من `html` أو `text` أو `draftId` أو `template`. وHTML هو ما يراه المستلمون عندما يُعطى `html` و`text` معًا. بحد أقصى 1,000,000 حرف.
textString
جزء النص العادي، بحد أقصى 1,000,000 حرف.
templateHash
اعرض قالبًا مخزَّنًا على الخادم: Hash فيه `id`، الذي يأخذ معرّفًا أو slug، و`version` اختياري (Integer) و`props` و`slots`. ويثبّت `version` مراجعة بعينها. اتركه لاستخدام ما يكون منشورًا عند قبول الطلب. والخاصية المجهولة أو الناقصة تعطي 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 ميغابايت للملفات المضمّنة مجتمعة بعد فك الترميز. والملف المخزَّن يمكن أن يكون أكبر ويُرسَل كرابط تنزيل.
attachmentDeliveryString
`mime` أو `link` أو `auto`. تحمل `auto` الملفات كروابط تنزيل متى تجاوزت 2 ميغابايت على نطاق له نطاق ملفات نشط، وداخل الرسالة فيما عدا ذلك. وإذا تُركت، طُبّق إعداد صندوق البريد، وهو `auto` افتراضيًا.
threadIdString
الرد داخل محادثة قائمة. ويكتب النقل ترويستي 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. نافذة تراجع على إرسال فوري: آلية التراجع في محرّر الرسائل، مكشوفة بدل أن تكون مثبتة في الشيفرة.
tagsHash
حتى 10 وسوم، بمفاتيح من 1 إلى 64 حرفًا من الحروف أو الأرقام أو `_` أو `-`، وقيم String حتى 256 حرفًا. تُعاد كما هي في كل قراءة ولا تُفسَّر أبدًا.
signatureBoolean
هل تحمل هذه الرسالة توقيع العنوان المرسِل: توقيعه الخاص، وإلا فتوقيع الالتقاط الشامل لعنوان التقطه، وإلا فتذييل OpenEmail ما لم يوقفه ذلك العنوان. إن لم يُحدَّد، يخرج متن `html` كما كُتب تمامًا بلا توقيع، ويحمله متن `text` وحده. اضبطه على `false` للبريد الذي يرسله برنامج نيابةً عن شخص، مثل إيصال أو إعادة تعيين كلمة مرور أو ملخص، فلا أحد منها يحتاج توقيع شخص أسفله. ولا تحمل الإرسالات بالقوالب ولا الإرسالات المشفّرة توقيعًا أبدًا.
trackingHash
Hash فيه `opens` و`clicks` اختياريان من نوع Boolean: هل يُضاف بكسل فتح وتُعاد كتابة الروابط لهذه الرسالة. معطَّل ما لم يُفعَّل التتبّع للعنوان الذي تُرسل منه (أو للالتقاط الشامل الذي التقطه)، وأي مفتاح يُذكر هنا يحسم أمر تلك الرسالة وحدها أيًّا كان ضبط العنوان.
translateHash
أرسلها بلغة المستلم: Hash فيه `to`، ومعه `from` و`subject` و`includeOriginal` اختياريًا. تأخذ `to` رمزًا أو اسمًا إنجليزيًا أو اسم اللغة بلغتها، و`subject` و`includeOriginal` كلاهما true افتراضيًا. ويُحسم ذلك عند قبول الطلب، فالرسالة المجدولة تحمل الكلمات التي اعتُمدت. ويُرفض مع `draftId`.
idempotency_keyString
مفتاحك الخاص لهذا الإرسال، من 1 إلى 255 حرفًا من الحروف أو الأرقام أو `_` أو `.` أو `:` أو `-`. ودونه يولّد العميل مفتاحًا لكل استدعاء، فلا ترسل إعادات محاولته مرتين أبدًا، ومعه يُعاد تشغيل الإرسال الذي يعمل مجددًا في عملية أخرى بدل تكراره.
api_keyString
يرسل بهذا المفتاح بدل مفتاح العميل، لعملية ترسل بالنيابة عن عدة مساحات عمل.

الاستجابة

Hash بمفاتيح من نوع Symbol، فيقرأ email[:status] الحالة.

idString
معرّف الإرسال، `msg_` متبوعًا بـ 24 حرفًا ست عشريًا. استخدمه مع `get` و`cancel` و`reschedule` و`get_tracking`.
statusString
queued أو scheduled أو sending أو sent أو partial أو bounced أو cancelled أو failed. اقرأ هذا بدل الاكتفاء بأن الاستدعاء قد عاد: فالإرسال الفوري يُنفَّذ داخل الطلب ويعود عادةً بالحالة `sent` أو `partial` أو `failed`، والإرسال المؤجَّل يعود بالحالة `queued` أو `scheduled`. و`partial` حالة قائمة بذاتها: فبعض المستلمين لديهم الرسالة ولا يمكن سحبها منهم، ومن ثَم فإعادة المحاولة خطأ والإبلاغ عن فشل كذب.
modeString
`live` أو `test`: نوع المفتاح الذي أرسلها. والإرسال التجريبي يُسجَّل ولا يُبثّ أبدًا. وتظهر حالته `sent`، مع ضبط `transport` على `test`، فتحقق من الاستجابة لا من صندوق وارد.
fromString
العنوان الذي أُذن به فعلًا ووُضع على الشبكة، وهو ليس دائمًا العنوان المطلوب.
subjectString or nil
كما أُرسل.
messageIdString or nil
ترويسة Message-ID بحسب RFC 5322. تكون nil إلى أن توجد رسالة MIME. وتعيد خدمة الإرسال كتابة الترويسة عند الخروج، فلا يحمل أي ارتداد أو تقرير تسليم هذه القيمة. و`id` هو ما يعود به أي حدث.
threadIdString or nil
المحادثة التي حطّت فيها.
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 للطلب، وما خرج هو ما يُرسل: فترجمة تعذّر إنتاجها ترفض الإرسال بدل أن تنشره باللغة التي كتبته بها.

translate.rb
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_translation.rb
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]  )end
languages.rb
p 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. والجدول مضمَّن، بترتيب أداة الاختيار، بوصفه OpenEmail::LANGUAGES، وهو Array مجمَّدة من Hash فيها code وlabel وnative وflag وrtl، فيمكن ملء أداة اختيار اللغة قبل أول طلب. ويعيد languages.list السجلات نفسها من الشبكة في صورة Array عادية، لمن يفضّل الحالية على تلك التي جاء بها هذا الإصدار. ويأخذ OpenEmail.resolve_language رمزًا أو اسمًا إنجليزيًا أو اسم اللغة بلغتها أو اسمًا بديلًا (zh-TW اسم بديل لرمز لم يعد مدرجًا) ويعيد nil حين لا يطابق شيء، ويطابق OpenEmail.language_by_code رمزًا مطابقًا تمامًا بأي حالة أحرف، وستة عشر من السجلات تُكتب من اليمين إلى اليسار. ابحث في native وlabel وcode معًا، واعرض native أولًا، واحفظ الرمز.

لا يُعاد استدعاء emails.translate تلقائيًا. فهو ينفق استدعاءات للنموذج ولا يكتب شيئًا، فلا شيء هناك لجعله عديم أثر التكرار، وإعادة المحاولة بعد طلب بلا إجابة لن تشتري سوى الإجابة نفسها مرتين.

  • اللغة التي لا تستطيع API مطابقتها تعطي validation_error على translate.to، قبل إرسال أي شيء.
  • translation_too_long فوق 30,000 حرف، وtranslation_not_configured عندما لا يكون في التثبيت أي إعداد للذكاء الاصطناعي، و429 ai_quota_exceeded عندما تكون مساحة العمل قد استنفدت إجراءات الذكاء الاصطناعي لهذا اليوم (يُصفَّر عند منتصف الليل بتوقيت UTC ولا تُعاد المحاولة)، وtranslation_failed عندما لا يجيب المزوّد. ولا يرسل أي منها الرسالة دون ترجمة كحل بديل.
  • يعمل مع template: فالمخرَج المعروض هو ما يُترجم، فيخدم جسم مخزَّن واحد كل لغة يقرأ بها عملاؤك. والقالب الذي يعرض مستندًا كاملًا يحتفظ بـ doctype وكتل <style> وقواعد @font-face الخاصة به: إذ لا يذهب إلى النموذج سوى الجسم ويُعاد الباقي حوله. ويُترك <title> كما هو، وهو ما لا يعرضه شيء على أي حال.
  • إعادة المحاولة لا تكلّف شيئًا إضافيًا. فالترجمة ليست جزءًا من بصمة منع التكرار (الطلب هو الجزء، بما فيه translate)، لذا فإن إعادة إرسال طلب بلا إجابة بالـ Idempotency-Key نفسه تعيد تشغيل الرسالة الموجودة أصلًا بدل أن تترجم وترسل ثانية.
  • الرسالة المترجمة التي تكون في الطابور أو مجدولة تحتفظ بصياغتها المعتمدة. وemails.reschedule ما زال ينقلها، بينما يرفض emails.update أي صياغة جديدة بالخطأ 409 translation_locked، فتغيير ما تقوله يعني الإلغاء وإعادة الإرسال.

المرفقات

يكون content بترميز base64 عند الإرسال عبر الشبكة. مرّر البايتات وتُرمَّز لك: String ثنائي مثل الذي يعيده File.binread، أو IO مثل File مفتوح، أو Pathname يُقرأ لك.

attachments.rb
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 قبل إرسال أي شيء. اقرأ الملفات عبر File.binread، أو استدعِ .b على البايتات التي وصلت موسومة كنص.

يتوفر OpenEmail.to_base64 إن احتجت إلى الترميز نفسه في مكان آخر. يأخذ String ثنائيًا أو IO أو Pathname ويعيد base64 صارمًا، دون فواصل أسطر.