Верстаем письмо на 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'
}
Если захотите отправить несколько писем в цикле, рекомендуем добавить в код задержку между отправками, чтобы не превысить квоту.