پرش به مستندات
PHP

ارسال یک ایمیل

`emails->send`: یک پیام، حالا یا بعداً.

emails->send

send_email.php
$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 درخواست را می‌پذیرد ترجمه می‌شود، و آنچه بیرون آمد همان است که بیرون می‌رود: ترجمه‌ای که نشود تولیدش کرد، به‌جای فرستادن پیام به زبانی که نوشته‌اید، ارسال را رد می‌کند.

translate.php
$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_translation.php
$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'],    ]);}
languages.php
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 پیکربندی‌شده‌ای ندارد، یک 429 ai_quota_exceeded وقتی آن فضای کاری کنش‌های هوش مصنوعی امروز را مصرف کرده باشد (در نیمه‌شب UTC بازنشانی می‌شود و دوباره تلاش نمی‌شود)، translation_failed وقتی ارائه‌دهنده پاسخ نداده است. هیچ‌کدام به‌عنوان جایگزین، پیام را ترجمه‌نشده نمی‌فرستند.
  • با template کار می‌کند: آنچه ترجمه می‌شود خروجیِ RENDER شده است، پس یک بدنهٔ ذخیره‌شده به هر زبانی که مشتریانتان می‌خوانند خدمت می‌کند. قالبی که یک سند کامل رندر می‌کند، doctype، بلوک‌های <style> و قاعده‌های @font-face خود را نگه می‌دارد: فقط بدنه به مدل می‌رود و بقیه دوباره دورش گذاشته می‌شود. <title> آن دست‌نخورده می‌ماند، که به‌هرحال چیزی نمایشش نمی‌دهد.
  • تلاش دوباره هزینهٔ اضافه ندارد. ترجمه بخشی از اثرانگشت idempotency نیست (خودِ درخواست هست، با translate و همه)، پس بازفرستادن یک ارسال بی‌پاسخ با همان Idempotency-Key پیامی را که از پیش وجود دارد بازپخش می‌کند، نه اینکه بار دوم ترجمه و ارسال کند.
  • پیام ترجمه‌شده‌ای که queued یا scheduled باشد متن تأییدشده‌اش را نگه می‌دارد. emails->reschedule هنوز جابه‌جایش می‌کند، در حالی که emails->update متن تازه را با یک 409 translation_locked رد می‌کند، پس تغییر آنچه می‌گوید یعنی لغو و ارسال دوباره.

پیوست‌ها

content روی سیم base64 است. چیزی را که کلاینت بتواند بخواند به آن بدهید تا بایت‌ها را برایتان کدگذاری کند: یک منبع stream از fopen، یک SplFileInfo، یا یک stream یا فایل بارگذاری‌شدهٔ PSR-7. یک رشته همان‌طور که هست فرستاده می‌شود، پس باید از پیش base64 باشد، و OpenEmail::toBase64() همین را از بایت‌هایی که در حافظه دارید می‌سازد.

attachments.php
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 بدون شکست خط برمی‌گرداند.