ارسالهای گروهی
`broadcasts->preview`، `send`، `list`، `listAll`، `iterate`، `get`، `listRecipients`، `listAllRecipients`، `iterateRecipients`، `getRecipient`، `stats`، `analytics` و `cancel`.
همهٔ متدها
use OpenEmail\Constants\BroadcastRecipientFilters;use OpenEmail\Constants\BroadcastStatuses; $draft = [ 'audienceIds' => ['aud_4c1b8e2a7d9f05c36b4e8a71'], 'from' => 'Acme <[email protected]>', 'subject' => '{{firstName|Hello}}, the September release is out', 'html' => '<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p>', 'text' => 'Hi {{firstName|there}}, here is what changed this month. Unsubscribe: {{unsubscribeUrl}}', 'tags' => ['campaign' => 'release-2026-09'],]; $reach = $client->broadcasts->preview($draft);echo $reach['recipients'], ' ', $reach['unsubscribed'], ' ', $reach['suppressed'], PHP_EOL; $broadcast = $client->broadcasts->send($draft); $latest = $client->broadcasts->get($broadcast['id']); while (in_array($latest['status'], [BroadcastStatuses::SCHEDULED, BroadcastStatuses::QUEUED, BroadcastStatuses::SENDING], true)) { sleep(5); $latest = $client->broadcasts->get($broadcast['id']);} foreach ($client->broadcasts->iterateRecipients($broadcast['id']) as $copy) { echo $copy['email'], ' ', $copy['status'], ' ', $copy['opens'], ' ', $copy['clicks'], PHP_EOL;} $bounced = $client->broadcasts->listRecipients($broadcast['id'], filter: BroadcastRecipientFilters::BOUNCED); foreach ($bounced as $row) { echo $row['emailId'], ' ', $row['email'], PHP_EOL;} $copy = $client->broadcasts->getRecipient($broadcast['id'], 'msg_01dad25067bc4dac966d515d');echo $copy['subject'], ' ', $copy['bouncedAt'] ?? 'not bounced', PHP_EOL; $stats = $client->broadcasts->stats($broadcast['id'], grain: 'day');echo $stats['totals']['opened'], ' ', $stats['totals']['clicked'], ' ', $stats['totals']['unsubscribed'], PHP_EOL; $lately = $client->broadcasts->stats($broadcast['id'], days: 1);echo $lately['window']['opened'] ?? 0, PHP_EOL; $later = $client->broadcasts->send([...$draft, 'scheduledAt' => 'P1D']);$client->broadcasts->cancel($later['id']); $history = $client->broadcasts->list(audienceId: $draft['audienceIds'][0]);echo $latest['status'], ' ', $latest['counts']['sent'], ' ', count($history), PHP_EOL; $month = $client->broadcasts->analytics(days: 30); foreach ($month['broadcasts'] as $row) { echo $row['subject'], ' ', $row['sent'], ' ', $row['opened'], PHP_EOL;}ارسال گروهی یک پیام را برای همهٔ افراد یک یا چند گروه مخاطب میفرستد، به شکل نسخهای جدا برای هر نفر. هر نسخه دقیقاً یک گیرنده دارد و cc یا bcc ندارد، پس هیچکس نمیبیند برای چه کس دیگری رفته، و هر نسخه ایمیلی معمولی است با شناسهٔ msg_، رویدادها، ردیابی و وبهوکهای خودش. listRecipients آنها را همراه با آنچه بر سر هر کدام آمد فهرست میکند. نسخهها در پوشهٔ «ارسالشده» بایگانی نمیشوند، چون ارسال گروهی سابقه است.
send بیدرنگ با ارسال گروهی در حالت queued، یا scheduled وقتی بدنه scheduledAt داشته باشد، برمیگردد و ارسال در پسزمینه ادامه مییابد. send به emails:send و audiences:read نیاز دارد، و preview به audiences:read. list، listAll، iterate، get، listRecipients، listAllRecipients، iterateRecipients، getRecipient، stats و analytics به emails:read نیاز دارند، و cancel به emails:send.
هر send یک Idempotency-Key دارد، کلید شما از راه idempotencyKey: یا کلیدی که کلاینت میسازد، پس تلاش دوباره پس از شکست شبکه بهجای دو بار فرستادن، با ارسال گروهیای که تلاش نخست ساخته پاسخ میدهد، با replayed برابر true. preview، get، cancel و همهٔ خواندنها را میتوان بیخطر تکرار کرد و دوباره تلاش میشوند.
$broadcast = $client->broadcasts->send([ 'audienceIds' => ['aud_4c1b8e2a7d9f05c36b4e8a71'], 'from' => 'Acme <[email protected]>', 'subject' => 'Doors open on Friday', 'text' => 'Hi {{firstName|there}}, doors open at nine. Unsubscribe: {{unsubscribeUrl}}', 'scheduledAt' => new \DateTimeImmutable('+1 hour'),], idempotencyKey: 'doors-open-2026-10'); echo $broadcast['id'], ' ', $broadcast['status'], ' ', $broadcast['replayed'] ? 'replayed' : 'new', PHP_EOL;فیلدهای یک ارسال گروهی کلیدهای یک آرایه با نامهای camelCase در API هستند (audienceIds، scheduledAt). idempotencyKey: و apiKey: آرگومانهای نامدار فراخوانیاند و هرگز بهصورت فیلد فرستاده نمیشوند. باز کردن یک پیشنویس در یک آرایهٔ تازه در کنار یک فیلد، همان پیشنویس را با همان یک تغییر میفرستد، پس send([...$draft, 'scheduledAt' => 'P1D']) آن را یک روز بعد میفرستد. scheduledAt یک DateTimeInterface، یک رشتهٔ ISO 8601 یا مدتی مانند PT2H میگیرد، و DateTimeInterface بهصورت یک لحظهٔ UTC فرستاده میشود. preview از آنچه به آن میدهید فقط audienceIds را میفرستد، پس همان آرایهٔ send را میپذیرد. پاسخ یک آرایه با کلیدهای camelCase است، پس $broadcast['status'] وضعیت را میخواند.
فیلدهای ادغام
subject، html و text برای هر نفر از روی مخاطبش پر میشوند. {{firstName}} نخستین واژهٔ نام مخاطب است، {{lastName}} بقیهٔ آن، {{name}} نام کامل، {{email}} نشانیای که نسخه به آن میرود و {{unsubscribeUrl}} پیوندی که اشتراکش را لغو میکند.
هر فیلد پس از یک خط یک مقدار جایگزین میپذیرد که وقتی مخاطب مقداری برای آن ندارد به کار میرود، پس {{firstName|there}} برای مخاطبی که بینام ذخیره شده "there" میشود. مقدارها در html گریزانده میشوند و هر {{…}} دیگری دقیقاً همانطور که نوشته شده میماند.
برای فرستادن یک قالب ذخیرهشده، template را بهجای html و text بدهید، بهصورت یک آرایه با id و بهطور اختیاری version، props و slots. همان پنج مقدار به شکل prop به آن میرسند، ولی فقط propهایی که قالب اعلام میکند، پس قالبی که firstName را اعلام کند آن را میگیرد و قالبی که اعلام نکند هرگز به خاطرش رد نمیشود. هر چه در props آن باشد برای همهٔ نسخهها یکسان میرود.
لغو اشتراک
هر نسخه سرآیندهای لغو اشتراک با یک کلیک را دارد که به برنامهٔ ایمیل اجازه میدهند دکمهٔ لغو اشتراکِ خودش را نشان دهد، چیزی که ارائهدهندگان بزرگ صندوق ایمیل از ایمیل انبوه میخواهند. متن html یا text که خودش {{unsubscribeUrl}} را نگذارد یک پانویس یکخطی با پیوند میگیرد. قالب دقیقاً همانطور که هست فرستاده میشود، پس {{unsubscribeUrl}} را در قالب بگذارید.
لغو اشتراک، فرد را در همهٔ گروههایی که آن ارسال گروهی برایشان رفته لغواشتراککرده علامت میزند، و audiences->listContacts آن را در unsubscribedAt ردیف او نشان میدهد، همانطور که صفحهٔ «گروههای مخاطب» توضیح میدهد. او در گروه و در دفترچهٔ نشانیها میماند، گروههای دیگرش دست نمیخورند، و ایمیلی که تکتک برایش فرستاده میشود همچنان میرود. بیرون آوردن او از گروه و افزودن دوبارهاش او را از نو مشترک میکند.
چه کسانی رد میشوند
ارسال گروهی به هر مخاطبی میرسد که دستکم در یکی از audienceIds باشد، یک بار هر چند تا که او را داشته باشند. از مخاطبی که از همهٔ آن گروههایی که در آنهاست لغو اشتراک کرده، و از نشانیای که پس از برگشت یا شکایت، یا چون کسی آن را افزوده، در فهرست توقیف است رد میشود. مخاطبی که پس از send ولی پیش از رسیدن ارسال به او به یکی از گروهها افزوده شود، دریافت میکند.
preview همان عددها را بدون ارسال برمیگرداند: recipients، unsubscribed و suppressed. sendی که به هیچکس نرسد 422 no_recipients را بهصورت ValidationException پرتاب میکند.
کل ارسال پیش از نوشتن هر چیزی با سهمیهٔ ماهانهٔ ارسال در طرح سنجیده میشود، پس ارسال گروهیای که سهمیه پوشش ندهد 429 send_quota_exceeded را بهصورت RateLimitException پرتاب میکند و چیزی از خود به جا نمیگذارد. هر نسخه یک ارسال حساب میشود.
وضعیت و پیشرفت
get مقدار counts را زنده از نسخهها میخواند، پس در طول ارسال آن را پیاپی بخوانید، با sleep() میان فراخوانیها همانطور که نمونهٔ بالا انجام میدهد. status از scheduled یا queued به sending میرود و وقتی هر نسخهٔ سپردهشده رفته یا ناموفق شده روی sent میایستد. تا وقتی نسخهها هنوز منتظرند sending میماند، حتی پس از آنکه completedAt بگوید به آخرین نفر رسیده. failed یعنی کل ارسال گروهی متوقف شده و lastError دلیلش را میگوید: دیگر نمیشود از نشانی from فرستاد، قالب دیگر بارگذاری نمیشود، طرح در میانهٔ راه تمام شد، خودِ ارسال پیاپی ناموفق ماند، یا حتی یک نسخه هم نوشته نشد.
cancel ارسال گروهیای را که scheduled، queued یا sending است متوقف میکند. کسی دیگر افزوده نمیشود و هر نسخهای که هنوز منتظر است لغو میشود، در حالی که نسخههای رفته برگرداندنی نیستند. وقتی همهٔ نسخهها رفته باشند، cancel خطای 409 broadcast_not_cancellable را بهصورت ConflictException پرتاب میکند، و لغو یک ارسال گروهیِ لغوشده آن را با همان حالتی که هست برمیگرداند.
به چه کسانی رسید
listRecipients یک OpenEmail\Result\Page از کسانی که ارسال گروهی برایشان رفت برمیگرداند، یک ردیف برای هر نسخه، مرتبشده بر اساس نشانی، با items، hasMore و nextCursor. listAllRecipients همهٔ صفحهها را در یک آرایه میپیماید، و iterateRecipients یک Generator برمیگرداند که هر بار یک نسخه را yield میکند و صفحهٔ بعد را فقط وقتی حلقه بخواهد میگیرد. limit: از 1 تا 200 است با پیشفرض 50، و cursor: با همان filter: و q: پس داده میشود.
| `filter:` | نگه میدارد |
|---|---|
| pending | نسخههایی که هنوز در صف، زمانبندیشده یا در حال ارسالاند. |
| sent | نسخههایی که فرستاده شدند. |
| delivered | نسخههایی که سرور گیرنده پذیرفت. |
| opened | نسخههایی که دستکم یک بار باز شدند. |
| not_opened | نسخههایی که فرستاده شدند و هرگز باز نشدند. |
| clicked | نسخههایی با دستکم یک کلیک ردیابیشده. |
| bounced | نسخههایی که برگشت خوردند. |
| complained | نسخههایی که آن شخص به عنوان هرزنامه گزارش کرد. |
| failed | نسخههایی که ناموفق بودند یا لغو شدند. |
| unsubscribed | افرادی که پس از ارسال گروهی لغو اشتراک کردند. |
OpenEmail\Constants\BroadcastRecipientFilters هر فیلتر را نام میبرد، و q: نشانی و نام را بدون توجه به بزرگی و کوچکی حروف جستوجو میکند. باز کردنها و کلیکها پراکسیهای تصویر و اسکنرهای پیوند را کنار میگذارند، و وقتی ارسال گروهی با ردیابی خاموش رفته باشد 0 میمانند.
getRecipient($id, $emailId) یک نسخه را برمیگرداند: همان ردیف، بهعلاوهٔ subject، html و text دقیقاً همانطور که آن شخص دریافت کرد، با فیلدهای ادغامِ پرشده و پیوند لغو اشتراک مخصوص خودش. emailId یک ردیف را بهعنوان آرگومان دوم بدهید. HTML مربوط به پیش از افزودن ردیابی باز کردن و کلیک است. emailIdی که نسخهای از این ارسال گروهی نیست یک 404 recipient_not_found پرتاب میکند، و ارسال گروهی ناشناخته یک 404 broadcast_not_found، هر دو بهصورت NotFoundException.
stats مجموعها و یک سری را برمیگرداند. totals نسخههای sent، delivered، bounced، complained و failed را میشمارد، با pending برای آنهایی که هنوز در انتظارند، و افرادی را که opened، clicked و unsubscribed شدند، با opens و clicks بهعنوان شمار رویدادها. series پراکنده است و قدیمیترین اول، یک بازه برای هر grain: (minute، hour یا day، با پیشفرض hour) که در آن چیزی رخ داده، بریدهشده در منطقهٔ زمانیای که offsetMinutes: دقیقه در شرق UTC است. برای منطقهٔ زمانی محلی intdiv((int) date('Z'), 60) را بدهید. هر کس را یک بار میشمارد، در نخستین باری که برایش رخ داد، پس جمعش با مجموعها برابر میشود.
برای اینکه آنچه اخیراً رخ داده را هم بخوانید، days: یا minutes: را به stats بدهید. آنگاه window آنچه را درون آن تحویل شده، برگشت خورده، هرزنامه گزارش شده، باز شده، کلیک شده و لغو اشتراک شده میشمارد، و series فقط بازههای همان پنجره را نگه میدارد، در حالی که totals همچنان کل ارسال گروهی را در بر میگیرد. بدون هیچکدام، window برابر null است.
کلیدی که به نشانیها یا دامنههای خاصی محدود است فقط به ارسالهای گروهیای دسترسی دارد که از نشانی یا دامنهای که دارد فرستاده شدهاند. list، listAll و iterate بقیه را کنار میگذارند، و get، متدهای گیرندگان، stats و cancel برای آنها 404 broadcast_not_found را پرتاب میکنند.
پاسخ: یک ارسال گروهی
send، get و cancel هرکدام یکی از اینها را بهصورت یک آرایه با کلیدهای camelCase برمیگردانند، و send مقدار replayed را هم میافزاید. list یک OpenEmail\Result\Page از آنها برمیگرداند، تازهترین اول، listAll همه را در یک آرایه برمیگرداند و iterate یک Generator روی آنها برمیگرداند. preview یک آرایه با audienceIds، recipients، unsubscribed و suppressed برمیگرداند. listRecipients یک Page از ردیفهای گیرنده برمیگرداند، getRecipient یک ردیف را همراه محتوایش برمیگرداند، و stats یک آرایه با broadcastId، grain، totals، window و series برمیگرداند. analytics یک آرایه با totals، series و یک ردیف برای هر ارسال گروهی در broadcasts برمیگرداند. زمانها رشتههایی با قالب ISO 8601 هستند که new \DateTimeImmutable() آنها را میخواند.
idstring- شناسهٔ ماندگار، `brd_` و پس از آن ۲۴ نویسهٔ هگزادسیمال.
statusstring- `scheduled`، `queued`، `sending`، `sent`، `cancelled` یا `failed`. `OpenEmail\Constants\BroadcastStatuses` هرکدام را نام میبرد.
modestring- `live` یا `test`، بسته به کلیدی که آن را ساخته. نسخههای ارسال گروهیِ آزمایشی ارسالشده علامت میخورند و به هیچکس تحویل داده نمیشوند.
sourcestring- از کجا شروع شده: `api` برای کلید، `oauth` برای برنامهٔ متصل، `composer` برای خود برنامه، `mcp` برای دستیار.
audienceIdsarray- گروههایی که برایشان فرستاده شده، هر کدام یک بار.
fromstring- نشانیای که هر نسخه از آن فرستاده میشود.
subjectstring- موضوع همانطور که نوشته شده، با فیلدهای ادغام. خالی وقتی قالب موضوع را میدهد.
countsarray- `recipients` تخمینی است که هنگام `send` گرفته شده. `created` نسخههای نوشتهشده را میشمارد، `skipped` کسانی را که چون نشانیشان تا آن موقع توقیف بود کنار گذاشته شدند، و `failedToQueue` کسانی را که نسخهشان نوشته نشد. `queued`، `sending`، `sent`، `failed` و `cancelled` نسخهها را بر اساس وضعیتی که هر کدام الان دارد میشمارند.
lastErrorstring or null- اینکه ارسال گروهی چرا ناموفق شد، یا تازهترین نسخهای که نوشته نشد و چرا. تا وقتی مشکلی پیش نیامده null است.
scheduledAtstring or null- ISO-8601 به وقت UTC، زمانی که ارسال باید شروع شود. برای ارسال گروهیای که بیدرنگ فرستاده شده null است.
startedAtstring or null- ISO-8601 UTC، زمانی که ارسال به نخستین افراد رسید.
completedAtstring or null- ISO-8601 UTC، زمانی که به آخرین نفر رسید. پس از آن هنوز ممکن است نسخههایی منتظر رفتن باشند.
cancelledAtstring or null- ISO-8601 UTC، زمانی که `cancel` آن را متوقف کرد.
createdAtstring- ISO-8601 UTC، زمانی که `send` فراخوانده شد. ترتیب فهرست را تعیین میکند.
updatedAtstring- ISO-8601 UTC، با پیشرفت ارسال بهروز میشود.
پاسخ: یک ردیف گیرنده
هر ردیف listRecipients، listAllRecipients و iterateRecipients، بهصورت یک آرایه با کلیدهای camelCase. آرایهای که getRecipient برمیگرداند subject، html و text را هم میافزاید.
emailIdstring- شناسهٔ `msg_` نسخهٔ این شخص. `getRecipient` آن را همراه محتوایش میخواند، و `emails->get` آن را بهعنوان یک ایمیل ارسالشده میخواند، همانطور که صفحهٔ «فهرست و دریافت» توضیح میدهد.
contactIdstring or null- مخاطبی که نسخه برایش رفت، یا null وقتی مخاطب از آن پس حذف شده باشد.
emailstring- نشانیای که نسخه به آن رفت.
namestring or null- نام روی مخاطب.
statusstring- وضعیت نسخه: `queued`، `scheduled`، `sending`، `sent`، `failed` یا `cancelled`.
sentAtstring or null- ISO-8601 UTC، زمانی که نسخه فرستاده شد.
deliveredAtstring or null- ISO-8601 UTC، زمانی که سرور گیرنده آن را پذیرفت، نخستین `email.delivered`.
bouncedAtstring or null- ISO-8601 UTC، زمانی که برگشت خورد، نخستین `email.bounced`.
complainedAtstring or null- ISO-8601 UTC، زمانی که آن شخص آن را به عنوان هرزنامه گزارش کرد، نخستین `email.complained`.
failurestring or null- دلیل ناموفق بودن نسخه، اگر ناموفق بود.
opensint- باز کردنهای ثبتشده، بدون آنهایی که پراکسیهای تصویر و اسکنرها ایجاد میکنند. وقتی ردیابی خاموش بود 0 است.
firstOpenAtstring or null- ISO-8601 UTC، نخستین باز کردن.
clicksint- کلیکهای ثبتشده روی لینکهای ردیابیشده، بدون اسکنرها.
firstClickAtstring or null- ISO-8601 UTC، نخستین کلیک.
unsubscribedAtstring or null- ISO-8601 به وقت UTC، زمانی که این شخص پس از ارسال، از راه پیوند آن یا به هر راه دیگری، از یکی از گروههای مخاطب ارسال گروهی لغو اشتراک کرد.