ईमेल भेजें
`emails.send`: एक संदेश, अभी या बाद में।
emails.send
from openemail import openemail email = 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': pdf_bytes}], 'threadId': 'thread_…', 'scheduledAt': 'PT1H', 'tags': {'order': '4021'}, 'tracking': {'opens': True, 'clicks': True},})to, cc और bcc एक प्राप्तकर्ता लेते हैं या कई, और अकेले को आपके लिए लपेट दिया जाता है। हर एक सादा पता हो सकता है, Name <addr@host>, या {'email': ..., 'name': ...}।
पैरामीटर
fromRecipientInputआवश्यक- भेजने वाला। सादा पता, `Name <addr@host>`, या कोई dict। यह ऐसा होना चाहिए जिसके रूप में यह कुंजी भेज सकती है। कोई फ़ॉलबैक प्रेषक नहीं है, इसलिए हर send हमेशा वह पता बताता है जिससे वह जाता है।
toRecipientInput | list[RecipientInput]आवश्यक- एक प्राप्तकर्ता या कई; अकेले को आपके लिए लपेट दिया जाता है। to, cc और bcc को मिलाकर अधिकतम 50।
ccRecipientInput | list[RecipientInput]- यह 50 प्राप्तकर्ताओं की सीमा में गिना जाता है।
bccRecipientInput | list[RecipientInput]- बाक़ी लोगों को मिलने वाले bytes में इसका नाम कभी नहीं आता, क्योंकि प्रति प्राप्तकर्ता एक लिफ़ाफ़ा प्रेषित होता है।
replyToRecipientInput- एक अकेला पता, जो Reply-To header के रूप में भेजा जाता है।
subjectstr- अधिकतम 998 वर्ण, यानी RFC 5322 की पंक्ति-सीमा। डिफ़ॉल्ट खाली।
htmlstr- html, text, draftId या template में से एक ज़रूरी है। जब html और text दोनों दिए जाएँ तो प्राप्तकर्ता HTML ही देखते हैं।
textstr- सादा-पाठ हिस्सा।
templateEmailSendTemplate- सर्वर पर संग्रहित template को render करें। `version` उसे पिन करता है; इसे छोड़ दें तो रिक्वेस्ट स्वीकार होते समय जो प्रकाशित हो वही उपयोग होता है। अनजान या ग़ायब prop संदेश में ख़ाली जगह नहीं, 422 देता है।
draftIdstr- इस लिफ़ाफ़े के तहत कोई सहेजा गया draft भेजें।
headersdict[str, str]- `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority और Feedback-Id। जो कुछ transport ख़ुद सेट करता है उसे चुपचाप गिराने के बजाय अस्वीकार किया जाता है।
attachmentslist[AttachmentInput]- वैकल्पिक `'contentType'` के साथ `{'filename': ..., 'content': ...}`, या वर्कस्पेस में पहले से मौजूद किसी फ़ाइल का नाम लेता `{'fileId': ...}`, जैसे `files.upload` से आई फ़ाइल। content के लिए bytes दें और वे आपके लिए base64 में बदल दिए जाते हैं। 20 फ़ाइलें, जिनमें inline फ़ाइलें decode होने के बाद कुल 5 MB तक सीमित। संग्रहित फ़ाइल इससे बड़ी हो सकती है और डाउनलोड लिंक के रूप में जाती है।
attachmentDeliveryAttachmentDeliveryMode- `mime`, `link` या `auto`। `auto` फ़ाइलों को डाउनलोड लिंक के रूप में तब ले जाता है जब वे सक्रिय files domain वाले किसी domain पर 2 MB पार कर जाएँ, और बाक़ी हालत में संदेश के भीतर। छोड़ देने पर मेलबॉक्स की सेटिंग लागू होती है, और उसका डिफ़ॉल्ट `auto` है।
threadIdstr- किसी मौजूदा thread में उत्तर दें। transport In-Reply-To और References लिखता है।
scheduledAtdatetime | str- एक `datetime`, एक ISO-8601 क्षण, या `PT1H` जैसी कोई अवधि। एक साल तक आगे, अतीत में कभी नहीं। इसे cancellableForSeconds के साथ नहीं मिलाया जा सकता।
cancellableForSecondsint- 0 से 900 तक। तत्काल send पर एक undo खिड़की: composer की undo व्यवस्था, hardcode किए जाने के बजाय उजागर की हुई।
tagsdict[str, str]- अधिकतम 10 लेबल, वापस लौटाए जाने वाले और फ़िल्टर करने योग्य। इनकी कभी व्याख्या नहीं होती।
signaturebool- यह संदेश उस पते का हस्ताक्षर ले जाए या नहीं जिससे वह भेजा जा रहा है: उसका अपना, नहीं तो catch-all के पकड़े पते के लिए catch-all का, नहीं तो OpenEmail फ़ुटर, जब तक उस पते ने उसे बंद न किया हो। न देने पर `html` बॉडी बिल्कुल वैसी ही जाती है जैसी लिखी है, बिना हस्ताक्षर के, और सिर्फ़ `text` वाली बॉडी में हस्ताक्षर लगता है। जो मेल कोई प्रोग्राम किसी की ओर से भेजता है, जैसे रसीद, पासवर्ड रीसेट या digest, उसके लिए इसे `False` रखें, क्योंकि इनमें से किसी के नीचे किसी व्यक्ति के दस्तख़त नहीं चाहिए।
trackingTrackingRequest- इस संदेश में open pixel जोड़ा जाए और लिंक दोबारा लिखे जाएँ या नहीं। यह तब तक बंद रहता है जब तक उस पते के लिए (या उसे पकड़ने वाले catch-all के लिए) tracking चालू न की गई हो जिससे संदेश भेजा जा रहा है, और यहाँ बताया गया कोई भी फ़ील्ड उस एक संदेश के लिए फ़ैसला कर देता है, चाहे पते की सेटिंग जो भी हो।
translateSendTranslateOptions- इसे प्राप्तकर्ता की भाषा में भेजें। `to` कोई कोड, अंग्रेज़ी नाम या भाषा का अपना नाम लेता है; `subject` और `includeOriginal` दोनों डिफ़ॉल्ट रूप से true हैं। यह रिक्वेस्ट स्वीकार होते समय हल किया जाता है, इसलिए निर्धारित संदेश वही शब्द ले जाता है जो मंज़ूर हुए थे। `draftId` के साथ अस्वीकार।
प्रतिक्रिया
idstr- send की id, `msg_…`। इसका उपयोग `get`, `cancel`, `reschedule` और `get_tracking` के लिए करें।
statusEmailStatus- queued, scheduled, sending, sent, partial, bounced, cancelled या failed। कॉल के लौट आने के तथ्य के बजाय इसे पढ़ें। `partial` अपने आप में एक स्थिति है: कुछ प्राप्तकर्ताओं के पास संदेश है और उसे वापस नहीं लिया जा सकता, इसलिए दोबारा कोशिश करना ग़लत है और विफलता बताना झूठ।
modeApiKeyMode- किस प्रकार की कुंजी ने इसे भेजा। test send दर्ज होता है और कभी प्रेषित नहीं होता।
fromstr- वह पता जो असल में अधिकृत हुआ और तार पर गया, जो हमेशा वही नहीं होता जो माँगा गया था।
subjectstr | None- जैसा भेजा गया।
messageIdstr | None- RFC 5322 Message-ID। MIME बनने तक null। sending सेवा बाहर जाते समय इस header को दोबारा लिख देती है, इसलिए कोई bounce या delivery report यह मान नहीं ढोती। event `id` पर ही वापस आता है।
threadIdstr | None- वह thread जिसमें यह उतरा।
transportEmailTransport | str | None- संदेश कैसे रवाना हुआ। dispatch तक null।
attemptsint- dispatch कितनी बार आज़माया जा चुका है।
lastErrorstr | None- आख़िरी प्रयास क्यों विफल हुआ, शब्दशः।
scheduledAtstr | None- ISO क्षण जब यह जाने वाला है।
cancellableUntilstr | None- जब तक अभी का समय इससे पहले है, cancel काम करता है।
sentAtstr | None- ISO क्षण जब यह रवाना हुआ।
tagsdict[str, str]- आपने जो भेजा, वही वापस लौटाया हुआ।
sourceEmailSource | str- composer, api, mcp, ai, oauth या form: किस सतह ने माँगा। `api` API कुंजी पर चलता यही क्लाइंट है, और `oauth` एक्सेस टोकन पर चलता यही क्लाइंट।
createdAtstr- ISO क्षण जब रिकॉर्ड लिखा गया।
replayedbool- True तब, जब कोई Idempotency-Key पहले से मौजूद किसी send से मेल खा गई। कुछ भी नया नहीं भेजा गया, और यह मूल संदेश है।
translationNotRequired[EmailTranslationResource]- केवल उसी संदेश पर मौजूद जो अनूदित हुआ था, और केवल वहाँ जहाँ पूरा संग्रहित अनुरोध साथ चलता है: यह रिस्पॉन्स और `get`। `language`, `languageName`, `detectedSourceLanguage`, `subject` और `includeOriginal` का एक dict, सब भाषा-पंक्तियों के बजाय कोड। list की पंक्ति पर यह कभी नहीं होता, इसलिए वहाँ इसकी अनुपस्थिति किसी भी दिशा में कुछ नहीं कहती। इसे `email.get('translation')` से पढ़ें।
प्राप्तकर्ता की भाषा में
translate संदेश को जाने से पहले किसी और की भाषा में लिख देता है। body, और जब तक आप उसे बंद न करें तब तक विषय भी, तब अनूदित होता है जब API रिक्वेस्ट स्वीकार करता है, और जो निकला वही बाहर जाता है: जो अनुवाद बन ही नहीं सका, वह संदेश को आपकी लिखी भाषा में भेजने के बजाय send को अस्वीकार कर देता है।
from openemail import openemail email = 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'},}) print(email.get('translation'))जाने से पहले उसे किसी ने पढ़ा ही नहीं। emails.translate वही चक्कर है, बस एक क़दम पहले रोक दिया गया। इसे किसी व्यक्ति को दिखाएँ, उसे बदलने दें, फिर जो उसने मंज़ूर किया वही भेजें, कॉल पर translate बिल्कुल लगाए बिना। दोबारा उसे पास करना दूसरी बार अनुवाद कर देता और उनके संपादन फेंक देता।
from openemail import openemail preview = openemail.emails.translate({ 'subject': 'Your September invoice', 'html': '<p>Invoice attached. Payment is due on the 14th.</p>', 'to': 'de',}) print(preview['language']['native'], preview['detectedSourceLanguage'])print(preview['html']) approved_subject = input(f"Subject [{preview['subject']}]: ") or preview['subject'] or '' openemail.emails.send({ 'from': '[email protected]', 'to': '[email protected]', 'subject': approved_subject, 'html': preview['html'] or '',})from openemail import LANGUAGES, is_rtl_language, language_by_code, openemail, resolve_language current = openemail.languages.list() german = resolve_language('Deutsch')traditional = resolve_language('zh-TW')upper = language_by_code('DE') assert len(LANGUAGES) == 200assert german is not None and german['code'] == 'de'assert traditional is not None and traditional['code'] == 'zh-Hant'assert upper is not None and upper['native'] == 'Deutsch'assert is_rtl_language('ar')तालिका picker के क्रम में बंडल की गई है, ताकि पहले अनुरोध से पहले ही picker भरा जा सके। languages.list() तार से आई उन्हीं पंक्तियों को एक सादी list के रूप में लौटाता है, उस कॉलर के लिए जो इस वर्शन के साथ आई पंक्तियों के बजाय मौजूदा पंक्तियाँ चाहता हो। resolve_language कोई कोड, अंग्रेज़ी नाम, स्वनाम या उपनाम लेता है (zh-TW अब सूचीबद्ध न रहे एक कोड का उपनाम है), language_by_code किसी सटीक कोड से केस की परवाह किए बिना मिलान करता है, और सोलह पंक्तियाँ दाएँ से बाएँ हैं। native, label और code को एक साथ खोजें, native पहले दिखाएँ, और कोड संग्रहित करें।
emails.translate अपने आप दोबारा नहीं आज़माया जाता। इसमें model कॉल ख़र्च होती हैं और यह कुछ लिखता नहीं, इसलिए idempotent बनाने को कुछ है ही नहीं और बिना उत्तर वाली रिक्वेस्ट के बाद का retry वही उत्तर दो बार ख़रीदने भर से ज़्यादा कुछ नहीं होता।
- जो भाषा किसी पर हल नहीं होती वह कुछ भी भेजे जाने से पहले
translate.toपरvalidation_errorहै। - 30,000 वर्ण से ऊपर
translation_too_long, जब install में कोई AI कॉन्फ़िगर न हो तबtranslation_not_configured, जब workspace ने आज की AI क्रियाएँ इस्तेमाल कर ली हों तब 429ai_quota_exceeded(यह UTC की आधी रात को रीसेट होता है और इसे दोबारा नहीं आज़माया जाता), और जब provider ने उत्तर न दिया हो तबtranslation_failed। इनमें से कोई भी fallback के तौर पर संदेश बिना अनुवाद के नहीं भेजता। templateके साथ काम करता है: अनुवाद render किए गए आउटपुट का होता है, इसलिए एक संग्रहित body आपके ग्राहकों की हर पढ़ी जाने वाली भाषा में काम आता है। पूरा दस्तावेज़ render करने वाला template अपना doctype, अपने<style>ब्लॉक और अपने@font-faceनियम बनाए रखता है: model के पास केवल body जाता है और बाक़ी सब उसके चारों ओर वापस रख दिया जाता है। उसका<title>अछूता छोड़ दिया जाता है, जिसे वैसे भी कुछ नहीं दिखाता।- retry का कोई अतिरिक्त ख़र्च नहीं। अनुवाद idempotency fingerprint का हिस्सा नहीं है (रिक्वेस्ट है,
translateसहित), इसलिए बिना उत्तर वाले send को उसीIdempotency-Keyके साथ दोबारा भेजना पहले से मौजूद संदेश को दोहरा देता है, दूसरी बार अनुवाद करके भेजता नहीं। - जो अनूदित संदेश queued या scheduled है, उसके शब्द बदले नहीं जा सकते।
emails.rescheduleअब भी उसे खिसका सकता है; उसमें लिखी बात बदलने का मतलब है उसे रद्द करके दोबारा भेजना।
Attachments
तार पर content base64 होता है। आप bytes दें और वे आपके लिए encode कर दिए जाते हैं।
from pathlib import Path from openemail.types import AttachmentInput attachments: list[AttachmentInput] = [ { 'filename': 'invoice.pdf', 'content': Path('invoice.pdf').read_bytes(), 'contentType': 'application/pdf', },]अगर आपको कहीं और ज़रूरत हो तो to_base64 export किया गया है। content में दी गई str जैसी है वैसी ही भेजी जाती है, इसलिए वह पहले से base64 होनी चाहिए।