Переход с SendGrid
У SendGrid тело запроса устроено иначе: получатели живут в personalizations, а
контент — в массиве content. У нас плоская структура, поэтому основная работа при
миграции — «развернуть» payload.
Соответствия составлены по публичному Mail Send v3 API SendGrid на момент написания. Сверьтесь с их актуальной документацией, если пользуетесь свежими возможностями.
Ключи и клиент
| SendGrid | MailInfra | |
|---|---|---|
| Префикс ключа | SG.… | mi_live_… (боевой), mi_test_… (sandbox) |
| Переменная окружения | SENDGRID_API_KEY | MAILINFRA_API_KEY |
| База API | https://api.sendgrid.com/v3 | https://app.mailinfra.ru/v1 |
| Эндпоинт отправки | POST /mail/send | POST /v1/emails |
| Тестовый режим | mail_settings.sandbox_mode | отдельный ключ mi_test_… |
На других языках клиент создаётся так же — ключ берётся из MAILINFRA_API_KEY:
from mailinfra import MailInfra
client = MailInfra()
use MailInfra\MailInfra;
$client = new MailInfra();
client, err := mailinfra.New()
Дальше примеры — на TypeScript. Набор методов во всех четырёх SDK один, а имена полей
письма следуют языку: в Node — как в API (from, reply_to), в PHP — именованные
аргументы в camelCase (from:, replyTo:), в Python —
именованные аргументы (from_email=, потому что from — ключевое слово), в Go — поля
структуры SendParams (From, FromName, To, CC). Примеры на каждом языке —
на страницах Python, Node, PHP и Go.
Отправка письма
| SendGrid | MailInfra | Комментарий |
|---|---|---|
personalizations[].to[].email | to | у нас список адресов, одно письмо = одна персонализация |
personalizations[].cc / bcc | cc / bcc | всего до 50 адресов вместе с to |
personalizations[].dynamic_template_data | variables | переменные шаблона |
personalizations[].substitutions | variables | подстановок вида -key- нет, только именованные переменные |
from.email, from.name | from, from_name | |
reply_to.email | reply_to | у нас список, до 10 адресов |
subject | subject | |
content[{type:"text/plain"}] | text | |
content[{type:"text/html"}] | html | |
template_id (d-…) | template | у нас слаг шаблона: welcome, а не UUID |
categories | tags | до 10, до 32 символов |
custom_args | metadata | пары «ключ — значение» (до 20), возвращаются в письме и в каждом вебхуке |
attachments[].content (base64) | attachments[].content_base64, либо content байтами | |
attachments[].type | attachments[].content_type | |
attachments[].disposition: "inline", content_id | attachments[].content_id | картинка внутри письма по cid: |
send_at (unix-время) | send_at | ISO 8601 с часовым поясом, до 7 дней вперёд; отмена и перенос — POST /v1/emails/{id}/cancel и PATCH /v1/emails/{id} |
asm (группы отписки) | — | отписка ведётся через список подавления |
ip_pool_name | — | пулами IP управляет MailInfra |
Python
# было
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
message = Mail(
from_email="hello@example.ru",
to_emails="user@example.com",
subject="Привет",
html_content="<p>Привет!</p>",
)
response = SendGridAPIClient(os.environ["SENDGRID_API_KEY"]).send(message)
print(response.status_code, response.headers["X-Message-Id"])
# стало
from mailinfra import MailInfra
client = MailInfra()
result = client.emails.send(
from_email="hello@example.ru",
to="user@example.com",
subject="Привет",
html="<p>Привет!</p>",
)
print(result.status, result.id)
Шаблоны
# было
message = Mail(from_email="no-reply@example.ru", to_emails="user@example.com")
message.template_id = "d-0123456789abcdef"
message.dynamic_template_data = {"user_name": "Анна"}
# стало
client.emails.send(
from_email="no-reply@example.ru",
to="user@example.com",
template="welcome", # слаг из дашборда
variables={"user_name": "Анна"},
)
Шаблоны у нас хранятся в проекте и рендерятся на сервере (Jinja) —
как их заводить. Handlebars-конструкции SendGrid
({{#if}}, {{#each}}) нужно переписать на Jinja.
Node.js
// было
import sgMail from "@sendgrid/mail";
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
await sgMail.send({
to: "user@example.com",
from: "hello@example.ru",
subject: "Привет",
html: "<p>Привет!</p>",
categories: ["welcome"],
});
// стало
import { MailInfra } from "mailinfra";
const client = new MailInfra();
await client.emails.send({
to: "user@example.com",
from: "hello@example.ru",
subject: "Привет",
html: "<p>Привет!</p>",
tags: ["welcome"],
});
Массовая отправка
У SendGrid «много писем» делается несколькими personalizations в одном запросе. У нас
для этого отдельный эндпоинт — батч до 100 писем:
await client.emails.sendBatch([
{ from: "no-reply@example.ru", to: "a@example.com", template: "welcome",
variables: { user_name: "Анна" } },
{ from: "no-reply@example.ru", to: "b@example.com", template: "welcome",
variables: { user_name: "Борис" } },
]);
Разница в трактовке ответа: 202 приходит даже при частичном отказе, у каждого
элемента results своё error — проверяйте поштучно.
Идентификатор письма и статусы
| SendGrid | MailInfra |
|---|---|
X-Message-Id в заголовке ответа | result.id в теле ответа |
| статусы через Event Webhook или Activity API | client.emails.get(id), client.emails.list(...), client.emails.events(id) |
sg_message_id в событиях | data.email.id в вебхуке |