Обновлено 2026-10-08
Как отправлять почту из Node.js через Nodemailer и SMTP
Чтобы отправлять почту из Node.js через Nodemailer, вызовите nodemailer.createTransport с host smtp.bulko.io, port 587, secure: false и auth.user и auth.pass из переменных окружения; Nodemailer сам включит шифрование через STARTTLS. secure: true ставьте только для порта 465.
Что указать в Nodemailer
| Поле | Значение |
|---|---|
| host | smtp.bulko.io |
| port | 587 (или 2525 при блокировке; 465 вместе с secure: true) |
| secure | false для 587 и 2525, true только для 465 |
| requireTLS | true (необязательно, запрещает отправку без STARTTLS) |
| auth.user | process.env.SMTP_USERNAME (вида smtp_xxxxxxxxxxxxxxxx) |
| auth.pass | process.env.SMTP_PASSWORD |
| from | Адрес на вашем домене, например "Your App" <[email protected]> |
Настройка по шагам
- Купите SMTP-пакет на странице Bulko SMTP Relay и скопируйте логин и пароль в разделе Dashboard -> SMTP Access.
- Установите библиотеку:
npm install nodemailer. Она подключается и черезimport nodemailer from "nodemailer"(ESM), и черезrequire("nodemailer")(CommonJS). - Храните доступы в переменных окружения
SMTP_USERNAMEиSMTP_PASSWORD(в менеджере процессов, контейнере или в файле.env, который подключается черезnode --env-file=.env). - Создайте один transporter с
host: "smtp.bulko.io",port: 587,secure: falseи объектомauth. Используйте его повторно, а не создавайте новый на каждое письмо. - Про
secure:trueозначает TLS с первого байта и подходит только для порта 465. ПриfalseNodemailer подключается без шифрования и поднимает TLS через STARTTLS, если сервер его предлагает. ДобавьтеrequireTLS: true, чтобы сделать это обязательным. - В
fromукажите адрес на своём домене. Для выровненных SPF, DKIM и DMARC подтвердите домен в разделе Sending Domains личного кабинета Bulko. - Вызовите
await transporter.verify()при старте, чтобы сразу поймать ошибку порта или пароля, а письма отправляйте черезawait transporter.sendMail({...}).
Если хостинг блокирует исходящие 587 и 465 (так делают некоторые облачные платформы), используйте port: 2525 с тем же secure: false. Разница между портами описана в статье о SMTP-портах.
send-test.mjs
// send-test.mjs (npm install nodemailer)
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "smtp.bulko.io",
port: 587,
secure: false, // false для 587 и 2525 (STARTTLS), true только для 465
requireTLS: true, // ошибка вместо отправки без TLS
auth: {
user: process.env.SMTP_USERNAME,
pass: process.env.SMTP_PASSWORD,
},
});
// Порт 465 (неявный TLS):
// const transporter = nodemailer.createTransport({
// host: "smtp.bulko.io",
// port: 465,
// secure: true,
// auth: { user: process.env.SMTP_USERNAME, pass: process.env.SMTP_PASSWORD },
// });
try {
await transporter.verify(); // проверяет DNS, TLS и логин без отправки письма
const info = await transporter.sendMail({
from: '"Your App" <[email protected]>',
to: "[email protected]",
subject: "Nodemailer SMTP test",
text: "It works.",
html: "<p>It works.</p>",
});
console.log("Sent:", info.messageId, info.response);
} catch (err) {
console.error("SMTP error:", err.responseCode, err.message);
process.exitCode = 1;
}
Проверка
Запустите SMTP_USERNAME=smtp_xxx SMTP_PASSWORD=yourpass node send-test.mjs, указав в скрипте реальный адрес получателя. При успехе скрипт выведет messageId и response, начинающийся с 250: релей принял письмо. Проверьте ящик через минуту-две.
Если verify() падает, у ошибки будет code вроде EAUTH, ETIMEDOUT или ESOCKET, а у ошибок SMTP есть ещё responseCode. Сверьтесь с таблицей ниже.
Ошибки и решения
| Проблема | Решение |
|---|---|
| Error: Invalid login: 535 (code EAUTH) | Неверный логин или пароль, либо переменные окружения не заданы в запущенном процессе. Проверьте Boolean(process.env.SMTP_PASSWORD). Подробнее: https://bulko.io/ru/smtp-errors/535/ |
| SSL routines: wrong version number | secure: true указан для порта 587 или 2525. Для этих портов нужен secure: false, либо перейдите на 465 с secure: true. |
| Greeting never received или зависание на 465 | Для порта 465 указан secure: false, и Nodemailer ждёт открытого приветствия, которого не будет. Поставьте secure: true. |
| ETIMEDOUT или ECONNREFUSED | Исходящие SMTP-порты закрыты хостингом или фаерволом. Попробуйте порт 2525 с secure: false. |
| 554 5.7.1 в err.response | Письмо отклонил ИИ-фильтр контента (фишинг, вредоносное ПО, имитация бренда, мошенничество). Проверьте текст и ссылки, правила: https://bulko.io/ru/acceptable-use/ |
Частые вопросы
Когда в Nodemailer нужен secure: true?
Только для порта 465, где TLS начинается сразу. Для 587 и 2525 оставьте secure: false: соединение всё равно шифруется через STARTTLS, а requireTLS: true делает это обязательным.
Нужен ли пул соединений для массовой отправки?
Для большого числа писем можно добавить pool: true, чтобы переиспользовать соединения. Учитывайте лимит по умолчанию: 2 000 писем в сутки на SMTP-аккаунт, увеличить его можно через [email protected].
Можно ли читать входящую почту через Nodemailer и этот сервер?
Нет. Nodemailer только отправляет, а Bulko SMTP работает только на исходящую почту, без IMAP. Ответы приходят на ваш адрес From или Reply-To.
Работает ли это в Next.js, Express или NestJS?
Да, в любом серверном коде на Node.js. Не запускайте отправку в браузере и не включайте SMTP-доступы в клиентский бандл.
Сколько это стоит?
Разовые пакеты: $5 за 5 000 писем, $15 за 20 000, $30 за 50 000, $60 за 150 000. Неиспользованные письма не сгорают, бесплатного пробного периода для SMTP нет.
Получить SMTP-доступ для Nodemailer
Разовая оплата картой или криптой, без подписки. Неиспользованные письма не сгорают. Лимит 2 000 писем в сутки на один доступ.
Что можно отправлять: правила использования.