Верстаем письмо на React, чтобы оно корректно отображалось во всех почтовых клиентах
Чтобы свёрстанные письма хорошо выглядели на десктопе и мобильных, нужно знать, как почтовые клиенты поддерживают возможности CSS и HTML. И на практике это не всегда просто. Например, Gmail отбрасывает атрибут style целиком, если встречает в нём цвет, заданный как rgb. В итоге даже в 2025 году вёрстка писем нередко сводится к написанию таблиц и атрибутов наподобие align, valign, bgcolor и т.д.
Вдобавок, после отправки письмо нельзя поправить, как страницу на сайте, и это тоже добавляет сложности.
Наша команда решила оценить для создания писем библиотеку React Email. Она предоставляет компоненты, которые генерируют HTML и CSS для корректного отображения во всех почтовых клиентах. Письмо можно посмотреть в браузере и отправить на почту. Под капотом всё равно останутся таблицы, но писать их руками не придётся.
На примере отправки через сервис Yandex Postbox покажем, как это работает.
Начало работы. Установим библиотеку @react‑email/components и клиент для работы с почтовым сервисом AWS SESv2 — Postbox поддерживает эту версию клиента.
npm install @aws-sdk/client-sesv2 @react-email/components
Создадим компонент, который будет генерировать письмо:
email.tsx import * as React from 'react'; import { Button, Html } from '@react-email/components'; export function Email(props) { const { url } = props; return ( <Html lang="en"> <Button href={url}>Click me</Button> </Html> ); }
Больше компонентов — в документации.
Создание аккаунта в облаке
Создадим сервисный аккаунт в том же каталоге, в котором находится адрес. Если создать сервисный аккаунт и адрес в разных каталогах, при попытке отправить письмо возникнет ошибка.
Для отправки письма с помощью SDK создадим статический ключ доступа. Важно надёжно сохранить идентификатор и секретный ключ. После того как вы закроете окно, параметры секретного ключа станут недоступны.
Отправка письма. Ключи доступа можно передать в конструктор SESv2Client явно, как показано ниже, указать их в переменных окружения или использовать конфигурацию AWS CLI.
import { render } from '@react-email/components'; import type { SendEmailCommandInput } from '@aws-sdk/client-sesv2'; import { SendEmailCommand, SESv2Client } from '@aws-sdk/client-sesv2'; import { Email } from './email'; import React from 'react' const sesClient = new SESv2Client({ region: 'ru-central1', endpoint: 'https://postbox.cloud.yandex.net', }); const emailHtml = await render(<Email url="https://example.com"/>); const emailText = await render(<Email url="https://example.com"/>, { pretty: true, plainText: true, }); const email: SendEmailCommandInput = { Content: { Simple: { Body: { Html: { Data: emailHtml, }, Text: { Data: emailText, }, }, Subject: { Data: 'Тестовое письмо', }, }, }, Destination: { ToAddresses: [ 'bob@example.com' ], }, FromEmailAddress: 'Alice <alice@example.com>', } const command = new SendEmailCommand(email); const result = await sesClient.send(command); console.log(result);
Чтобы удобно запускать скрипт, установим tsx loader:
npm install --save-dev tsx
Теперь запустим скрипт, передав в переменные окружения ключи сервисного аккаунта:
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... node --import @nodejs-loaders/tsx index.tsx
В консоли увидим ответ от Postbox. Если письмо отправлено успешно, то в ответе будет MessageId.
{ '$metadata': { httpStatusCode: 200, requestId: undefined, extendedRequestId: undefined, cfId: undefined, attempts: 1, totalRetryDelay: 0 }, MessageId: 'D8BT2CX3IDK2.2HZQ4CE0E8CRL@ingress1-sas' }
Если захотите отправить несколько писем в цикле, рекомендуем добавить в код задержку между отправками, чтобы не превысить квоту.
