Python: отправка почты через smtplib с вложениями (Яндекс и Gmail)
Содержание
Для отправки писем из Python хватает стандартных модулей: smtplib подключается к серверу, email.message.EmailMessage собирает письмо. Установка сторонних библиотек не нужна. Важно сделать две вещи правильно: использовать пароль приложения вместо основного пароля и хранить его не в коде, а в переменных окружения. Ниже готовые примеры для Яндекса и Gmail, а также отправка вложений и ответы на типичные ошибки.
Что нужно перед стартом
- Python 3 (с python.org).
- Ящик с включенным доступом по SMTP. Для Яндекса, Mail.ru и Gmail нужен пароль приложения (Gmail - при включенной двухэтапной аутентификации). См. пароль приложения для почты.
- Переменные окружения с логином и паролем. В Windows PowerShell:
$env:MAIL_USER = "you@yandex.ru"и$env:MAIL_PASS = "пароль-приложения". В Linux и macOS:export MAIL_USER=....
В интерфейсе Google пункт может находиться в разных местах и быть недоступен без двухэтапной аутентификации. Как ее включить, написано в статье про двухфакторную аутентификацию.
Параметры серверов
| Сервис | Сервер | Порт | Шифрование |
|---|---|---|---|
| Яндекс | smtp.yandex.ru | 465 | SSL |
| Mail.ru | smtp.mail.ru | 465 | SSL |
| Gmail | smtp.gmail.com | 465 | SSL |
| Gmail | smtp.gmail.com | 587 | STARTTLS |
Разницу портов объясняет статья порты почтовых серверов.
Простое письмо через Яндекс
Порт 465 означает, что соединение сразу шифруется, поэтому используется SMTP_SSL.
import os
import smtplib
from email.message import EmailMessage
user = os.environ["MAIL_USER"]
password = os.environ["MAIL_PASS"]
msg = EmailMessage()
msg["From"] = user
msg["To"] = "friend@example.com"
msg["Subject"] = "Тест из Python"
msg.set_content("Привет! Это письмо отправлено скриптом.")
with smtplib.SMTP_SSL("smtp.yandex.ru", 465) as server:
server.login(user, password)
server.send_message(msg)
Адрес в поле From должен совпадать с логином ящика: Яндекс отклонит письмо с чужим отправителем.
Gmail через порт 587
Для STARTTLS соединение сначала открывается без шифрования, а затем переводится в защищенный режим командой starttls().
import os
import smtplib
from email.message import EmailMessage
user = os.environ["MAIL_USER"]
password = os.environ["MAIL_PASS"]
msg = EmailMessage()
msg["From"] = user
msg["To"] = "friend@example.com"
msg["Subject"] = "Письмо через Gmail"
msg.set_content("Текст письма")
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(user, password)
server.send_message(msg)
Вложения и HTML
Файл добавляется методом add_attachment. Тип вложения нужно указать вручную. Для PDF это application/pdf.
from pathlib import Path
path = Path("schet.pdf")
msg.add_attachment(
path.read_bytes(),
maintype="application",
subtype="pdf",
filename=path.name,
)
Чтобы письмо было с оформлением, добавьте HTML-версию вторым вариантом: msg.add_alternative("<h1>Счет</h1>", subtype="html"). Текстовую версию оставьте: так письмо корректно откроется в любых клиентах. Если файл большой, помните об ограничениях на размер вложения, см. как отправить большой файл.
Типичные ошибки
| Ошибка | Причина | Что делать |
|---|---|---|
| SMTPAuthenticationError 535 | Неверный пароль или использован основной пароль | Создайте пароль приложения |
| SMTPSenderRefused | Адрес "From" не совпадает с логином | Укажите адрес ящика |
| Connection timed out | Заблокирован порт или неверный сервер | Проверьте сервер и порт, попробуйте 587 |
| Письмо ушло в спам | Нет подписи домена, много ссылок | См. почему письма попадают в спам |
Расшифровка кодов - в статье Ошибки SMTP.
Частые вопросы
Можно ли хранить пароль прямо в скрипте?
Не стоит: файл легко отправить или выложить случайно. Используйте переменные окружения или отдельный файл настроек вне репозитория.
Чем отличаются SMTP_SSL и starttls?
SMTP_SSL шифрует соединение с первой секунды (порт 465). starttls() переключает обычное соединение на шифрованное (порт 587). Оба варианта безопасны.
Сколько писем можно отправить за день?
У каждого сервиса есть свои дневные лимиты, они могут меняться. Для больших списков лучше использовать сервис рассылок, см. рассылка писем.
Можно ли попросить ИИ написать такой скрипт?
Да, это быстрый способ получить заготовку. Подробнее в статье про Claude Code и почту. Код все равно проверяйте и запускайте сначала на себе.





