Отправляет письмо со всем, что есть в почтовой программе: несколько получателей, копия и скрытая копия, Reply-To, тема, текст и свой html, вложения, подпись, цитата, «ответить всем», отчёт о прочтении, важность, свои заголовки. Письмо уходит от адреса ящика, копия ложится в «Отправленные». Повтор с тем же clientMessageId второго письма не создаёт.
| Запрос | POST /waInstance{idInstance}/sendEmail/{apiTokenInstance} |
| Тело | JSON |
| Каналы | почта |
Параметры
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
chatId |
string | да | первый получатель в «Кому» — адрес почты |
to |
array, string | нет | ещё получатели в «Кому» |
cc |
array, string | нет | копия |
bcc |
array, string | нет | скрытая копия: остальные получатели этих адресов не видят |
replyTo |
array, string | нет | Reply-To — куда отвечать на письмо |
subject |
string | нет | тема. Не задана: у ответа в цепочку — «Re: …», у нового письма — emailSubject или первая строка текста |
message |
string | нет* | текст письма |
html |
string | нет* | своя html-версия. Без неё html собирается из текста, если emailHtml: "yes" |
files |
array | нет* | вложения: [{"urlFile": "…", "fileName": "Расписание.pdf"}] — ссылка из uploadFile или публичная http(s) |
quotedMessageId |
string | нет | ответить на это письмо переписки с chatId — в его цепочку |
newThread |
boolean | нет | true — новая цепочка. Без него письмо продолжает последнюю переписку с chatId не старше 30 дней |
replyAll |
boolean | нет | в ответе — «ответить всем»: в копию все из «Кому» и «Копии» письма, на которое отвечаете. Не задан — emailReplyAll |
quote |
boolean | нет | в ответе — процитировать письмо собеседника. Не задан — emailQuote |
signature |
string | нет | подпись под текстом; "" — без подписи. Не задана — emailSignature |
readReceipt |
boolean | нет | попросить у получателя отчёт о прочтении |
priority |
string | нет | важность: high, normal, low |
headers |
object | нет | свои заголовки, только X-…: {"X-Order": "1532"} |
clientMessageId |
string | нет | ключ от дублей: из него выводится Message-ID письма — см. Надёжная отправка без дублей |
* Нужен хотя бы один из message, html, files.
- Адреса в
to,cc,bcc,replyTo— один адрес, список или строка через запятую. - Новая тема в
subjectне начинает новую цепочку, если переписка сchatIdуже идёт: письмо уйдёт ответом на её последнее письмо. Новая цепочка —newThread: true. - Тема без текста,
emailSubjectи первой строки — «(без темы)». Первая строка длиннее 70 знаков обрезается по слову.
Пример запроса
Расписание Марии и папе, копия — офису, новая цепочка:
curl
curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/sendEmail/$GRATIO_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"chatId": "maria@client.ru",
"to": [
"papa@client.ru"
],
"cc": [
"office@school.ru"
],
"subject": "Расписание на ноябрь",
"message": "Здравствуйте! Высылаем расписание занятий на ноябрь.",
"files": [
{
"urlFile": "https://api.gratio.net/upload/7100000001/9b2e…/schedule.pdf",
"fileName": "Расписание.pdf"
}
],
"newThread": true,
"clientMessageId": "nov-schedule-maria"
}'
Python
import os
import requests
BASE = f"{os.environ['GRATIO_URL']}/waInstance{os.environ['GRATIO_ID']}"
TOKEN = os.environ["GRATIO_TOKEN"]
url = f"{BASE}/sendEmail/{TOKEN}"
payload = {
"chatId": "maria@client.ru",
"to": ["papa@client.ru"],
"cc": ["office@school.ru"],
"subject": "Расписание на ноябрь",
"message": "Здравствуйте! Высылаем расписание занятий на ноябрь.",
"files": [
{
"urlFile": "https://api.gratio.net/upload/7100000001/9b2e…/schedule.pdf",
"fileName": "Расписание.pdf",
},
],
"newThread": True,
"clientMessageId": "nov-schedule-maria",
}
response = requests.post(url, json=payload, timeout=60)
print(response.status_code, response.json())
Node.js
const { GRATIO_URL, GRATIO_ID, GRATIO_TOKEN } = process.env;
const base = `${GRATIO_URL}/waInstance${GRATIO_ID}`;
const url = `${base}/sendEmail/${GRATIO_TOKEN}`;
const payload = {
chatId: "maria@client.ru",
to: ["papa@client.ru"],
cc: ["office@school.ru"],
subject: "Расписание на ноябрь",
message: "Здравствуйте! Высылаем расписание занятий на ноябрь.",
files: [
{
urlFile: "https://api.gratio.net/upload/7100000001/9b2e…/schedule.pdf",
fileName: "Расписание.pdf",
},
],
newThread: true,
clientMessageId: "nov-schedule-maria",
};
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
console.log(response.status, await response.json());
PHP
<?php
$base = getenv('GRATIO_URL') . '/waInstance' . getenv('GRATIO_ID');
$url = $base . '/sendEmail/' . getenv('GRATIO_TOKEN');
$payload = [
'chatId' => 'maria@client.ru',
'to' => ['papa@client.ru'],
'cc' => ['office@school.ru'],
'subject' => 'Расписание на ноябрь',
'message' => 'Здравствуйте! Высылаем расписание занятий на ноябрь.',
'files' => [
[
'urlFile' => 'https://api.gratio.net/upload/7100000001/9b2e…/schedule.pdf',
'fileName' => 'Расписание.pdf',
],
],
'newThread' => true,
'clientMessageId' => 'nov-schedule-maria',
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$response = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), PHP_EOL;
print_r($response);
Файл сначала загрузите методом uploadFile — он вернёт urlFile.
Пример ответа
Ответ 200 OK:
{
"idMessage": "459f33988b5b2aa35d44",
"emailMessageData": {
"subject": "Расписание на ноябрь",
"messageId": "gr.mcduelocvo27nud5klrpglrn3m@school.ru",
"threadId": "459f33988b5b2aa35d44",
"inReplyTo": null,
"to": ["maria@client.ru", "papa@client.ru"],
"cc": ["office@school.ru"],
"bcc": [],
"refused": {}
}
}
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
idMessage |
string | id письма. Тот же — у копии в «Отправленных» и в уведомлениях |
emailMessageData.subject |
string | тема, с которой письмо ушло |
emailMessageData.messageId |
string | Message-ID письма: gr.…@ и домен ящика |
emailMessageData.threadId |
string | цепочка: у нового письма — его idMessage |
emailMessageData.inReplyTo |
string | Message-ID письма, на которое это ответ; null — не ответ |
emailMessageData.to, cc, bcc |
array | кому письмо ушло, с учётом «ответить всем» |
emailMessageData.refused |
object | адреса, которые сервер не принял, с его ответом. Остальным письмо ушло |
Если сервер отказал части получателей, ответ всё равно 200:
"refused": {"papa@client.ru": "550 5.1.1 Mailbox not found"}
Ещё примеры
Ответ в цепочку письма
На конкретное письмо Марии — всем, кто был в переписке:
curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/sendEmail/$GRATIO_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"chatId": "maria@client.ru",
"quotedMessageId": "c62b698304229a98aad3",
"message": "Мария, записали вас на субботу, 11:00.",
"replyAll": true
}'
Ответ на письмо из любой папки, без chatId, — replyEmail.
Свой html
Письмо со своей вёрсткой. message — текст для почтовых программ без html:
curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/sendEmail/$GRATIO_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"chatId": "maria@client.ru",
"subject": "Итоги занятия",
"message": "Сегодня собрали робота-сортировщика.",
"html": "<h2>Итоги занятия</h2><p>Сегодня собрали <b>робота-сортировщика</b>.</p>",
"newThread": true
}'
Важное, с отчётом о прочтении
Высокая важность, отчёт о прочтении и свой заголовок для поиска:
curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/sendEmail/$GRATIO_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"chatId": "maria@client.ru",
"subject": "Оплата за ноябрь",
"message": "Напоминаем об оплате до 25 ноября.",
"priority": "high",
"readReceipt": true,
"headers": {
"X-Order": "1532"
},
"newThread": true
}'
Получатель прочитал письмо и программа отправила отчёт — придёт outgoingMessageStatus со статусом read. Письма с заголовком найдёт searchMessages: {"folder": "sent", "header": {"X-Order": "1532"}}.
Что происходит после отправки
- Копия письма ложится в «Отправленные», если сервер не кладёт её сам. У копии тот же
idMessage. - Приходит уведомление о своём письме — см. Свои сообщения.
- Сервер получателя не принял письмо уже после отправки — он присылает отчёт, и приходит outgoingMessageStatus со статусом
failedи причиной. - Письма уходят не чаще одного в 2 секунды: следующий запрос подождёт.
Ошибки
| Код | code |
Когда | Что делать |
|---|---|---|---|
400 |
validation |
нет chatId; нет ни message, ни html, ни files; files — не список {urlFile, fileName}; неверный priority; headers — не объект |
исправить запрос |
400 |
no_account |
chatId — не адрес почты |
указать адрес |
400 |
bad_address |
адрес в to, cc, bcc или replyTo не распознан; заголовок в headers — не X-… |
исправить адрес или заголовок |
400 |
not_found |
нет письма quotedMessageId в переписке с chatId; адреса получателя не существует |
проверить письмо или адрес |
400 |
too_large |
письмо с вложениями больше 20 МБ или больше предела сервера | уменьшить вложения, крупное — ссылкой |
400 |
rejected |
почта отклонила письмо, например как спам | изменить письмо |
400 |
sender_refused |
почта не даёт отправлять от этого адреса | проверить настройки ящика |
400 |
send_failed |
почта не приняла письмо по другой причине | см. message |
400 |
auth_failed |
почта больше не принимает вход: сменили пароль или отозвали доступ | войти снова: connectMailbox |
400 |
bad_url, url_unavailable, file_too_large |
файл по ссылке не скачался: не http(s), недоступен, больше 100 МБ |
проверить ссылку, загрузить через uploadFile |
400 |
not_authorized |
ящик не подключён | подключить ящик |
402 |
payment_required |
канал на паузе за неоплату | продлить канал в кабинете |
409 |
idempotency_conflict |
тот же clientMessageId с другим письмом |
новый ключ для нового письма |
429 |
daily_limit |
300 писем за сутки с ящика | повторить после Retry-After |
429 |
too_frequent |
почта временно не принимает письма и просит повторить позже | повторить после Retry-After |
501 |
not_supported |
канал — не почта; chatId — номер …@c.us |
вызвать у канала «Почта» с адресом |
503 |
outcome_unknown |
связь оборвалась посреди отправки | повторить с тем же clientMessageId |
Общие правила — в статье Ответы и ошибки.
Что дальше
- replyEmail — ответить на письмо из любой папки.
- saveDraft — сохранить письмо черновиком.
- outgoingMessageStatus — недоставка и отчёт о прочтении.
- Настройки ящика — подпись, имя отправителя и умолчания.
