ईमेल भेजें
`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' => new \SplFileInfo('invoice.pdf')]], 'threadId' => 'CAHk7pQ2x9LmZ4-mail.example.com', 'scheduledAt' => 'PT1H', 'tags' => ['order' => '4021'], 'tracking' => ['opens' => true, 'clicks' => true],]); echo $email['id'], ' ', $email['status'], PHP_EOL;to, cc और bcc एक प्राप्तकर्ता या उनकी सूची लेते हैं, और अकेला प्राप्तकर्ता आपके लिए सूची में लपेट दिया जाता है। हर एक सादा पता, Name <addr@host>, या email और name वाला array हो सकता है।
संदेश एक array है जिसकी कुंजियाँ API के फ़ील्ड नाम हैं, इसीलिए replyTo और scheduledAt camelCase में रहते हैं, जबकि idempotencyKey: और apiKey: कॉल के named आर्ग्युमेंट हैं और कभी संदेश का हिस्सा नहीं होते। पहले बनाए गए संदेश का एक फ़ील्ड बदलने के लिए, उसे एक नए array में फैलाएँ: $client->emails->send([...$message, 'subject' => 'Re: your invoice']) बाकी हर फ़ील्ड रखता है और subject बदल देता है।
पैरामीटर
fromstring or arrayआवश्यक- भेजने वाला। सादा पता, `Name <addr@host>`, या `email` और `name` वाला array। यह ऐसा पता होना चाहिए जिससे यह कुंजी भेज सके, वरना कॉल 403 `from_address_forbidden` throw करती है। कोई fallback भेजने वाला नहीं है, इसलिए हर send हमेशा उस पते का नाम लेता है जिससे वह जाता है।
tostring or arrayआवश्यक- एक प्राप्तकर्ता या उनकी सूची, और अकेला प्राप्तकर्ता आपके लिए लपेट दिया जाता है। `to`, `cc` और `bcc` को मिलाकर अधिकतम 50, और इससे ज़्यादा होने पर 422 `too_many_recipients`।
ccstring or array- यह 50 प्राप्तकर्ताओं की सीमा में गिना जाता है।
bccstring or array- किसी और को मिलने वाले बाइट्स में इसका नाम कभी नहीं आता, क्योंकि हर प्राप्तकर्ता के लिए एक envelope भेजा जाता है। यह भी 50 में गिना जाता है।
replyTostring or array- एक अकेला पता, जो Reply-To header के रूप में भेजा जाता है।
subjectstring- अधिकतम 998 वर्ण, जो RFC 5322 की पंक्ति सीमा है। डिफ़ॉल्ट ख़ाली है, और ख़ाली विषय टेम्पलेट या ड्राफ़्ट के विषय पर चला जाता है।
htmlstring- `html`, `text`, `draftId` या `template` में से एक ज़रूरी है। जब `html` और `text` दोनों दिए जाएँ तो प्राप्तकर्ता HTML ही देखते हैं। अधिकतम 1,000,000 वर्ण।
textstring- सादा-टेक्स्ट हिस्सा, अधिकतम 1,000,000 वर्ण।
templatearray- सहेजे गए टेम्पलेट को सर्वर पर render करें: `id` वाला एक array, जो id या slug लेता है, और वैकल्पिक `version` (एक int), `props` और `slots`। `version` किसी revision को तय कर देता है। रिक्वेस्ट स्वीकार होने के समय जो प्रकाशित है उसे इस्तेमाल करने के लिए इसे छोड़ दें। अज्ञात या ग़ायब prop संदेश में ख़ाली जगह के बजाय 422 होता है।
draftIdstring- सहेजे गए ड्राफ़्ट को इस envelope के तहत, जैसा लिखा गया था वैसा भेजें। इसे `template` या `translate` के साथ नहीं मिलाया जा सकता।
headersarray- हेडर नाम से स्ट्रिंग मान तक, `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority और Feedback-ID तक सीमित। transport जो कुछ ख़ुद सेट करता है, उसे चुपचाप हटाने के बजाय 422 `reserved_header` के साथ अस्वीकार किया जाता है।
attachmentsarray- एक सूची, जिसकी हर प्रविष्टि `filename`, `content` और वैकल्पिक `contentType` वाला array हो, या सिर्फ़ `fileId` वाला array, जो वर्कस्पेस में पहले से मौजूद किसी फ़ाइल का नाम ले, जैसे `files->upload` से आई फ़ाइल। `content` base64 है: `fopen` का stream, `SplFileInfo` या PSR-7 stream आपके लिए पढ़ा और encode किया जाता है, और स्ट्रिंग पहले से base64 होनी चाहिए। 20 फ़ाइलें, जिनमें inline फ़ाइलें डिकोड होने के बाद कुल 5 MB तक सीमित हैं। सहेजी गई फ़ाइल इससे बड़ी हो सकती है और download link के रूप में जाती है।
attachmentDeliverystring- `mime`, `link` या `auto`। `auto` फ़ाइलों को डाउनलोड लिंक के रूप में तब ले जाता है जब वे सक्रिय files domain वाले किसी domain पर 2 MB पार कर जाएँ, और बाक़ी हालत में संदेश के भीतर। छोड़ देने पर मेलबॉक्स की सेटिंग लागू होती है, और उसका डिफ़ॉल्ट `auto` है।
threadIdstring- किसी मौजूदा thread में उत्तर दें। transport In-Reply-To और References लिखता है।
scheduledAtDateTimeInterface or string- एक `DateTimeInterface`, जो UTC में ISO 8601 क्षण के रूप में भेजा जाता है, स्ट्रिंग के रूप में ISO 8601 क्षण, या `PT1H` जैसी अवधि। अधिकतम एक साल आगे तक, अतीत में कभी नहीं। `cancellableForSeconds` के साथ नहीं जोड़ा जा सकता। बिना समय वाली तारीख़ की स्ट्रिंग, जैसे `2027-01-01`, उस दिन की UTC आधी रात के रूप में पढ़ी जाती है, इसलिए जब घंटा मायने रखता हो तो क्षण पास करें।
cancellableForSecondsint- 0 से 900 तक। तत्काल send पर एक undo खिड़की: composer की undo व्यवस्था, hardcode किए जाने के बजाय उजागर की हुई।
tagsarray- अधिकतम 10 लेबल, जिनकी कुंजियाँ 1 से 64 अक्षरों, अंकों, `_` या `-` की हों और स्ट्रिंग मान 256 अक्षरों तक। हर read पर वैसे ही लौटाए जाते हैं और कभी interpret नहीं किए जाते।
signaturebool- क्या यह संदेश उस पते का signature रखता है जिससे यह भेजा गया: उस पते का अपना, नहीं तो catch-all द्वारा पकड़े गए पते के लिए catch-all का, नहीं तो OpenEmail footer, जब तक उस पते ने उसे बंद न किया हो। इसे छोड़ने पर `html` बॉडी बिना signature के ठीक वैसी ही जाती है जैसी लिखी गई, और सिर्फ़ `text` वाली बॉडी में signature होता है। किसी की ओर से प्रोग्राम द्वारा भेजी जाने वाली मेल के लिए इसे false सेट करें, जैसे रसीद, पासवर्ड रीसेट या digest, जिनमें से किसी के नीचे किसी व्यक्ति का sign-off नहीं चाहिए। टेम्पलेट send और encrypted send में कभी signature नहीं होता।
trackingarray- वैकल्पिक `opens` और `clicks` वाला array, हर एक bool: इस संदेश के लिए open pixel जोड़ना है या नहीं और links को फिर से लिखना है या नहीं। तब तक बंद, जब तक भेजने वाले पते (या उसे पकड़ने वाले catch-all) के लिए tracking चालू न की गई हो, और यहाँ बताई गई कोई भी कुंजी उस एक संदेश के लिए फ़ैसला कर देती है, पते की सेटिंग चाहे जो हो।
translatearray- इसे प्राप्तकर्ता की भाषा में भेजें: `to` और वैकल्पिक `from`, `subject` और `includeOriginal` वाला array। `to` एक कोड, अंग्रेज़ी नाम या भाषा का अपना नाम लेता है, और `subject` तथा `includeOriginal` दोनों डिफ़ॉल्ट रूप से true होते हैं। रिक्वेस्ट स्वीकार होते ही तय हो जाता है, इसलिए शेड्यूल किया गया संदेश वही शब्द ले जाता है जो स्वीकृत किए गए थे। `draftId` के साथ अस्वीकार किया जाता है।
idempotencyKeystring- संदेश का फ़ील्ड नहीं, बल्कि कॉल का named आर्ग्युमेंट। इस send के लिए आपकी अपनी कुंजी, अक्षरों, अंकों, `_`, `.`, `:` या `-` के 1 से 255 अक्षर। इसके बिना क्लाइंट हर कॉल के लिए एक कुंजी बनाता है, इसलिए उसके अपने retry कभी दो बार नहीं भेजते, और इसके साथ, किसी दूसरी प्रोसेस में दोबारा चलने वाला send दोहराने के बजाय replay होता है।
apiKeystring- यह भी एक named आर्ग्युमेंट है। क्लाइंट की कुंजी के बजाय इस कुंजी से भेजता है, ऐसी प्रोसेस के लिए जो कई वर्कस्पेस की ओर से भेजती है।
प्रतिक्रिया
API के camelCase नामों वाली कुंजियों का एक array, इसलिए $email['status'] status पढ़ता है।
idstring- send की id, `msg_` के बाद 24 hex वर्ण। इसे `get`, `cancel`, `reschedule` और `getTracking` के लिए इस्तेमाल करें।
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 null- जैसा भेजा गया।
messageIdstring or null- RFC 5322 Message-ID। MIME बनने तक null। भेजने वाली सेवा बाहर जाते समय हेडर को फिर से लिखती है, इसलिए कोई bounce या delivery report यह मान नहीं रखती। event `id` के आधार पर लौटता है।
threadIdstring or null- वह thread जिसमें यह उतरा।
transportstring or null- संदेश कैसे गया। dispatch होने तक null।
attemptsint- dispatch कितनी बार आज़माया जा चुका है।
lastErrorstring or null- आख़िरी प्रयास क्यों विफल हुआ, शब्दशः।
scheduledAtstring or null- वह ISO 8601 क्षण जब इसे जाना है।
cancellableUntilstring or null- जब तक अभी का समय इससे पहले है, `cancel` काम करता है।
sentAtstring or null- वह ISO 8601 क्षण जब यह निकला।
tagsarray- आपने जो भेजा, वही वापस लौटाया हुआ।
sourcestring- composer, api, mcp, ai या queue: किस सतह ने माँगा। `api` यही क्लाइंट है।
createdAtstring- वह ISO 8601 क्षण जब रिकॉर्ड लिखा गया।
replayedbool- तब true जब कोई Idempotency-Key पहले से मौजूद send से मेल खा गई। कुछ नया नहीं भेजा गया, और यह मूल संदेश है जैसा वह अभी है।
translationarray- सिर्फ़ उस संदेश पर मौजूद जिसका अनुवाद हुआ, और सिर्फ़ वहाँ जहाँ पूरी सहेजी गई रिक्वेस्ट साथ आती है: यह जवाब और `get`। इसमें `language`, `languageName`, `detectedSourceLanguage`, `subject` और `includeOriginal` होते हैं, पूरी भाषा पंक्तियों के बजाय कोड के साथ। सूची की पंक्ति में यह कभी नहीं होता, इसलिए वहाँ इसका न होना किसी भी तरफ़ कुछ नहीं कहता।
प्राप्तकर्ता की भाषा में
translate संदेश को जाने से पहले किसी और की भाषा में लिख देता है। body, और जब तक आप उसे बंद न करें तब तक विषय भी, तब अनूदित होता है जब API रिक्वेस्ट स्वीकार करता है, और जो निकला वही बाहर जाता है: जो अनुवाद बन ही नहीं सका, वह संदेश को आपकी लिखी भाषा में भेजने के बजाय send को अस्वीकार कर देता है।
$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'],]); print_r($email['translation'] ?? []);तब $email['translation'] में language का मान de, languageName का German, detectedSourceLanguage का en होता है, और subject तथा 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',]); echo $preview['language']['native'], PHP_EOL, $preview['subject'], PHP_EOL, $preview['html'], PHP_EOL;echo 'Send it as it is? [y/N] '; $answer = fgets(STDIN); if ($answer !== false && strtolower(trim($answer)) === 'y') { $client->emails->send([ 'from' => '[email protected]', 'to' => '[email protected]', 'subject' => $preview['subject'], 'html' => $preview['html'], ]);}use OpenEmail\Constants\Languages;use OpenEmail\OpenEmail; echo count(Languages::ALL), PHP_EOL; $current = $client->languages->list();echo count($current), PHP_EOL; echo OpenEmail::resolveLanguage('Deutsch')['code'] ?? 'none', PHP_EOL;echo OpenEmail::resolveLanguage('zh-TW')['code'] ?? 'none', PHP_EOL;echo OpenEmail::languageByCode('DE')['native'] ?? 'none', PHP_EOL;var_dump(OpenEmail::isRtlLanguage('ar'));ये पंक्तियाँ 200 छापती हैं, यानी इस संस्करण के साथ आने वाली पंक्तियाँ, फिर यह कि API में अभी कितनी हैं, फिर de, zh-Hant, Deutsch और bool(true)। यह तालिका picker के क्रम में OpenEmail\Constants\Languages::ALL के रूप में साथ आती है, code, label, native, flag और rtl वाले arrays की एक सूची, ताकि पहली रिक्वेस्ट से पहले ही picker भरा जा सके। languages->list यही पंक्तियाँ नेटवर्क से एक सादी सूची के रूप में लौटाता है, उस कॉलर के लिए जिसे इस संस्करण के साथ आई पंक्तियों के बजाय मौजूदा पंक्तियाँ चाहिए। OpenEmail::resolveLanguage() एक कोड, अंग्रेज़ी नाम, भाषा का अपना नाम या कोई उपनाम लेता है (zh-TW एक ऐसे कोड का उपनाम है जो अब सूची में नहीं है) और कुछ मेल न खाने पर null लौटाता है, OpenEmail::languageByCode() किसी भी case में सटीक कोड से मिलान करता है, और OpenEmail::isRtlLanguage() बताता है कि कोई भाषा दाएँ से बाएँ पढ़ी जाती है या नहीं, जैसी सोलह पंक्तियाँ हैं। native, label और code में एक साथ खोजें, पहले native दिखाएँ, और कोड सहेजें।
emails->translate अपने आप दोबारा नहीं आज़माया जाता। इसमें model कॉल ख़र्च होती हैं और यह कुछ लिखता नहीं, इसलिए idempotent बनाने को कुछ है ही नहीं और बिना उत्तर वाली रिक्वेस्ट के बाद का retry वही उत्तर दो बार ख़रीदने भर से ज़्यादा कुछ नहीं होता।
- जिस भाषा को API मिला न सके वह कुछ भी भेजे जाने से पहले
translate.toपरvalidation_errorहै। - 30,000 वर्णों से ज़्यादा पर
translation_too_long, जब इंस्टॉल में कोई AI कॉन्फ़िगर न हो तोtranslation_not_configured, जब वर्कस्पेस ने आज की AI कार्रवाइयाँ इस्तेमाल कर ली हों तो 429ai_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नए शब्दों को 409translation_lockedके साथ अस्वीकार करता है, इसलिए उसकी बात बदलने का मतलब है रद्द करके फिर से भेजना।
Attachments
नेटवर्क पर content base64 होता है। क्लाइंट को कुछ ऐसा दें जिसे वह पढ़ सके, और वह आपके लिए बाइट्स encode कर देता है: fopen का stream resource, SplFileInfo, या PSR-7 stream या अपलोड की गई फ़ाइल। स्ट्रिंग वैसी ही भेजी जाती है जैसी है, इसलिए उसे पहले से base64 होना चाहिए, और मेमोरी में रखे बाइट्स को OpenEmail::toBase64() यही बनाता है।
use OpenEmail\OpenEmail; $attachments = [ ['filename' => 'invoice.pdf', 'content' => OpenEmail::toBase64(file_get_contents('invoice.pdf')), 'contentType' => 'application/pdf'], ['filename' => 'report.csv', 'content' => new \SplFileInfo('report.csv')], ['filename' => 'contacts.csv', 'content' => fopen('contacts.csv', 'rb')], ['fileId' => 'file_6bb640f5b99e47deb758f1f5'],]; $client->emails->send([ 'from' => '[email protected]', 'to' => '[email protected]', 'subject' => 'Your documents', 'text' => 'All three are attached.', 'attachments' => $attachments,]);जो स्ट्रिंग content base64 नहीं है, वह कुछ भी भेजे जाने से पहले OpenEmail\Exception\InvalidArgumentException throw करता है। जो कच्चे बाइट्स संयोग से base64 जैसे पढ़े जाएँ, वे इसके बजाय बिगड़कर चले जाते, इसलिए किसी फ़ाइल के बाइट्स कभी वैसे ही पास न करें: उन्हें OpenEmail::toBase64() में लपेटें, या ख़ुद फ़ाइल पास करें।
अगर आपको यही encoding कहीं और चाहिए, तो OpenEmail::toBase64() मौजूद है। यह बाइट्स की स्ट्रिंग, stream resource, SplFileInfo या PSR-7 stream लेता है और बिना line break वाला base64 लौटाता है।