ارسال یک ایمیل
`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 باشد.
پیام یک آرایه است که کلیدهایش نام فیلدهای API هستند، و به همین دلیل replyTo و scheduledAt به شکل camelCase میمانند، در حالی که idempotencyKey: و apiKey: آرگومانهای نامدار فراخوانیاند و هرگز بخشی از پیام نیستند. برای تغییر یک فیلد از پیامی که پیشتر ساختهاید، آن را در یک آرایهٔ تازه باز کنید: $client->emails->send([...$message, 'subject' => 'Re: your invoice']) همهٔ فیلدهای دیگر را نگه میدارد و موضوع را جایگزین میکند.
پارامترها
fromstring or arrayالزامی- فرستنده. یک نشانی خام، `Name <addr@host>` یا یک آرایه با `email` و `name`. باید نشانیای باشد که این کلید اجازهٔ ارسال با آن را دارد، وگرنه فراخوانی یک 403 `from_address_forbidden` را پرتاب میکند. هیچ فرستندهٔ جایگزینی وجود ندارد، پس هر ارسال همیشه نشانیای را که از آن فرستاده میشود نام میبرد.
tostring or arrayالزامی- یک گیرنده یا فهرستی از گیرندگان، و اگر یکی تنها بدهید برایتان در فهرست پیچیده میشود. حداکثر 50 نشانی روی هم در `to`، `cc` و `bcc`، و بیشتر از آن یک 422 `too_many_recipients` است.
ccstring or array- به سقف 50 گیرنده شمرده میشود.
bccstring or array- هرگز در بایتهایی که دیگران دریافت میکنند نام برده نمیشود، چون به ازای هر گیرنده یک پاکت منتقل میشود. در شمار همان 50 هم حساب میشود.
replyTostring or array- یک نشانی تکی، که به شکل هدر Reply-To فرستاده میشود.
subjectstring- حداکثر 998 نویسه، همان حد طول خط RFC 5322. پیشفرض خالی است، و موضوع خالی به موضوع قالب یا پیشنویس بازمیگردد.
htmlstring- یکی از `html`، `text`، `draftId` یا `template` الزامی است. وقتی هر دو `html` و `text` داده شوند، آنچه گیرندگان میبینند HTML است. حداکثر 1,000,000 نویسه.
textstring- بخش متن ساده، حداکثر 1,000,000 نویسه.
templatearray- یک قالب ذخیرهشده را سمت سرور رندر میکند: یک آرایه با `id`، که شناسه یا slug میگیرد، و `version` اختیاری (یک int)، `props` و `slots`. `version` یک نسخه را سنجاق میکند. آن را ننویسید تا هرچه هنگام پذیرش درخواست منتشر شده باشد به کار رود. prop ناشناخته یا نیامده، بهجای جای خالی در پیام، یک 422 است.
draftIdstring- یک پیشنویس ذخیرهشده را همانطور که نوشته شده، زیر این پاکت بفرستید. نمیتوان آن را با `template` یا `translate` ترکیب کرد.
headersarray- نام سرآیند به مقدار رشتهای، محدود به `X-*`، `List-*`، Reply-To، Precedence، Auto-Submitted، Importance، Priority و Feedback-ID. هر چیزی که خودِ لایهٔ انتقال تنظیم میکند، بهجای حذف بیسروصدا، با یک 422 `reserved_header` رد میشود.
attachmentsarray- یک فهرست، که هر مورد آن آرایهای با `filename`، `content` و `contentType` اختیاری است، یا آرایهای فقط با `fileId` که فایلی را نام میبرد که از پیش در فضای کاری هست، مثلاً فایلی از `files->upload`. `content` با base64 است: یک stream از `fopen`، یک `SplFileInfo` یا یک stream از نوع PSR-7 برایتان خوانده و کدگذاری میشود، و یک رشته باید از پیش base64 باشد. 20 فایل، با سقف مجموع 5 MB برای فایلهای درونخطی پس از رمزگشایی. فایل ذخیرهشده میتواند بزرگتر باشد و به شکل پیوند دانلود میرود.
attachmentDeliverystring- `mime`، `link` یا `auto`. `auto` فایلها را وقتی روی دامنهای با files domain فعال از 2 MB بگذرند به شکل پیوند دانلود میبرد و در غیر این صورت درون پیام. اگر ننویسید، تنظیم صندوق اعمال میشود، که پیشفرضش `auto` است.
threadIdstring- پاسخدادن درون یک thread موجود. حملونقل In-Reply-To و References را مینویسد.
scheduledAtDateTimeInterface or string- یک `DateTimeInterface` که بهصورت یک لحظهٔ ISO 8601 با UTC فرستاده میشود، یک لحظهٔ ISO 8601 بهصورت رشته، یا مدتی مانند `PT1H`. تا یک سال بعد، هرگز در گذشته. نمیتوان آن را با `cancellableForSeconds` ترکیب کرد. رشتهٔ تاریخی بدون ساعت، مانند `2027-01-01`، نیمهشب UTC همان روز خوانده میشود، پس وقتی ساعت مهم است یک لحظه بدهید.
cancellableForSecondsint- 0 تا 900. پنجرهٔ لغو روی یک ارسال فوری: همان سازوکار لغوِ composer، که بهجای hardcode شدن در دسترس گذاشته شده است.
tagsarray- حداکثر 10 برچسب، با کلیدهای 1 تا 64 نویسه از حروف، ارقام، `_` یا `-` و مقدارهای رشتهای تا 256 نویسه. در هر خواندن همانطور بازگردانده میشوند و هرگز تفسیر نمیشوند.
signaturebool- اینکه این پیام امضای نشانی فرستنده را داشته باشد یا نه: امضای خودِ آن نشانی، وگرنه امضای catch-all برای نشانیای که catch-all دریافت کرده، وگرنه پانویس OpenEmail، مگر اینکه آن نشانی خاموشش کرده باشد. اگر مشخص نشود، بدنهٔ `html` دقیقاً همانطور که نوشته شده و بدون امضا میرود و بدنهٔ فقط `text` آن را دارد. برای نامهای که برنامهای از طرف کسی میفرستد، مثل رسید، بازنشانی گذرواژه یا خلاصه، false بگذارید، چون هیچکدام امضای یک شخص را زیر خود نمیخواهند. ارسالهای قالبی و ارسالهای رمزگذاریشده هرگز امضا ندارند.
trackingarray- یک آرایه با `opens` و `clicks` اختیاری، هرکدام یک bool: اینکه آیا برای این پیام pixel باز شدن افزوده و پیوندها بازنویسی شوند یا نه. خاموش است مگر ردیابی برای نشانیای که پیام از آن میرود (یا catch-allی که آن را گرفته) روشن شده باشد، و هر یک از این دو کلید که اینجا بیاید تکلیف همان یک پیام را، هرطور که نشانی تنظیم شده باشد، روشن میکند.
translatearray- آن را به زبان گیرنده بفرستید: یک آرایه با `to` و `from`، `subject` و `includeOriginal` اختیاری. `to` یک کد، یک نام انگلیسی یا نام خودِ زبان میگیرد، و `subject` و `includeOriginal` هر دو پیشفرض true دارند. هنگام پذیرفتهشدن درخواست تعیین میشود، پس پیام زمانبندیشده همان کلماتی را میبرد که تأیید شدهاند. در کنار `draftId` رد میشود.
idempotencyKeystring- آرگومان نامدار فراخوانی، نه فیلدی از پیام. کلید خودتان برای این ارسال، 1 تا 255 نویسه از حروف، ارقام، `_`، `.`، `:` یا `-`. بدون آن، کلاینت برای هر فراخوانی کلیدی تولید میکند، پس تلاشهای دوبارهٔ خودش هرگز دو بار نمیفرستند، و با آن، ارسالی که در فرایندی دیگر دوباره اجرا شود بهجای تکرار، بازپخش میشود.
apiKeystring- این هم آرگومان نامدار است. بهجای کلید کلاینت با این کلید میفرستد، برای فرایندی که از طرف چند فضای کاری ارسال میکند.
پاسخ
آرایهای که کلیدهایش نامهای camelCase در API هستند، پس $email['status'] وضعیت را میخواند.
idstring- شناسهٔ ارسال، `msg_` و به دنبالش 24 نویسهٔ hex. برای `get`، `cancel`، `reschedule` و `getTracking` از آن استفاده کنید.
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 null- همانطور که فرستاده شد.
messageIdstring or null- همان Message-ID مربوط به RFC 5322. تا وقتی MIME وجود نداشته باشد null است. سرویس ارسال سرآیند را در مسیر خروج بازنویسی میکند، پس هیچ bounce یا گزارش تحویلی این مقدار را حمل نمیکند. چیزی که رویداد با آن برمیگردد `id` است.
threadIdstring or null- thread ای که در آن نشست.
transportstring or null- پیام چگونه رفت. تا پیش از ارسال null است.
attemptsint- چند بار ارسال تلاش شده است.
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 با ارسالی که از پیش وجود داشته مطابقت کرده باشد. چیز تازهای فرستاده نشده، و این همان پیام اصلی در وضعیت کنونیاش است.
translationarray- فقط روی پیامی حاضر است که ترجمه شده، و تنها جایی که کل درخواست ذخیرهشده حمل میشود: همین پاسخ و `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'],]); 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، پس میشود یک picker را پیش از نخستین درخواست پر کرد. languages->list همان ردیفها را از روی سیم به شکل یک فهرست ساده برمیگرداند، برای فراخوانندهای که ردیفهای کنونی را به ردیفهایی که این نسخه با آنها عرضه شده ترجیح میدهد. OpenEmail::resolveLanguage() یک کد، یک نام انگلیسی، یک نام بومی یا یک نام مستعار میگیرد (zh-TW نام مستعار کدی است که دیگر فهرست نمیشود) و وقتی چیزی مطابقت نکند null برمیگرداند، OpenEmail::languageByCode() کد را دقیقاً و بدون حساسیت به بزرگی و کوچکی حروف تطبیق میدهد، و OpenEmail::isRtlLanguage() میگوید آیا یک زبان از راست به چپ خوانده میشود، همانطور که شانزده ردیف چنیناند. 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 است. چیزی را که کلاینت بتواند بخواند به آن بدهید تا بایتها را برایتان کدگذاری کند: یک منبع stream از fopen، یک SplFileInfo، یا یک stream یا فایل بارگذاریشدهٔ PSR-7. یک رشته همانطور که هست فرستاده میشود، پس باید از پیش 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 را پرتاب میکند. بایتهای خامی که از قضا بهصورت base64 خوانده شوند در عوض درهمریخته میروند، پس هرگز بایتهای یک فایل را همانطور که هست ندهید: آنها را در OpenEmail::toBase64() بپیچید، یا خودِ فایل را بدهید.
اگر همین کدگذاری را جای دیگری لازم دارید، OpenEmail::toBase64() هست. یک رشتهٔ بایتی، یک منبع stream، یک SplFileInfo یا یک stream از نوع PSR-7 میگیرد و base64 بدون شکست خط برمیگرداند.