Планирование и отмена
`scheduledAt`, `emails.reschedule`, `emails.update` и `emails.cancel`.
Отправка позже
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} client.emails.send(message, scheduledAt: "PT1H")client.emails.send(message, scheduledAt: Time.utc(2027, 1, 1, 9))client.emails.send(message, scheduledAt: "2027-01-01T09:00:00.000Z")Time или DateTime, момент ISO 8601 в виде String или длительность вроде PT1H или P2D. Не дальше чем на год вперёд и никогда в прошлом. Именованный аргумент рядом с Hash добавляет поле к сообщению, собранному ранее.
Date из Ruby отправляется как голая дата вроде 2027-01-01, которую API читает как полночь UTC в этот день. Передавайте Time, например Time.utc(2027, 1, 1, 9), когда важен час.
Перенос и остановка
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} queued = client.emails.send(message, scheduledAt: "PT1H") client.emails.reschedule(queued[:id], Time.now + 86_400)client.emails.cancel(queued[:id])Остановить можно только сообщения в состоянии queued и scheduled. Для всего, что продвинулось дальше, выбрасывается OpenEmail::ConflictError, потому что часть уже лежит в чьём-то почтовом ящике. Отмена уже отменённого сообщения проходит успешно и ничего не меняет.
Чтобы найти, что ждёт отправки в определённом окне, запросите список с status: ["scheduled", "queued"], scheduled_from: и scheduled_to:, как это делает календарь приложения.
Изменение до отправки
emails.update меняет сообщение, которое ещё не ушло: когда оно уйдёт (через scheduledAt), что в нём сказано (через subject, html и text), от имени какого адреса оно уйдёт (через from) и кому (через to, cc и bcc). Передавайте любые из них вместе, а поле, которое вы не указали, сохраняет своё значение. Список получателей заменяет сохранённый целиком. Именно это делает редактирование запланированного сообщения в календаре приложения.
updated = client.emails.update( "msg_3f9a1c07d2b84e6a9c5b1f20", subject: "Your September invoice, corrected", to: ["[email protected]", "[email protected]"], scheduledAt: Time.utc(2026, 10, 5, 8)) puts updated[:status], updated[:subject], updated[:scheduledAt]from проверяется так же, как при отправке, поэтому это должен быть адрес, от имени которого ключу разрешено отправлять. Сообщение, переведённое при принятии, сохраняет одобренный текст, поэтому новый subject, html или text для него даёт 409 translation_locked, а сообщение, зашифрованное до планирования, сохраняет и текст, и получателей. Такие сообщения вместо этого отмените и отправьте заново.
Окно отмены вместо этого
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} held = client.emails.send(message, cancellableForSeconds: 30) puts held[:status], held[:cancellableUntil]Запланированное сообщение и так можно отменить до его ухода, поэтому эти два нельзя сочетать, и сервер это отклоняет. Используйте это для окна отмены у немедленного сообщения.
Параметры: планирование
scheduledAtTime, DateTime or String- Когда отправить, в `emails.send`: Time или DateTime, момент ISO 8601 в виде String или длительность вроде `PT1H` или `P2D`. Time или DateTime отправляется как момент в UTC, String как есть, а Date из Ruby как голая дата, означающая полночь UTC. Не раньше чем через одну секунду и не позже чем через 365 дней, а выход за любую границу даёт `validation_error` для `scheduledAt`. Естественный язык не принимается, потому что неверно разобранное «в следующий вторник» отправит сообщение в момент, который уже не вернуть.
cancellableForSecondsInteger- Окно отмены отправки для НЕМЕДЛЕННОЙ отправки: Integer от 0 до 900, по умолчанию 0. Любое значение больше 0 отклоняется вместе с `scheduledAt`, которое и так можно отменить, пока сообщение не ушло, а сообщение, задержанное таким образом, находится в состоянии `queued`, а не `scheduled`. Это тот же механизм отложенной отправки с короткой задержкой.
idStringобязательно- Идентификатор `msg_` и первый аргумент `emails.cancel`, `emails.reschedule` и `emails.update`. Им нужна область `emails:send`, а не собственная, и они ищут идентификатор в рабочем пространстве самого ключа, поэтому идентификатор из другого пространства даёт `not_found_error` точно так же, как идентификатор, которого никогда не существовало.
scheduled_atTime, DateTime or Stringобязательно- Новое время, второй аргумент `emails.reschedule`, читается по тем же правилам и в том же окне в один год. Это единственное, что меняет `reschedule`, и клиент больше ничего не отправляет. Длительность отсчитывается от момента, когда её прочитал СЕРВЕР, поэтому повторённый перенос сработает чуть позже, чем сработал бы первый: позже, но никогда не раньше.
api_keyString- Действует с этим ключом вместо ключа клиента в любом из трёх вызовов.
Ответ
cancel, reschedule и update каждый возвращают всё сообщение как Hash с ключами типа Symbol.
objectString- Всегда `email`. Эти вызовы отвечают всем сообщением, а не подтверждением, поэтому, чтобы увидеть изменения, ничего не нужно запрашивать заново. `emails.send` возвращает ту же форму плюс `replayed`.
idString- Дескриптор `msg_`. Стабилен на протяжении всей жизни сообщения, и именно этот идентификатор принимает любой другой вызов для него.
statusString- `cancelled` после отмены и `scheduled` после переноса, в том числе для сообщения, которое было лишь в состоянии `queued` за окном отмены: перенос превращает его в настоящее расписание. Переносить или останавливать можно только сообщения в состоянии `queued` и `scheduled`. Для всего, что продвинулось дальше, возвращается `conflict_error` с кодом `email_not_cancellable`, потому что часть уже лежит в чьём-то почтовом ящике.
scheduledAtString or nil- Момент ISO 8601, когда сообщение должно быть отправлено. Задаётся и для окна отмены, и для отправки с `scheduledAt`, поскольку это один механизм, и равен nil при обычной немедленной отправке.
cancellableUntilString or nil- Когда отмена перестаёт работать. На обоих отложенных путях это тот же момент, что и `scheduledAt`. nil при немедленной отправке, которая уже ушла к моменту возврата из вызова.
sentAtString or nil- Когда сообщение действительно ушло. nil, пока оно ждёт, и nil навсегда у отменённого.
messageIdString or nil- Message-ID по RFC 5322, nil, пока не существует MIME, поэтому у сообщения, с которым могут работать эти вызовы, он всегда nil. Его нельзя использовать для обращения к API, и с ним не возвращается более поздний отказ: сервис отправки переписывает заголовок на выходе.
threadIdString or nil- Цепочка, к которой относится это сообщение. Берётся из запроса и перезаписывается тем, что сообщит транспорт после отправки. nil, если это не ответ.
transportString or nil- Каким путём ушли байты. nil до отправки, поэтому nil у каждого сообщения, которое может вернуть отмена или перенос. Отправка в тестовом режиме записывает `test`, а может появиться и транспорт, которого этот гем пока не называет, поэтому считайте незнакомое значение информацией, а не ошибкой.
attemptsInteger- Сколько раз отправка захватывала эту запись. Растёт с каждым захватом, а не с каждой успешной отправкой, и равно 0 для всего, что ещё ждёт.
lastErrorString or nil- Последний сбой, записанный для сообщения, nil, пока ничего не сломалось. Отложенная отправка, задание которой не удалось поставить в очередь, записывается здесь как `Could not schedule: …` и переводится в `failed`. Это единственный способ, которым запланированное сообщение перестаёт быть отменяемым без чьей-либо просьбы.
fromString- Адрес, от имени которого сообщению было разрешено уйти: отправленный `from`, сохранённый голым и в нижнем регистре. Отображаемое имя здесь отбрасывается, потому что фильтр `from:` в `emails.list` сравнивает на равенство.