Переход с Resend
API устроены похоже, поэтому миграция — это в основном переименование полей и замена обработки ошибок. Ниже — что меняется в коде.
Соответствия составлены по публичному API Resend на момент написания. Если у вас свежая версия их SDK — сверьтесь с их документацией: поля могли измениться.
Ключи и клиент
| Resend | MailInfra | |
|---|---|---|
| Префикс ключа | re_… | mi_live_… (боевой), mi_test_… (sandbox) |
| Переменная окружения | RESEND_API_KEY | MAILINFRA_API_KEY |
| База API | https://api.resend.com | https://app.mailinfra.ru/v1 |
| Тестовый режим | отдельные тестовые адреса (delivered@resend.dev) | отдельный ключ mi_test_…, письмо получает статус SIMULATED |
// было
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
// стало
import { MailInfra } from "mailinfra";
const client = new MailInfra(); // ключ из MAILINFRA_API_KEY
На других языках клиент создаётся так же — ключ берётся из 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.
Отправка письма
Имена полей в основном совпадают:
| Resend | MailInfra | Комментарий |
|---|---|---|
from | from | адрес на подтверждённом домене |
to, cc, bcc | to, cc, bcc | строка или массив; всего до 50 адресов |
subject | subject | до 998 символов |
html, text | html, text | нужно хотя бы одно, либо template |
replyTo / reply_to | reply_to | до 10 адресов |
headers | headers | системные заголовки переопреде лять нельзя |
tags: [{name, value}] | tags: ["строка"] | разный формат — см. ниже |
attachments: [{filename, content}] | attachments: [{filename, content}] | у нас content — байты, которые SDK кодирует сам; либо готовый content_base64 |
attachments: [{path}] | — | скачивания по URL нет: приложите содержимое |
scheduled_at | send_at | ISO 8601 с часовым поясом, до 7 дней вперёд; естественный язык («in 1 hour») не принимается. Отмена — POST /v1/emails/{id}/cancel, перенос — PATCH /v1/emails/{id}, как emails.cancel и emails.update у Resend |
React-компонент (react) | — | рендерите HTML сами либо используйте серверные шаблоны |
// было
const { data, error } = await resend.emails.send({
from: "hello@example.ru",
to: ["user@example.com"],
subject: "Привет",
html: "<p>Привет!</p>",
tags: [{ name: "category", value: "welcome" }],
});
if (error) {
console.error(error);
}
// стало
const result = await client.emails.send({
from: "hello@example.ru",
to: ["user@example.com"],
subject: "Привет",
html: "<p>Привет!</p>",
tags: ["welcome"], // просто строки, до 10, до 32 символов
});
Теги
У Resend тег — пара «имя/значение». У нас для этого два поля:
metadata— пары «ключ — значение» (до 20):{"order_id": "1042"}. Они возвращаются в письме и в каждом вебхуке — ближе всего к тегам Resend;tags— плоские строки (до 10, до 32 символов каждая), по ним фильтруются письма в дашборде, вemails.list()и в статистике:["welcome"].
Ошибки вместо { data, error }
Главное различие в коде: Resend-SDK возвращает объект с полем error и ничего не
бросает. MailInfra бросает типизированные исключения.
// было
const { data, error } = await resend.emails.send({ /* … */ });
if (error) {
if (error.name === "validation_error") { /* … */ }
return;
}
use(data.id);
// стало
import { UnprocessableError, RateLimitError, MailInfraError } from "mailinfra";
try {
const result = await client.emails.send({ /* … */ });
use(result.id);
} catch (error) {
if (error instanceof UnprocessableError) {
for (const field of error.fields) {
console.error(field.field, field.message);
}
} else if (error instanceof RateLimitError) {
// SDK уже подождал Retry-After и повторил; сюда попадаем, если не помогло
} else if (error instanceof MailInfraError) {
console.error(error.code, error.requestId);
} else {
throw error;
}
}
Если хочется сохранить прежний стиль — оберните вызов один раз:
async function send(params) {
try {
return { data: await client.emails.send(params), error: null };
} catch (error) {
return { data: null, error };
}
}
Пакетная отправка
| Resend | MailInfra |
|---|---|
resend.batch.send([...]), до 100 писем | client.emails.sendBatch([...]), до 100 писем |
Разница в трактовке ответа: у нас 202 приходит даже при частичном отказе, и у каждого
элемента results может быть своё error. Проверяйте их поштучно —
подробнее.