Отправка почты в Go через net/smtp

Вы часто можете потребоваться отправлять письма из программ — для подтверждения аккаунта, уведомлений, логирования или других целей. SMTP отвечает за отправку писем между серверами, а IMAP — за приём. В Go есть стандартный пакет net/smtp, реализующий основные возможности SMTP и поддерживающий расширения (AUTH, STARTTLS, 8BITMIME). Код в этой статье доступен в репозитории на GitHub и распространяется под лицензией MIT.
Для кого эта инструкция
- Разработчики backend на Go, которые хотят быстро отправлять почту.
- Девопсы, которым нужно понять, как устроен поток отправки почты через SMTP с TLS.
- Тестировщики, которым нужно автоматизировать отправку уведомлений.
Важно: в примерах используется SMTP сервера Yahoo как иллюстрация. Шаги применимы и к другим провайдерам, но параметры хоста/порта и требования к аутентификации могут отличаться.
Краткие термины
- SMTP — протокол для передачи почты между серверами.
- TLS — безопасный уровень транспортного шифрования.
- App password — отдельный пароль для приложений, если основной аккаунт защищён 2FA.
Что вам нужно перед началом
- Установленный Go (1.20+ рекомендуется).
- Учетная запись почтового провайдера и, при необходимости, созданный пароль приложения (app password) или OAuth2-токен.
- Базовые знания работы с TLS и сетями.
Импорт пакетов и минимальный шаблон
Пакет net/smtp входит в стандартную библиотеку — ничего дополнительно устанавливать не нужно. Также используйте log и crypto/tls для логирования и конфигурации безопасного соединения.
import (
"net/smtp"
"log"
"crypto/tls"
"fmt"
)
Вы можете написать функцию SendMail(), которая отправляет письмо, и вызвать её из main.
func main() {
fmt.Print(SendMail())
}
func SendMail() string {
// Add code here
}
Основная идея: как работает отправка писем
SMTP требует набор параметров: адрес отправителя, адрес получателя(ей), хост сервера, порт и содержимое сообщения (заголовки + тело). В общем виде последовательность действий:
- Подготовка заголовков и тела сообщения.
- Установка TLS-соединения (если нужно).
- Аутентификация (PlainAuth или OAuth2).
- Инициация SMTP-клиента и отправка DATA.
- Закрытие соединения.
Генерация пароля приложения для Yahoo
Если вы используете Yahoo Mail, зайдите в настройки аккаунта -> Account Security и создайте пароль приложения (app password). Этот пароль используется вместо основного пароля и лучше хранится в защищённых секретах среды выполнения (см. раздел Безопасность).

Пример переменных в функции SendMail
В функции SendMail вы объявляете переменные: from — адрес отправителя, password — пароль приложения или токен, to — адрес получателя.
from := "yourMail@gmail.com"
password := "aSecurePasswordHere"
to := "anemail@gmail.com"
Если нужно отправить на несколько адресов — используйте срез и цикл.
Хост и порт SMTP
Провайдер определяет хост и порт. Типичные порты:
- 25 — стандартный SMTP (обычно без шифрования)
- 465 — SMTPS (SMTP поверх SSL/TLS), часто используется для явного TLS при установке соединения
- 587 — SMTP с STARTTLS (начинается как незашифрованное соединение, затем переводится в TLS)
Пример для Yahoo:
host := "smtp.mail.yahoo.com"
port := "465"
К сведению: Gmail отключил «менее безопасные приложения», поэтому для Gmail часто требуется OAuth2 или использование пароля приложения с включённой двухфакторной аутентификацией.
Формирование заголовков и тела письма
Заголовки — это простая map[string]string; затем вы собираете строку сообщения из заголовков и тела.
headers := make(map[string]string)
headers["From"] = from
headers["To"] = to
headers["Subject"] = subject
message := ""
for k, v := range headers {
message += fmt.Sprintf("%s: %s\r", k, v)
}
message += "\r" + body
Важно: для сложных сообщений (HTML, вложения, кодировка) используйте MIME-заголовки, boundary и кодирование (base64/quoted-printable). Для простых уведомлений этого куска достаточно.
Аутентификация через PlainAuth
Пакет smtp предоставляет smtp.PlainAuth для простой аутентификации:
authenticate := smtp.PlainAuth("", from, password, host)
Если используется OAuth2, вместо PlainAuth вы должны подготовить специальный механизм аутентификации (токен) и использовать smtp.Auth интерфейс.
Создание TLS-соединения и SMTP-клиента
Некоторые провайдеры требуют прямого TLS-соединения (SMTPS на порту 465). Пример конфигурации TLS:
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
ServerName: host,
}
Важно: InsecureSkipVerify: true отключает проверку сертификата — это удобно в локальной среде, но опасно в продакшене. См. раздел Безопасность ниже.
Установка соединения и создание клиента:
connection, err := tls.Dial("tcp", serverAddress, tlsConfig) err != nil {
log.Panic(err)
}
smtpClient, err := smtp.NewClient(connection, host)
if err != nil {
log.Panic(err)
}
(В реальном коде разбивайте выражение на строки и правильно обрабатывайте err после вызова Dial.)
Передача параметров и отправка письма
После создания smtpClient выполните аутентификацию, укажите отправителя и получателей и передайте данные:
if err = smtpClient.Auth(authenticate); err != nil {
log.Panic(err)
}
if err = smtpClient.Mail(from); err != nil {
log.Panic(err)
}
if err = smtpClient.Rcpt(headers["To"]); err != nil {
log.Panic(err)
}
writer, err := smtpClient.Data()
if err != nil {
log.Panic(err)
}
_, err = writer.Write([]byte(message))
if err != nil {
log.Panic(err)
}
err = writer.Close()
if err != nil {
log.Panic(err)
}
err = smtpClient.Quit()
if err != nil {
return
}
return "Successful, the mail was sent!"
После вызова SendMail в main вы увидите сообщение об успехе в консоли, а письмо будет доставлено получателю.

Когда этот подход не подходит
Важно: net/smtp удобен для простых задач и тестовых скриптов, но имеет ограничения:
- Для массовых рассылок и статистики нужен сторонний сервис (SendGrid, Mailgun, Amazon SES).
- Для сложных писем с вложениями и HTML лучше использовать библиотеку, которая умеет строить MIME с boundary и кодировками.
- Для OAuth2-аутентификации (например, Gmail API) потребуются дополнительные реализации.
Альтернативные подходы
- Использовать API сторонних почтовых сервисов (SendGrid, Mailgun, Postmark). Они обеспечивают доставляемость, очереди, шаблоны и статистику.
- Локальный MTA (Postfix) + отправка через localhost — полезно для изоляции и очередей.
- SMTP-клиенты/библиотеки, поддерживающие вложения и удобное создание MIME (github.com/jordan-wright/email и пр.).
Безопасность и хранение секретов
Важно соблюдать простые принципы:
- Никогда не храните пароли в коде. Используйте переменные окружения или менеджеры секретов (Vault, AWS Secrets Manager).
- Не устанавливайте InsecureSkipVerify: true в продакшене — это отключает проверку сертификатов.
- Предпочтительно использовать пароль приложения или OAuth2; пароль аккаунта менее безопасен.
- Лимитируйте количество отправляемых писем и обрабатывайте ошибки отправки, чтобы избежать блокировок у провайдера.
Важно: для соответствия требованиям безопасности и конфиденциальности избегайте включения личных данных в логи.
Отладка и распространённые ошибки
- net/smtp: unexpected TLS handshake — проверьте порт (465 vs 587) и режим (SMTPS vs STARTTLS).
- 535 Authentication failed — проверьте правильность пароля/токена и настройки доступа в аккаунте.
- Connection refused — проверьте, не блокирует ли исходящие соединения ваш хост/файрволл.
Пошаговый план при ошибке:
- Проверить корректность host:port.
- Попробовать telnet host порт для проверки соединения или openssl s_client -connect host:port.
- Проверить логи провайдера (если доступны).
- Включить подробное логирование в приложении и проверить содержимое message и заголовков.
Роль‑ориентированные чеклисты
Чеклист разработчика:
- Код не содержит паролей.
- Заголовки и кодировка верны.
- Обработаны ошибки и таймауты.
Чеклист оператора/админа:
- Открыты нужные исходящие порты.
- Сертификаты действительны.
- Мониторинг очередей отправки настроен.
Чеклист специалиста по безопасности:
- Используются секретные хранилища.
- Нет InsecureSkipVerify в проде.
- Минимальные привилегии для аккаунтов/токенов.
Чеклист QA:
- Тесты на успешную отправку и обработку ошибок.
- Проверка заголовков и отображения в популярных почтовых клиентах.
Критерии приёмки
- Письмо доставлено на указанный адрес и отображается корректно в почтовом клиенте.
- В логах приложения фиксируется статус отправки/ошибки.
- Секреты не находятся в репозитории.
- Для массовой рассылки используется сторонний сервис или очередь.
Тесты и сценарии приёмки
- Отправка простого текста одному получателю. Ожидается: статус успешен, письмо получено.
- Отправка на несколько получателей. Ожидается: все получатели получают письмо.
- Некорректный пароль. Ожидается: получение ошибки аутентификации и корректный лог.
- Неправильный хост/порт. Ожидается: ошибка соединения и корректный лог.
Шаблоны и сниппеты
Отправка на несколько получателей (пример):
recipients := []string{"user1@example.com", "user2@example.com"}
for _, r := range recipients {
if err := smtpClient.Rcpt(r); err != nil {
log.Printf("rcpt failed for %s: %v", r, err)
}
}Использование STARTTLS (если сервер поддерживает порт 587):
// Подключиться через net.Dial, затем вызвать smtp.NewClient, затем c.StartTLS(tlsConfig)(Полный пример STARTTLS выходит за рамки краткого сниппета — используйте официальную документацию и примеры в сети.)
Соответствие приватности и GDPR
Если вы отправляете персональные данные (имена, адреса, данные аккаунтов), убедитесь, что у вас есть основание для обработки (согласие или контракт). Храните адреса и логи в соответствии с политиками хранения данных и предоставляйте возможность удаления/экспорта данных по запросу.
Ментальная модель процесса отправки почты
Представьте себе конвейер: вы упаковываете сообщение (заголовки + тело), передаёте в «почтовый клиент» (smtpClient), который говорит «я — отправитель», затем получает подтверждение от сервера-почтовика и кладёт письмо в очередь доставки. На каждом этапе возможны ошибки: упаковка (MIME), соединение (TLS), аутентификация, передача.
Когда стоит перейти на сторонний сервис
- Вам нужна статистика доставляемости и кликов.
- Огромные объёмы отправки и требования к очередям.
- Обработка отказов, повторов и блокировок.
Полезные рекомендации по миграции
- Разделите логику формирования письма и транспорт (SMTP). Это упростит замену транспорта на API SendGrid/SES без изменения генерации писем.
- Внедрите очередь сообщений (RabbitMQ, Kafka) для сглаживания пиков отправки.
1‑строчная глоссарий
- SMTP — протокол отправки почты.
- TLS — шифрование канала.
- App password — отдельный пароль для приложений при 2FA.
Заключение
net/smtp в Go — удобный инструмент для простых сценариев отправки почты. Для продакшена обратите внимание на безопасность, правильную обработку ошибок, хранение секретов и масштабируемость. Если требования возрастают, рассмотрите специализированные сервисы или внешние API.
Резюме
- net/smtp подходит для простых сценариев отправки писем и тестирования.
- Всегда защищайте секреты и не отключайте проверку сертификатов в проде.
- Для массовых рассылок и аналитики лучше использовать сторонние сервисы.
Похожие материалы
Как полностью переустановить ChromeOS на Chromebook
Идеальные скриншоты в Windows
Проверка скорости Wi‑Fi: тесты и устранение проблем
Виджеты и гаджеты для Windows 10
Коды BSOD Windows 10/11: как найти и исправить