Python отправка email: полный гайд по SMTP и вложениям
Содержание статьи
- Способы отправки писем
- Библиотека smtplib для отправки
- Формирование письма через email.mime
- Настройка SMTP-сервера
- Подключение к Gmail и Яндекс.Почте
- Параметры сервера и порты
- Отправка письма с вложениями
- Добавление файлов к письму
- Отправка HTML-письма с изображениями
- Обработка ошибок и логирование
- Исключения при подключении к серверу
- Проверка доставки и повторные попытки
- Практический пример кода
- Полный скрипт отправки письма
- Тестирование на локальном сервере
Способы отправки писем
Чтобы python отправить email, используют несколько библиотек. Базовая — smtplib из стандартной библиотеки, работающая через протокол SMTP. Для работы с MIME-форматом (вложения, HTML-разметка) подключают модуль email.mime. Альтернатива — сторонние обёртки вроде yagmail или Envelopes, упрощающие синтаксис.
Выбор зависит от задачи:
- простое текстовое сообщение — достаточно smtplib;
- письмо с картинками и файлами — потребуется MIME;
- массовая рассылка — лучше использовать готовые библиотеки с шаблонами.
Библиотека smtplib для отправки
Модуль smtplib входит в стандартный комплект Python, поэтому устанавливать ничего не придётся. Он реализует клиентскую часть протокола SMTP и берёт на себя весь диалог с почтовым сервером.
Базовый сценарий выглядит так:
- Создаётся объект SMTP с указанием хоста и порта.
- Вызывается starttls() для шифрования (если нужно).
- Происходит авторизация через login().
- Отправляется письмо методом sendmail().
Для проверки соединения удобно использовать локальный отладочный сервер: python -m smtpd -n -c DebuggingServer localhost:1025. Он выводит содержимое сообщений в консоль, что помогает отладить код без риска что-то отправить не туда.
Формирование письма через email.mime
Для отправки вложений и форматированного контента применяется модуль email.mime. Он позволяет собирать сообщение по частям: текст, HTML-версию, файлы. Основные классы — MIMEText для текста и MIMEBase для произвольных данных.
Сборка выглядит так:
- Создаётся корневой объект
MIMEMultipart(). - В него добавляются заголовки
From,To,Subject. - Через метод
attach()подключаются части — текст и файлы.
Для вложения файла его содержимое кодируется в Base64 и оборачивается в MIMEBase с указанием типа. Это стандартный подход, описанный в официальной документации Python.
Настройка SMTP-сервера
Для отправки писем через Python потребуется доступ к почтовому серверу, который принимает исходящие сообщения. Обычно это SMTP-хост вашего провайдера — например, для Gmail это smtp.gmail.com, для Яндекс.Почты — smtp.yandex.ru. Порт чаще всего 587 (с TLS) или 465 (с SSL).
Параметры подключения удобно хранить в переменных окружения, а не в коде — так безопаснее. Учтите, что для популярных сервисов понадобится пароль приложения, а не обычный пароль от аккаунта.
Подключение к Gmail и Яндекс.Почте
Для работы с почтовыми сервисами через Python потребуется настроить доступ. У Gmail и «Яндекса» свои требования к безопасности.
- Gmail: включите двухфакторную аутентификацию и создайте пароль приложения в настройках аккаунта.
- Яндекс.Почта: активируйте пункт «Пароли приложений» в разделе безопасности.
После этого укажите SMTP-сервер и порт в коде — обычно это smtp.gmail.com:587 и smtp.yandex.ru:587 соответственно.
Параметры сервера и порты
Для отправки через SMTP обычно применяются порт 25 (устаревший, часто блокируется провайдерами), 465 (подразумевает SSL/TLS сразу) и 587 (стартует с STARTTLS). Последний считается наиболее совместимым для большинства почтовых служб. Уточняйте актуальные значения в документации вашего провайдера — у Gmail, Yandex и Mail.ru они различаются. Неверный выбор параметра приводит к ошибке соединения или таймауту.
Отправка письма с вложениями
Когда базовая пересылка сообщений освоена, логичный следующий шаг — прикрепить к письму файлы. В стандартной библиотеке для этого предусмотрен модуль email.mime, а конкретно класс MIMEMultipart. Он выступает контейнером, в который складываются и текст, и вложения.
Алгоритм действий выглядит так:
- Создаётся объект
MIMEMultipart(), задаются тема, отправитель и получатель. - Текстовая часть добавляется через
MIMEText. - Файл читается в бинарном режиме и оборачивается в
MIMEApplication(илиMIMEBaseдля нестандартных типов). - Вложение присоединяется методом
attach().
Важный нюанс: для корректной передачи кириллических имён файлов их нужно кодировать в UTF-8 через заголовок Content-Disposition. Иначе получатель увидит «кракозябры» вместо названия документа.
Ниже — минимальный рабочий пример:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
msg = MIMEMultipart()
msg['Subject'] = 'Отчёт за квартал'
msg['From'] = 'sender@example.com'
msg['To'] = 'boss@example.com'
body = MIMEText('Во вложении — сводка.', 'plain', 'utf-8')
msg.attach(body)
with open('report.pdf', 'rb') as f:
part = MIMEApplication(f.read(), _subtype='pdf')
part.add_header('Content-Disposition', 'attachment',
filename=('utf-8', '', 'отчёт.pdf'))
msg.attach(part)
with smtplib.SMTP('smtp.example.com', 587) as server:
server.starttls()
server.login('sender@example.com', 'пароль')
server.send_message(msg)
Если нужно отправить сразу несколько файлов, цикл for по списку путей решит задачу без дублирования кода. Для больших объёмов данных стоит использовать потоковую передачу, чтобы не держать весь файл в памяти.
Обратите внимание: некоторые почтовые сервисы ограничивают размер вложения (обычно 25–50 МБ). Превышение лимита приведёт к ошибке на этапе send_message.
Добавление файлов к письму
Прикрепить вложение позволяет объект MIMEApplication или MIMEBase. Считываете файл в бинарном режиме, оборачиваете в экземпляр, задаёте заголовки Content-Disposition и Content-Type. Затем добавляете его через attach() к контейнеру MIMEMultipart. Для нескольких документов процедура повторяется циклически.
Отправка HTML-письма с изображениями
Для корректного отображения картинок в письме их встраивают через MIMEImage и прикрепляют к MIMEMultipart. Указывайте Content-ID для каждой вставки, тогда в HTML-разметке достаточно сослаться на cid:имя_файла. Это надёжнее, чем внешние ссылки, которые почтовые клиенты часто блокируют.
Примерный порядок действий:
- создать контейнер
MIMEMultipart; - добавить текстовую часть и HTML-версию;
- прочитать изображение и обернуть его в
MIMEImage; - присоединить файл и прописать заголовок
Content-Disposition.
Такой подход гарантирует, что получатель увидит оформление даже при отключённой загрузке внешних ресурсов.
Обработка ошибок и логирование
При работе с почтовыми сервисами сбои неизбежны: от временной недоступности SMTP-сервера до неверных учётных данных. Грамотная стратегия перехвата исключений экономит часы отладки. Базовый блок try/except ловит `SMTPException` и её наследников, но для диагностики этого мало.
Практичный подход — трёхуровневая схема:
- перехват конкретных типов ошибок (аутентификация, таймаут, квота);
- повторная попытка отправки с экспоненциальной задержкой (например, 1с → 4с → 16с);
- запись деталей в лог-файл с указанием времени, адресата и текста ответа сервера.
Для логирования удобен встроенный модуль `logging` — он позволяет разделять сообщения по уровням важности и выводить их одновременно в консоль и файл. Полезно фиксировать не только сам факт ошибки, но и содержимое заголовков письма — это помогает воспроизвести проблему.
Отдельного внимания заслуживает ситуация, когда письмо принято сервером, но не доставлено получателю. Тут поможет чтение возвратных сообщений (bounce-писем) через IMAP — это уже следующий уровень сложности, но именно он отличает надёжный почтовый сервис от игрушечного скрипта.
Исключения при подключении к серверу
При установлении соединения с SMTP-хостом часто возникают сбои. Наиболее типичные из них — ConnectionRefusedError (порт закрыт) и socket.gaierror (неверное имя хоста). Таймауты проявляются как TimeoutError, когда сервер не отвечает в отведённый срок. Для диагностики удобно использовать конструкцию try/except, перехватывая конкретные типы ошибок по отдельности. Это помогает отличить проблемы сети от неправильных учётных данных.
Проверка доставки и повторные попытки
После вызова метода отправки стоит проверить статус ответа сервера. Если код ответа не равен 250, значит, письмо не ушло. В таком случае разумно сделать несколько повторных попыток с нарастающей паузой, например, 5, 15 и 30 секунд. Это помогает справиться с временными сбоями почтового сервиса, не создавая избыточной нагрузки.
Практический пример кода
Соберём всё воедино. Ниже — рабочий скрипт, который отправляет письмо через SMTP-сервер Яндекса. Он включает подключение, авторизацию и передачу сообщения.
import smtplib
from email.mime.text import MIMEText
msg = MIMEText('Текст письма')
msg['Subject'] = 'Тема'
msg['From'] = 'sender@yandex.ru'
msg['To'] = 'recipient@example.com'
with smtplib.SMTP_SSL('smtp.yandex.ru', 465) as server:
server.login('sender@yandex.ru', 'пароль')
server.send_message(msg)
Для отправки через Gmail используйте smtp.gmail.com и порт 587 с SMTP() и starttls(). Пароль для внешних сервисов — отдельный, не основной.
Полный скрипт отправки письма
Соберите все компоненты воедино. Ниже — рабочий пример для SMTP-сервера Яндекса. Скопируйте код, подставьте свои данные и запустите.
import smtplib
from email.mime.text import MIMEText
msg = MIMEText("Текст сообщения", "plain", "utf-8")
msg["Subject"] = "Тема"
msg["From"] = "login@yandex.ru"
msg["To"] = "recipient@example.com"
with smtplib.SMTP_SSL("smtp.yandex.ru", 465) as server:
server.login("login@yandex.ru", "пароль_приложения")
server.send_message(msg)
Для почты Google используйте smtp.gmail.com и порт 587 с starttls(). Если нужно прикрепить файл, добавьте MIMEMultipart и MIMEBase — тогда структура письма станет составной.
Тестирование на локальном сервере
Проверить отправку писем без реального SMTP-сервера можно с помощью локального инструмента. Например, запустите python -m smtpd -c DebuggingServer -n localhost:1025 — он выведет содержимое сообщений в консоль. Для имитации почтового ящика подойдёт MailHog или Mailpit. Эти утилиты перехватывают трафик и показывают письма в веб-интерфейсе, что удобно для отладки.