SDK
Отправить пакет
`emails.sendBatch`: до 100 сообщений, результат по каждому.
emails.sendBatch
const result = await openemail.emails.sendBatch(invoices.map(toMessage)) console.log(result.sent, 'sent,', result.failed, 'failed') for (const item of result.items) { if (item.status === 'error') console.error(item.index, item.error.code, item.error.message) else console.log(item.index, item.email.id)}items содержит по одной записи на каждый вход, по порядку, каждая либо ok со своим сообщением, либо error с конвертом, которым это сообщение было бы отклонено. Ничего не откатывается, так что failed > 0 — это список, с которым надо работать, а не повод переслать пакет заново.
Один ключ идемпотентности покрывает пакет, а сервер расширяет его по каждому элементу, так что повторённый пакет воспроизводит каждое сообщение, а не схлопывает их в первое.
Параметры: emails.sendBatch
emailsEmailSend[]обязательно- От одного до 100 сообщений, сериализуемых как `{ "emails": [...] }` и принимаемых по одному в заданном порядке. Пустой массив, больше 100 либо больше 10 элементов с `translate` отклоняют весь вызов с `validation_error` на `emails`. То же делают отсутствующая область доступа `emails:send`, тело, которое не является массивом или `{ emails: [...] }`, и некорректный `Idempotency-Key`, — всё это до отправки хотя бы одного сообщения.
options.idempotencyKeystring- Дедуплицирует пакет между процессами. Клиент в любом случае прикрепляет свежесозданный ключ при каждом вызове, так что его собственные повторы никогда не отправляют дважды, а сервер расширяет полученный ключ по каждому элементу как `key/0`, `key/1` и так далее — через слеш, символ, которого не может быть в вашем собственном ключе, — так что один ключ на сотню сообщений не может схлопнуть их в первое.
emails[].fromRecipientInputобязательно- Отправитель — голый адрес, `Name <addr@host>` или объект. Отправителя по умолчанию нет, и ключу должен быть разрешён этот адрес; отказ проваливает именно этот элемент как `permission_error` с кодом `from_address_forbidden`.
emails[].toRecipientInput | RecipientInput[]обязательно- Хотя бы один получатель, а одиночный клиент оборачивает в массив. Не более 50 адресов суммарно по `to`, `cc` и `bcc`, считая на сообщение, а не на весь пакет.
emails[].ccRecipientInput | RecipientInput[]- По умолчанию отсутствует и засчитывается в те же 50 адресов, что `to` и `bcc`.
emails[].bccRecipientInput | RecipientInput[]- По умолчанию отсутствует и засчитывается в те же 50 адресов. `Bcc` — одно из имён, которые `headers` задавать не может, так что это единственный способ отправить скрытую копию. Форма заголовка свела бы на нет отдельный конверт для каждого получателя, который и делает адрес скрытым.
emails[].replyToRecipientInput- Куда идут ответы. Применяется после `headers`, так что он перезаписывает `Reply-To`, который вы задали и там, а не добавляет второй.
emails[].subjectstring- Не длиннее 998 символов — предел строки по RFC 5322, — по умолчанию пустая строка. Пустая тема переходит к собственной теме шаблона, если `template` её даёт.
emails[].htmlstring- Часть HTML, не длиннее миллиона символов, и именно её видят получатели, когда заданы оба тела. Требуется одно из `html`, `text`, `template` или `draftId`, и элемент без них проваливается как `validation_error` на `html`.
emails[].textstring- Текстовая часть, не длиннее миллиона символов. Можно передать обе, но каждый транспорт на этом пути собирает одно тело из одной строки, так что при наличии `html` побеждает он.
emails[].headersRecord<string, string>- Только `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority и Feedback-ID; всё, что транспорт ставит сам (From, To, Bcc, Subject, Message-ID, заголовки DKIM и ARC), отклоняется как `reserved_header`, а не отбрасывается тихо. Значения не длиннее 998 символов и не могут содержать CR, LF или NUL, потому что вторая строка — это второй заголовок.
emails[].attachmentsAttachmentInput[]- Не более 20 файлов на сообщение, причём встроенные файлы в сумме не больше 5 МБ после декодирования, считая на сообщение, а не на пакет. `content` на проводе в base64; передайте байты, и клиент закодирует их сам, — это то самое место, где самодельный base64 надёжно переполняет стек вызовов. Запись `{ fileId }` называет файл, уже находящийся в рабочем пространстве, и в лимит встроенных файлов не засчитывается.
emails[].threadIdstring- Ответить в существующую цепочку, не длиннее 256 символов. Транспорт пишет из этого In-Reply-To и References, и именно это помещает ответ в переписку, а не рядом с ней.
emails[].draftIdstring- Отправить содержимое сохранённого черновика под этим конвертом, не длиннее 256 символов. На провод уходят получатели, тема и заголовки, собранные здесь.
emails[].template{ id, version?, props?, slots? }- Отрисовать сохранённый шаблон на сервере — по идентификатору (`tpl_…`) или slug, где `version` закрепляет ревизию, а `props`/`slots` её заполняют. Разрешается один раз, при приёме элемента, и отклоняется вместе с `html`/`text` и вместе с `draftId`, поскольку каждое из них — второй ответ на вопрос, что содержит сообщение.
emails[].scheduledAtDate | string- `Date`, момент в ISO-8601 или длительность вроде `PT1H`; не меньше секунды в будущем и не дальше 365 дней. Элементы планируются независимо, так что один пакет может содержать сотню разных моментов отправки.
emails[].cancellableForSecondsnumber- Окно отмены в секундах для немедленной отправки, целое от 0 до 900, по умолчанию 0. Любое значение выше 0 отклоняется вместе с `scheduledAt` в том же элементе, поскольку запланированное сообщение и так можно отменить до его ухода.
emails[].trackingTrackingRequest- `opens` и `clicks`, каждое независимо необязательно и каждое переопределяет настройку только для этого сообщения. Опущенный переключатель падает обратно к настройке адреса, с которого отправляется сообщение, либо к настройке для всех адресов, которая включена, если её кто-то не выключил.
emails[].tagsRecord<string, string>- Не более 10 меток: ключи от 1 до 64 символов из набора `A-Za-z0-9_-` и значения до 256. Возвращаются вместе с сообщением и никогда не интерпретируются: `emails.list` принимает `status`, `from`, `limit` и `cursor` и ничего больше, так что метка — это то, что читают у уже имеющегося сообщения, а не способ его найти.
emails[].translateSendTranslateOptions- Отправить этот элемент на другом языке, разрешается в момент приёма, чтобы ушли именно те слова, которые были одобрены. Не более 10 элементов одного пакета могут его нести: каждый тратит несколько вызовов модели, а элементы обрабатываются по порядку, так что более крупный пакет был бы прерван на середине отправки. Сверх этого весь вызов отклоняется как `too_many_items` на `emails`, до того как что-либо отправлено.
Ответ: BatchResultResource
itemsBatchItemResource[]- По одной записи на каждый вход, в том порядке, в котором вы их отправили. Ничего не откатывается, так что это протокол того, что случилось с каждым сообщением, а не отчёт о транзакции. API отвечает 207 независимо от того, приняты ли все сообщения, часть или ни одного, так что промис разрешается в любом случае, а ветвиться нужно по `status` каждого элемента.
sentnumber- Сколько элементов было ПРИНЯТО, что не то же самое, сколько ушло. Элемент может быть `ok` и при этом нести `email.status` со значением `failed` или `partial`, потому что транспорт, отказавший в сообщении после появления строки, — это исход доставки, а не отклонённый запрос.
failednumber- Сколько записей несут `error`. `failed > 0` — это список, с которым надо работать, а не повод переслать пакет заново. Принятые сообщения уже ушли.
items[].indexnumber- Позиция, которую сообщение этой записи занимало в отправленном вами массиве. Передаётся и как поле, и как порядок, чтобы код, фильтрующий или сортирующий `items`, всё равно мог сказать, какой вход провалился.
items[].status'ok' | 'error'- Дискриминант объединения: `ok` несёт `email`, `error` несёт `error`, и ни одна запись не несёт оба.
items[].emailSentEmailResource- Принятое сообщение — только в записи `ok`, в той же форме, что возвращает одиночная отправка. Оно не несёт ключа `tracking`, потому что вовлечённость сообщается позже, и в момент приёма сообщать нечего.
items[].email.replayedboolean- True, когда выведенный `Idempotency-Key` совпал с уже существовавшей отправкой, так что нового ничего не отправлено и это исходное сообщение.
items[].error{ type: string; code: string; message: string; param?: string }- Почему именно это сообщение было отклонено — только в записи `error`. Это конверт ошибки API минус `docUrl` и `requestId`: они описывают запрос, а запрос в целом удался.
items[].error.typestring- Категория, по которой клиент может ветвиться: `validation_error`, `permission_error`, `not_found_error`, `conflict_error` и остальные. Набор заморожен и расти не будет, в отличие от `code`.
items[].error.codestring- Конкретный сбой: `from_address_forbidden`, `invalid_email_address`, `too_many_recipients`, `reserved_header`, `message_too_large`, `unknown_parameter`. Набор открытый и пополняемый, так что неизвестный вам код трактуйте как его `type`.
items[].error.messagestring- Одно предложение, написанное для человека, называющее ошибочное значение, если оно есть. Не стабильный идентификатор. Переключайтесь по `code`.
items[].error.paramstring- Поле, которое было отклонено, как путь через точку ВНУТРИ ТОГО сообщения: `to.0`, `from`, `attachments`. Отсутствует, когда сбой не называет поля, и никогда не снабжается позицией в пакете — для этого есть `index`.