руководство · resend email api
Как продуктовой команде безопасно внедрить Resend Email API?
Внедряйте Resend Email API через доверенный серверный воркер, а не в браузерном или мобильном коде. Подтвердите точный домен отправки, создайте API-ключ только для отправки и по возможности ограничьте его этим доменом, сохраните одобренную задачу на отправку и передавайте стабильный `Idempotency-Key` в `POST /emails`. Сохраняйте возвращённый ID письма, проверяйте подписи вебхуков до разбора, обрабатывайте события идемпотентно и добавляйте небезопасных получателей в стоп-лист. Разделяйте состояния: приём API, отправка провайдером, доставка на принимающий сервер и попадание во «Входящие».
Определите продуктовую операцию до запроса к провайдеру
Начните с узкой прикладной операции: подтверждение аккаунта, чек, оповещение безопасности или уведомление, которое запросил получатель. Публичный эндпоинт продукта должен авторизовать вызывающую сторону, тенанта, класс писем, адрес отправителя, получателей и шаблон ещё до того, как появится какая-либо полезная нагрузка для Resend. Не позволяйте браузеру с многоразовыми учётными данными передавать произвольные `from`, `to`, HTML или параметры провайдера. Создайте надёжную внутреннюю запись об исходящем письме с ключом события приложения, тенантом, ревизией шаблона, одобренным отправителем, набором получателей и текущим состоянием. Воркер может преобразовать эту запись в запрос к провайдеру. Такая граница держит API-ключи и недоверенное содержимое писем подальше от клиентов, делает предотвращение дублей тестируемым и позволяет продукту сменить провайдера, не переписывая каждый бизнес-процесс. Разделяйте во внутренней модели транзакционные письма и письма, зависящие от согласия, чтобы настройки подписки, стоп-листы и решения при инцидентах оставались явными.
Подтвердите точный домен, используемый в адресе From
Добавьте в Resend домен, которым вы управляете, и опубликуйте DNS-записи, показанные для этого домена. Подтверждайте именно тот организационный домен или поддомен, который используется в видимом адресе From, а не рассчитывайте, что его покрывает какой-то несвязанный родительский адрес. Перед изменением DNS изучите существующие политики SPF и DMARC и никогда не создавайте вторую SPF-запись для того же имени хоста. Используйте отдельный поддомен для отправки, если это оправдано требованиями к изоляции, владению или миграции. После того как панель сообщит о подтверждении, изучите полученное тестовое письмо и убедитесь в правильности видимого адреса From, идентификатора подписи DKIM, обратного пути, результатов аутентификации и поведения ответов. Подтверждение у провайдера доказывает, что настроенный адрес прошёл проверку настройки провайдера. Оно не доказывает согласие получателя, приём принимающим сервером, попадание во «Входящие» или хорошую репутацию. Храните сведения о владении DNS и историю изменений вне панели провайдера, чтобы ротация и откат оставались возможными.
Создайте API-ключ с минимальными правами для каждой нагрузки
Resend документирует API-ключи с уровнями доступа и необязательным ограничением по домену. Воркер отправки должен использовать ключ, ограниченный доступом на отправку и, если архитектура позволяет, единственным доменом, закреплённым за этой нагрузкой. Управление, домены, вебхуки и администрирование аккаунта держите под отдельными полномочиями. Создайте отдельные ключи для разработки, staging и продакшена, чтобы нижнее окружение не могло отправлять письма от имени продакшена или расходовать его лимиты. Сохраняйте каждый секрет сразу в управляемом хранилище секретов, открывайте его только серверному процессу, которому он нужен, и передавайте как Bearer-авторизацию по HTTPS. Не копируйте ключ в систему контроля версий, артефакты сборки, логи, шаблоны, аналитику, тикеты или промпты. Ротацию нужно отрепетировать: создайте замену с такими же правами, обновите воркер, проверьте контролируемый трафик и корреляцию событий, затем отзовите старый ключ. Настройте оповещения о неожиданных ошибках аутентификации и авторизации: они могут указывать на истечение срока, отзыв, дрейф прав или утечку секрета.
Одна надёжная задача и одна идемпотентная попытка отправки
Резервируйте внутреннюю задачу на отправку до вызова Resend. Выводите значение идемпотентности из стабильного продуктового факта — тенанта, типа операции и неизменяемого ID события приложения, — а не из случайной попытки повтора. Передавайте это значение в заголовке `Idempotency-Key`. Сейчас Resend документирует, что такие ключи предотвращают дублирование запросов на отправку, истекают через 24 часа и могут содержать не более 256 символов. Это окно провайдера полезно, но не является полной гарантией отсутствия дублей на уровне продукта. Для более длительных бизнес-процессов держите ограничение уникальности на внутреннем ключе события, сериализуйте воркеры, которые могут взять одну и ту же задачу, и сохраняйте ID письма у провайдера, возвращённый успешным запросом. Если из-за сетевого тайм-аута приём неясен, переведите задачу в неизвестное состояние и сверьте её с логами или событиями провайдера, прежде чем отправлять повторно. Переиспользовать один стабильный ключ для той же логической операции безопаснее, чем генерировать новый ключ для каждого транспортного повтора.
Осознанно формируйте и проверяйте запрос на отправку
Эндпоинт отправки писем Resend принимает адрес From, получателей, тему и содержимое письма, а также документированные параметры: text, HTML, контент, отрендеренный через React, шаблоны, Cc, Bcc, reply-to, заголовки, вложения, теги и отложенную доставку. Предоставляйте доступ только к тому подмножеству, которое нужно продукту. Проверяйте синтаксис адресов и принадлежность тенанту, ограничивайте число получателей и вложений ниже лимитов провайдера, отклоняйте внедрение переводов строк в заголовки и формируйте MIME-содержимое с помощью поддерживаемых библиотек или доверенных полей провайдера. Не помещайте учётные данные, чувствительные персональные данные или неограниченный пользовательский ввод в теги или заголовки. Сохраняйте ревизию шаблона и очищенные переменные, а не логируйте полное содержимое. Внутренний адаптер должен возвращать узкий результат — например, ID провайдера для принятого письма или классифицированную ошибку, — а не пропускать детали ответа провайдера в бизнес-код. Это позволяет обновлять специфичные для провайдера имена полей, версии SDK или лимиты запросов, не меняя контракт продуктовых событий.
Классифицируйте ответы API и лимиты использования до повтора
Рассматривайте HTTP-ответ как одно из наблюдений в процессе. Успешный ответ на отправку возвращает идентификатор письма, который нужно сохранить вместе с внутренней задачей, но он не подтверждает приём сервером назначения или попадание во «Входящие». Исправляйте ошибки валидации, аутентификации, домена, прав доступа и полезной нагрузки, а не повторяйте их вслепую. Resend документирует лимиты запросов к API и возвращает заголовки лимитов запросов и квот, включая поля об оставшемся запасе, времени сброса и задержке до повтора; при ответе 429 нужно подождать документированный интервал с добавлением случайного разброса (jitter). Повторяйте при транспортных сбоях и подходящих серверных ошибках с экспоненциальной задержкой, конечным числом попыток и тем же логическим ключом идемпотентности, пока действует его документированное окно. Неоднозначные сбои требуют сверки, потому что провайдер мог принять письмо, даже если клиент не получил ответ. Настройте оповещения, когда повторяющиеся сбои группируются по домену, шаблону, ключу или тенанту, но не допускайте в операционные логи учётные данные, полное содержимое и лишние данные получателей.
Аутентифицируйте запросы вебхуков до обработки событий
Настройте отдельный HTTPS-эндпоинт для вебхуков и сохраняйте точное исходное тело запроса. Resend документирует подпись вебхуков через Svix-совместимые заголовки и секреты подписи. Проверяйте ID вебхука, временную метку и подпись по неизменённой полезной нагрузке до разбора JSON или повторной сериализации и используйте официальный процесс проверки или поддерживаемую совместимую библиотеку. Отклоняйте недействительные или устаревшие запросы, ограничивайте размер запроса и храните секрет подписи отдельно от ключа отправки. После аутентификации надёжно сохраните событие или поставьте его в очередь до подтверждения получения, чтобы сбой процесса не мог незаметно уничтожить данные о доставке. Системы доставки могут повторять и дублировать вебхуки, поэтому используйте идентификатор события как ключ дедупликации и делайте переходы состояний монотонными. Более позднее или дублирующее событие не должно перезаписывать более информативный финальный результат только потому, что пришло последним. Фиксируйте ошибки проверки и задержку событий как операционные сигналы, не храня исходное содержимое писем дольше необходимого срока.
Моделируйте события провайдера, не преувеличивая доставку
Resend публикует именованные типы событий писем, включая sent, delivered, delivery delayed, bounced, complained, failed, opened и clicked. Сопоставляйте эти имена провайдера с внутренней моделью состояний, сохраняя исходный тип события, ID письма у провайдера, ID события, временную метку, круг получателей и доступные диагностические данные. Событие sent описывает продвижение у провайдера. Событие delivered сообщает о доставке в соответствии с документированной семантикой событий Resend, но успешный SMTP-ответ принимающей системы всё равно не раскрывает итоговую папку получателя. Открытия и клики — это наблюдения о вовлечённости, а не доказательство доставки, и на них могут влиять технологии защиты приватности. Отказы, жалобы и постоянные ошибки должны обновлять состояние безопасности получателя до принятия решения о следующей отправке. Храните историю событий провайдера в режиме только добавления и выводите статус для пользователя по явным правилам. Это сохраняет доказательства для поддержки и предотвращает небезопасные повторы после того, как ответственность уже передана или получатель подал негативный сигнал.
Тестируйте сценарии сбоев и восстановления на контролируемых получателях
Используйте ключ не из продакшена, контролируемый подтверждённый поддомен и почтовые ящики, принадлежащие команде. Протестируйте текстовое и HTML-содержимое, поведение reply-to, лимиты вложений, стабильные ключи идемпотентности и сохранённые идентификаторы провайдера. Отправьте одну и ту же логическую задачу дважды и убедитесь, что механизмы приложения и провайдера не создают непреднамеренного дубля. Проверьте некорректную полезную нагрузку, неверный домен, отозванный ключ, недостаточные права, лимит запросов, транспортный тайм-аут, отказ, жалобу, задержку доставки, дублированный вебхук, изменённое тело запроса с подписью, устаревшую временную метку вебхука и ротацию секрета подписи. Убедитесь, что приём событий надёжно сохраняется до подтверждения и что проверка безопасности получателя блокирует последующую задачу. Протестируйте ротацию DNS и удаление провайдера, не удаляя несвязанные записи. Дашборды должны охватывать ошибки отправки, задержки, ошибки проверки вебхуков, отставание событий, отказы, жалобы и очереди сверки. При запуске сверьтесь с актуальной документацией Resend и настройками аккаунта, потому что квоты, лимиты, поля событий и доступные права могут меняться независимо от развёрнутого кода приложения.
Сравните опубликованные возможности API до миграции
SendHQ публикует контракт OpenAPI 3.1 для своего email API в рамках рабочего пространства, включая отправку с подтверждённого домена, входящую почту, хранимые шаблоны, события доставки и стоп-листы. Перед миграцией интеграции сравните тела запросов, аутентификацию, идемпотентность, возвращаемые идентификаторы, формы ошибок, вебхуки, правила доменов и поведение стоп-листа, затем проверьте их тестами на уровне полей. Не предполагайте совместимость по похожим именам эндпоинтов.
Частые вопросы
Какой эндпоинт отправляет письмо через Resend?
Resend документирует `POST https://api.resend.com/emails` с Bearer-авторизацией. Вызывайте его только из доверенного серверного кода после авторизации продуктовой операции, домена отправителя, получателей и содержимого.
Как ограничить права API-ключа Resend?
Используйте ключ с доступом только на отправку и ограничьте его доменом нагрузки, если документированные механизмы подходят к вашей архитектуре. Держите полномочия для продакшена, других окружений и администрирования в отдельных учётных данных, управляемых через хранилище секретов.
Доказывает ли успешный ответ API Resend доставку?
Нет. Он фиксирует приём провайдером и возвращает идентификатор письма. Последующие аутентифицированные события могут сообщать о продвижении у провайдера и доставке в принимающую систему, а попадание во «Входящие» остаётся отдельной классификацией на стороне получателя.
Как идемпотентность Resend предотвращает дублирование писем?
Передавайте один стабильный `Idempotency-Key` для одного и того же логического запроса. Сейчас Resend хранит ключи 24 часа при максимальной длине 256 символов, поэтому держите также более долгоживущее внутреннее ограничение уникальности.
Как проверять подписи вебхуков Resend?
Сохраняйте точное исходное тело запроса и проверяйте документированные Svix-совместимые заголовки с ID вебхука, временной меткой и подписью до разбора. Отклоняйте недействительные или устаревшие данные, затем надёжно ставьте аутентифицированные события в очередь до подтверждения получения.
Может ли SendHQ заменить Resend?
Сравните опубликованные контракты API и выполните интеграционные тесты на уровне полей, прежде чем считать SendHQ и Resend совместимыми.
Источники
- Resend: API отправки писем — Resend
- Resend: API-ключи — Resend
- Resend: домены — Resend
- Resend: ключи идемпотентности — Resend
- Resend: лимиты использования — Resend
- Resend: вебхуки — Resend
- Resend: проверка запросов вебхуков — Resend
- Resend: типы событий вебхуков — Resend
- RFC 5321: простой протокол передачи почты (SMTP) — RFC Editor
- Контракт OpenAPI SendHQ — SendHQ