दस्तावेज़ पर जाएँ
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 लेते हैं, और अकेला हो तो आपके लिए Array में लपेट दिया जाता है। हर एक सादा पता, Name <addr@host>, या email और name वाला Hash हो सकता है।

संदेश keyword arguments के रूप में, या एक Hash के रूप में दिया जाता है। Hash के साथ दिए गए keyword arguments उसमें मिला दिए जाते हैं और जहाँ दोनों एक ही फ़ील्ड का नाम लें वहाँ वही जीतते हैं, इसलिए client.emails.send(message, subject: "Re: your invoice") पहले बनाए गए संदेश का एक फ़ील्ड बदल देता है। कुंजियाँ API के नाम बनाए रखती हैं, इसीलिए replyTo और scheduledAt camelCase में रहते हैं, जबकि idempotency_key: और api_key: कॉल के विकल्प हैं और कभी संदेश का हिस्सा नहीं होते।

पैरामीटर

fromString or Hashआवश्यक
प्रेषक। सादा पता, `Name <addr@host>`, या `email` और `name` वाला Hash। यह ऐसा पता होना चाहिए जिससे यह कुंजी भेज सकती है, वरना कॉल 403 `from_address_forbidden` raise करती है। कोई फ़ॉलबैक प्रेषक नहीं है, इसलिए हर send हमेशा उस पते का नाम लेता है जिससे वह बाहर जाता है।
toString, Hash or Arrayआवश्यक
एक प्राप्तकर्ता या उनकी एक Array, और अकेला हो तो आपके लिए Array में लपेट दिया जाता है। `to`, `cc` और `bcc` मिलाकर अधिकतम 50, और इससे ज़्यादा 422 `too_many_recipients` है।
ccString, Hash or Array
यह 50 प्राप्तकर्ताओं की सीमा में गिना जाता है।
bccString, Hash or Array
किसी और को मिलने वाले बाइट्स में इसका नाम कभी नहीं आता, क्योंकि हर प्राप्तकर्ता के लिए एक envelope भेजा जाता है। यह भी 50 में गिना जाता है।
replyToString or Hash
एक अकेला पता, जो Reply-To header के रूप में भेजा जाता है।
subjectString
अधिकतम 998 वर्ण, जो RFC 5322 की पंक्ति सीमा है। डिफ़ॉल्ट ख़ाली है, और ख़ाली विषय टेम्पलेट या ड्राफ़्ट के विषय पर चला जाता है।
htmlString
`html`, `text`, `draftId` या `template` में से एक ज़रूरी है। जब `html` और `text` दोनों दिए जाएँ तो प्राप्तकर्ता HTML ही देखते हैं। अधिकतम 1,000,000 वर्ण।
textString
सादा-टेक्स्ट हिस्सा, अधिकतम 1,000,000 वर्ण।
templateHash
सहेजे गए टेम्पलेट को सर्वर पर रेंडर करें: `id` वाला एक Hash, जो id या slug लेता है, और वैकल्पिक `version` (एक Integer), `props` और `slots`। `version` किसी संस्करण को पिन करता है। रिक्वेस्ट स्वीकार होने के समय जो प्रकाशित हो उसे इस्तेमाल करने के लिए इसे छोड़ दें। अज्ञात या ग़ायब prop संदेश में ख़ाली जगह के बजाय 422 है।
draftIdString
सहेजे गए ड्राफ़्ट को इस envelope के तहत, जैसा लिखा गया था वैसा भेजें। इसे `template` या `translate` के साथ नहीं मिलाया जा सकता।
headersHash
हेडर नाम से String मान तक, `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority और Feedback-ID तक सीमित। transport जो कुछ ख़ुद सेट करता है उसे चुपचाप हटाने के बजाय 422 `reserved_header` के साथ अस्वीकार किया जाता है।
attachmentsArray<Hash>
हर एक `filename`, `content` और वैकल्पिक `contentType` वाला Hash, या सिर्फ़ `fileId` वाला Hash, जो वर्कस्पेस में पहले से मौजूद किसी फ़ाइल का नाम लेता है, जैसे `files.upload` से आई फ़ाइल। `content` के लिए बाइट्स पास करें और वे आपके लिए base64 में एन्कोड हो जाते हैं। 20 फ़ाइलें, डिकोड होने के बाद इनलाइन फ़ाइलों की कुल सीमा 5 MB। सहेजी गई फ़ाइल बड़ी हो सकती है और डाउनलोड लिंक के रूप में जाती है।
attachmentDeliveryString
`mime`, `link` या `auto`। `auto` फ़ाइलों को डाउनलोड लिंक के रूप में तब ले जाता है जब वे सक्रिय files domain वाले किसी domain पर 2 MB पार कर जाएँ, और बाक़ी हालत में संदेश के भीतर। छोड़ देने पर मेलबॉक्स की सेटिंग लागू होती है, और उसका डिफ़ॉल्ट `auto` है।
threadIdString
किसी मौजूदा thread में उत्तर दें। transport In-Reply-To और References लिखता है।
scheduledAtTime, DateTime or String
एक Time या DateTime, जो UTC ISO 8601 क्षण के रूप में भेजा जाता है, String के रूप में एक ISO 8601 क्षण, या `PT1H` जैसी अवधि। एक साल आगे तक, अतीत में कभी नहीं। `cancellableForSeconds` के साथ नहीं मिलाया जा सकता। Ruby Date सादी तारीख़ के रूप में भेजी जाती है, जिसे API उस दिन की UTC आधी रात पढ़ता है, इसलिए जब घंटा मायने रखता हो तो Time पास करें।
cancellableForSecondsInteger
0 से 900 तक। तत्काल send पर एक undo खिड़की: composer की undo व्यवस्था, hardcode किए जाने के बजाय उजागर की हुई।
tagsHash
अधिकतम 10 लेबल, जिनकी कुंजियाँ अक्षरों, अंकों, `_` या `-` के 1 से 64 वर्णों की और String मान 256 वर्ण तक। हर read पर वापस लौटाए जाते हैं और इनकी कभी व्याख्या नहीं होती।
signatureBoolean
क्या यह संदेश उस पते का सिग्नेचर लिए होगा जिससे यह भेजा जाता है: उसी पते का अपना, वरना catch-all ने जिस पते को पकड़ा उसके लिए catch-all का, वरना OpenEmail फ़ुटर, जब तक उस पते ने उसे बंद न किया हो। छोड़ दें तो `html` बॉडी बिल्कुल लिखे अनुसार बिना सिग्नेचर के जाती है और सिर्फ़-`text` बॉडी में वह रहता है। किसी की ओर से प्रोग्राम द्वारा भेजे जाने वाले मेल के लिए `false` सेट करें, जैसे रसीद, पासवर्ड रीसेट या डाइजेस्ट, जिनमें से किसी के नीचे किसी व्यक्ति का हस्ताक्षर नहीं चाहिए। टेम्पलेट से भेजे गए और एन्क्रिप्टेड sends में कभी सिग्नेचर नहीं होता।
trackingHash
वैकल्पिक Boolean `opens` और `clicks` वाला एक Hash: क्या इस संदेश के लिए open pixel जोड़ा जाए और लिंक दोबारा लिखे जाएँ। यह बंद रहता है जब तक उस पते के लिए ट्रैकिंग चालू न की गई हो जिससे यह भेजा जाता है (या उसे पकड़ने वाले catch-all के लिए), और यहाँ बताई गई कोई भी कुंजी उस एक संदेश का फ़ैसला कर देती है, चाहे पता कैसे भी सेट हो।
translateHash
इसे प्राप्तकर्ता की भाषा में भेजें: `to` और वैकल्पिक `from`, `subject` और `includeOriginal` वाला एक Hash। `to` एक कोड, अंग्रेज़ी नाम या भाषा का अपना नाम लेता है, और `subject` तथा `includeOriginal` दोनों का डिफ़ॉल्ट true है। रिक्वेस्ट स्वीकार होते समय तय होता है, इसलिए शेड्यूल किया गया संदेश वही शब्द ले जाता है जो स्वीकृत हुए थे। `draftId` के साथ अस्वीकार किया जाता है।
idempotency_keyString
इस send के लिए आपकी अपनी कुंजी, अक्षरों, अंकों, `_`, `.`, `:` या `-` के 1 से 255 वर्ण। इसके बिना क्लाइंट हर कॉल के लिए एक कुंजी बनाता है, ताकि उसके अपने पुनः प्रयास कभी दो बार न भेजें, और इसके साथ, किसी दूसरे प्रोसेस में दोबारा चलने वाला send दोहराने के बजाय replay होता है।
api_keyString
क्लाइंट की कुंजी के बजाय इस कुंजी से भेजता है, उस प्रोसेस के लिए जो कई वर्कस्पेस की ओर से भेजता है।

प्रतिक्रिया

Symbol कुंजियों वाला एक Hash, इसलिए email[:status] status पढ़ता है।

idString
send की id, `msg_` के बाद 24 hex वर्ण। इसे `get`, `cancel`, `reschedule` और `get_tracking` के लिए इस्तेमाल करें।
statusString
queued, scheduled, sending, sent, partial, bounced, cancelled या failed। कॉल लौटने के तथ्य के बजाय इसे पढ़ें: तुरंत वाला send रिक्वेस्ट के अंदर ही भेज दिया जाता है और आमतौर पर `sent`, `partial` या `failed` लौटता है, और रोका गया send `queued` या `scheduled` लौटता है। `partial` अपनी अलग स्थिति है: कुछ प्राप्तकर्ताओं के पास यह पहुँच चुका है और उसे वापस नहीं लिया जा सकता, इसलिए पुनः प्रयास ग़लत है और विफलता बताना झूठ है।
modeString
`live` या `test`: किस तरह की कुंजी ने इसे भेजा। test send दर्ज होता है और कभी भेजा नहीं जाता। यह `sent` पढ़ता है, `transport` का मान `test` रखते हुए, इसलिए assert जवाब पर करें, किसी इनबॉक्स पर नहीं।
fromString
वह पता जो असल में अधिकृत हुआ और तार पर गया, जो हमेशा वही नहीं होता जो माँगा गया था।
subjectString or nil
जैसा भेजा गया।
messageIdString or nil
RFC 5322 Message-ID। जब तक MIME नहीं बनता तब तक nil। भेजने वाली सेवा बाहर जाते समय हेडर दोबारा लिखती है, इसलिए कोई bounce या डिलीवरी रिपोर्ट यह मान नहीं ले जाती। इवेंट `id` पर लौटता है।
threadIdString or nil
वह thread जिसमें यह उतरा।
transportString or nil
संदेश कैसे निकला। भेजे जाने तक nil।
attemptsInteger
dispatch कितनी बार आज़माया जा चुका है।
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 पहले से मौजूद send से मेल खा गई। कुछ नया नहीं भेजा गया, और यह मूल संदेश है जैसा वह अभी है।
translationHash
सिर्फ़ उस संदेश पर मौजूद जिसका अनुवाद हुआ, और सिर्फ़ वहाँ जहाँ पूरी सहेजी गई रिक्वेस्ट साथ आती है: यह जवाब और `get`। इसमें `language`, `languageName`, `detectedSourceLanguage`, `subject` और `includeOriginal` होते हैं, पूरी भाषा पंक्तियों के बजाय कोड के साथ। सूची की पंक्ति में यह कभी नहीं होता, इसलिए वहाँ इसका न होना किसी भी तरफ़ कुछ नहीं कहता।

प्राप्तकर्ता की भाषा में

translate संदेश को जाने से पहले किसी और की भाषा में लिख देता है। body, और जब तक आप उसे बंद न करें तब तक विषय भी, तब अनूदित होता है जब API रिक्वेस्ट स्वीकार करता है, और जो निकला वही बाहर जाता है: जो अनुवाद बन ही नहीं सका, वह संदेश को आपकी लिखी भाषा में भेजने के बजाय send को अस्वीकार कर देता है।

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। यह तालिका picker के क्रम में OpenEmail::LANGUAGES के रूप में साथ आती है, code, label, native, flag और rtl वाले Hashes की एक frozen Array, ताकि पहली रिक्वेस्ट से पहले ही picker भरा जा सके। languages.list यही पंक्तियाँ नेटवर्क से एक सादी Array के रूप में लौटाता है, उस कॉलर के लिए जिसे इस वर्शन के साथ आई पंक्तियों के बजाय मौजूदा पंक्तियाँ चाहिए। OpenEmail.resolve_language एक कोड, अंग्रेज़ी नाम, भाषा का अपना नाम या कोई उपनाम लेता है (zh-TW एक ऐसे कोड का उपनाम है जो अब सूची में नहीं है) और कुछ मेल न खाए तो nil लौटाता है, OpenEmail.language_by_code किसी भी case में सटीक कोड मिलाता है, और सोलह पंक्तियाँ दाएँ से बाएँ हैं। native, label और code को साथ में खोजें, पहले native दिखाएँ, और कोड सहेजें।

emails.translate अपने आप दोबारा नहीं आज़माया जाता। इसमें model कॉल ख़र्च होती हैं और यह कुछ लिखता नहीं, इसलिए idempotent बनाने को कुछ है ही नहीं और बिना उत्तर वाली रिक्वेस्ट के बाद का retry वही उत्तर दो बार ख़रीदने भर से ज़्यादा कुछ नहीं होता।

  • जिस भाषा को API मिला न सके वह कुछ भी भेजे जाने से पहले translate.to पर validation_error है।
  • 30,000 वर्णों से ज़्यादा पर translation_too_long, जब इंस्टॉल में कोई AI कॉन्फ़िगर न हो तो translation_not_configured, जब वर्कस्पेस ने आज की AI कार्रवाइयाँ इस्तेमाल कर ली हों तो 429 ai_quota_exceeded (यह UTC की आधी रात को रीसेट होता है और इस पर पुनः प्रयास नहीं होता), जब प्रदाता ने जवाब न दिया हो तो translation_failed। इनमें से कोई भी फ़ॉलबैक के रूप में संदेश बिना अनुवाद के नहीं भेजता।
  • template के साथ काम करता है: अनुवाद render किए गए आउटपुट का होता है, इसलिए एक संग्रहित body आपके ग्राहकों की हर पढ़ी जाने वाली भाषा में काम आता है। पूरा दस्तावेज़ render करने वाला template अपना doctype, अपने <style> ब्लॉक और अपने @font-face नियम बनाए रखता है: model के पास केवल body जाता है और बाक़ी सब उसके चारों ओर वापस रख दिया जाता है। उसका <title> अछूता छोड़ दिया जाता है, जिसे वैसे भी कुछ नहीं दिखाता।
  • retry का कोई अतिरिक्त ख़र्च नहीं। अनुवाद idempotency fingerprint का हिस्सा नहीं है (रिक्वेस्ट है, translate सहित), इसलिए बिना उत्तर वाले send को उसी Idempotency-Key के साथ दोबारा भेजना पहले से मौजूद संदेश को दोहरा देता है, दूसरी बार अनुवाद करके भेजता नहीं।
  • जो अनुवादित संदेश queued या scheduled है वह अपने स्वीकृत शब्द बनाए रखता है। emails.reschedule फिर भी उसे खिसका सकता है, जबकि emails.update नए शब्दों को 409 translation_locked के साथ अस्वीकार करता है, इसलिए उसकी बात बदलने का मतलब है रद्द करके फिर से भेजना।

अटैचमेंट

नेटवर्क पर content base64 है। बाइट्स पास करें और वे आपके लिए एन्कोड हो जाते हैं: File.binread जैसी binary String, खुली File जैसा IO, या 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 raise करती है। फ़ाइलें File.binread से पढ़ें, या टेक्स्ट के रूप में चिह्नित होकर आए बाइट्स पर .b कॉल करें।

अगर आपको यही एन्कोडिंग कहीं और चाहिए तो OpenEmail.to_base64 मौजूद है। यह binary String, IO या Pathname लेता है और बिना लाइन ब्रेक वाला strict base64 लौटाता है।