Отправка писем из Python используя модуль smtplib

SMTPlib Python

Возможно вы наткнулись на эту статью, потому что хотите отсылать письма при помощи Python. Возможно, вам нужно получать уведомления по почте из вашего кода, отправлять пользователям письма-подтверждения, когда те создают аккаунт, или отсылать письма коллегам. Отправка писем вручную — это весьма трудоемкая задача, однако ее легко автоматизировать при помощи Python.

Из данной статьи мы узнаем:

  • Как настроить безопасное подключение при помощи SMTP_SSL() и .starttls()
  • Как использовать встроенную библиотеку Python под названием smtplib для отправки простых писем;
  • Как отправлять письма с HTML содержимым и прикрепленными файлами при помощи пакета email;
  • Как отправлять несколько персонализированных писем при помощи файла СSV с контактными данными;
  • Как использовать пакет Yagmail для отправки через аккаунт Gmail используя всего несколько строк кода.

В конце данной статьи вы ознакомитесь с рядом транзакционных почтовых сервисов, которые могут пригодиться, если вам понадобиться рассылать большие количества писем.

Изучаем модуль smtplib Python

В Python есть встроенный модуль smtplib, предназначенный для отправки писем, используя Simple Mail Transfer Protocol (SMTP). Модуль smtplib использует протокол RFC 821 для SMTP. Примеры в данной статье будут браться из сервера Gmail SMTP для отправки писем, однако те же принципы будут актуальны и для других почтовых сервисов. Кроме этого, множество почтовых провайдеров используют те же порты подключения, что и упомянутые в этой статье, так что вы можете провести быстрый поиск в гугле, чтобы узнать о используемых вами портах.

Для начала, настроим аккаунт Gmail для разработки, или настроим сервер отладки SMTP, который отбрасывает отправленные вами письма и выводит их в командную строку. Мы рассмотрим оба варианта дальше. Локальный сервер отладки SMTP может быть полезным для решения любых проблем, связанных с функционалом почты и обеспечения исправности функций электронной почты перед перед тем как какое-либо из писем будет отправлено.

Настройка аккаунта Gmail для тестов с smtplib

Если вы решили использовать аккаунт Gmail для отправки писем, я настоятельно рекомендую настроить одноразовую учетную запись для разработки вашего кода. Это важно, так как вам придется настроить параметры безопасности вашего аккаунта Gmail для открытия доступа из вашего кода Python, а также есть вероятность того, что вы раскроете свои данные входа. Кстати, я обнаружил, что раздел входящих писем моего тестового аккаунта быстро набился тестовыми письмами, что является еще одной причиной настроить новый аккаунт Gmail для тестов.

Хорошая возможность Gmail в том, что вы можете использовать знак + для внесения любых модификаторов в ваш адрес электронной почты, прямо перед значком @. Например, письмо отправленное на my+person1@gmail.com и my+person2@gmail.com придет на мой адрес my@gmail.com. При тестировании функционала почты, вы можете использовать это для эмуляции нескольких адресов, которые имеют общие входящие письма.

Для настройка адреса Gmail для тестирования вашего кода, выполните следующее:

  1. Создайте новый аккаунт в гугле;
  2. Активируйте разрешение на использование небезопасных приложений. Учитывайте, что это упрощает другим получить доступ к вашему аккаунту;

Если вы не хотите снижать уровень безопасности в настройках вашего аккаунта Gmail, ознакомьтесь в документацией гугла о том, как получить учетные данные для доступа к вашему скрипту Python, используя фреймворк авторизации OAuth2.

Настройка VPS сервера c SMTP от Fornex (Вариант №2)

Работая на уже настроенном VPS сервере позволяет вам быстрее изучить операционную систему Linux. Такие знания приветствуются у тех кто только начинает свой путь как Python-разработчик. В качестве примера мы выбрали самый устойчивый VPS хостинг от Fornex. Используя такой подход, вы можете запускать парсеры того же Avito или Юла для составления собственной базы данных для E-mail рассылки. Мощный SSD Хостинг позволит ускорить работу по сбору и обработки данных на VPS.

После регистрации на Fornex вам предстоит выбор услуги:

VPS от Fornex

Выбираем нужный нам VPS с которым мы будем работать:

VPS тариф

После, нам предстоит выбрать операционную системы. Мы отдаём предпочтение Ubuntu. В нашем случае, необходимости в панели управления нет. Выбираем "Без панели".

VPS операционная система

После удачной установки, Fornex предоставит нам все данные для входа в наш новый VPS. Прежде чем начать работу с ним, Вам предстоит установка обновлений, необходимых библиотек и установка последней версии Python 3.7.

Подключение к VPS:

Обновляем систему:

Установка последней версии Python 3.7:

Установка необходимых библиотек для удобной и бесперебойной работы:

Не забываем про менеджер пакетов pip:

Заходим в домашнюю папку и тут уже можно создавать и запускать все примеры кода, что вы увидите ниже.

Создаём папку для наших тестов:

Учимся работать с консольными редакторами nano или vim:

Настройка локального сервера SMTP (Вариант №3)

Вы можете проверить функционал почты, запустив локальный сервер отладки SMTP, используя изначально установленный модуль smptd. Вместо того, чтобы отправлять письма на определенный адрес, он отбрасывает их и выводит содержимое в консоль. Запуск локального сервера отладки означает, что нет необходимости работать с шифрованием сообщений или использовать учетные данные для входа на сервер электронной почты.

Вы можете запустить локальный сервер отладки SMTP внеся следующее в командную строку:

На Линуксе используйте ту же команду, которая предшествует sudo.
Любые письма, отправленные через этот сервер будут отброшены и отображены в окне терминала в качестве байтового объекта для каждой строки:

До конца данной статьи будет подразумеваться, что вы используете аккаунт Gmail, но если вы используете локальный сервер отладки, убедитесь в том, что используете свой локальный хост в качестве SMTP сервера и используйте порт 1025 вместо 465 или 587. Кроме того, вам не нужно использовать login() или шифровать сообщения с использованием SSL/TLS.

Отправка письма через smtplib Python

Перед тем как мы перейдем к отправке писем с HTML содержимым и вложениями, нам нужно научиться отправлять текстовые письма при помощи Python. Есть письма, которые вы можете написать в простом текстовом редакторе. Мы обойдемся без роскоши, вроде форматирования текста и гиперссылок. О них мы узнаем позже.

Запуск безопасного подключения SMTP

Когда вы отправляете письма через Python, следует убедиться в том, что ваше подключение SMTP зашифровано, чтобы никто не получил доступ к данным вашего письма или логина. SSL (Secure Sockets Layer) и TLS (Transport Layer Security) — два протокола, которые могут быть использованы для шифровки SMTP подключения. Их использование при работе с локальным сервером отладки является необязательным.

Есть два способа запустить безопасное подключение с вашим почтовым сервером:

  • Запустить подключение SMTP, которое изначально является безопасным при помощи SMTP_SSL().
  • Запустить незащищенное подключение SMTP, которое может быть зашифровано при помощи .starttls().

В обоих случаях, Gmail зашифрует письма при помощи TLS, так как это наиболее безопасный преемник SSL. Согласно соображениям безопасности Python, настоятельно рекомендуется использовать create_default_context() из модуля ssl.

Таким образом это даст возможность запустить доверенные сертификаты CA, включить проверку имени хоста, валидацию сертификата, а также возможность выбрать безопасный протокол и настройки шифра.

Если вы хотите проверить шифровку для письма во входящих Gmail, перейдите в More → Show original, чтобы увидеть тип шифровки, внесенный под заголовком Received.

smtplib — это встроенный модуль Python, предназначенный для отправки писем на любой компьютер с SMTP или ESMTP.

Сначала я покажу вам как использовать SMTP_SSL(), так как он с самого начала создает безопасное подключение и является более лаконичным, чем альтернатива в лице .starttls().

Использование SMTP_SSL() в smtplib

Пример кода внизу создает безопасное подключение с сервером Gmail SMTP, используя SMTP_SSL() или smtplib для создания зашифрованного TLS подключения. Контест ssl по умолчанию проверяет имя хоста и его сертификаты, а также оптимизирует безопасность подключения. Убедитесь в том, что вы ввели собственный почтовый ящик, вместо my@gmail.com:

Использование smtplib.SMTP_SSL() в качестве сервера подтверждает автоматическое закрытие подключения в конце определенного блока кода. Если порт равен нулю или не определен, .SMTP_SSL() использует стандартный порт для SMTP в SSL (порт 465).

Хранить пароль от почты в коде — не самая здравая идея с точки зрения безопасности, особенно если вы планируете рассылать его (код) другим. Вместо этого, используйте input(), чтобы дать пользователю ввести его пароль при запуске скрипта, как в указанном ранее примере. Если вы не хотите, чтобы ваш пароль отображался на экране, когда вы его вводите, вы можете импортировать модуль getpass и использовать .getpass() для слепого ввода.

Использование .starttls() в smtplib Python

Вместо использования .SMTP_SSL() для создания подключения, которое будет безопасным с самого начала, мы можем создать небезопасное подключение SMTP и зашифровать его при помощи .starttls().

Чтобы сделать это, нужно создать экземпляр smtplib.SMTP, который инкапсулирует SMTP-соединение и позволяет получить доступ к его методам. Я рекомендую определить ваш сервер SMTP и порт в начале скрипта, чтобы без проблем его настроить.

Часть кода внизу использует конструкцию server = SMTP() вместо формата SMTP() в качестве сервера, как мы делали в прошлом примере. Чтобы убедиться в том, что ваш код не сломается, если что-то пойдет не так, поместите ваш основной код в блок try, и дайте блоку except выводить любые сообщения об ошибки в stdout:

Для определения себя на сервере, нужно вызвать .helo() (SMTP) или .ehlo() (ESMTP) после создания объекта .SMTP(), и еще раз после .starttls(). Эта функция неявно вызывается .starttls() и .sendmail() по необходимости, так что если вы не хотите проверять расширения сервера SMTP, нет необходимости явно использовать .helo() и .ehlo().

Отправка текстового письма из Python smtplib

После установки безопасного подключения SMTP любым из вышеперечисленных методов, вы можете отправлять свою почту при помощи .sendmail():

Я рекомендую определить почтовые адреса и содержимое письма вверху вашего скрипта, после импортирования, чтобы легко их поменять:

Строка message начинается с "Subject: Привет!", за которым следуют две новых строки (\n). Это гарантирует, что Привет! будет отображаться как тема письма, а текст, следующий за пустыми строками (\n) будет расценен как тело письма.

Пример кода ниже отправляет текстовое письмо, используя SMTP_SSL():

Для сравнения, есть пример кода, который отправляет письмо со сплошным текстом через подключение SMTP, которое защищено при помощи .starttls(). Строки server.ehlo() могут быть опущены, так как они уже вызваны .starttls() и .sendmail(). При необходимости:

Отправка HTML писем из модуля smtplib Python

Встроенный пакет Python email позволяет вам конструировать более сложные письма, которые затем могут быть отправлены при помощи smptlib, как мы делали ранее. Ниже вы узнаете, как использовать пакет email для отправки писем с HTML содержимым и вложениями.

HTML оформление письма для отправки

Если вы хотите отформатировать текст внутри вашего письма (сделать шрифт жирным, косым, и т.д.), или если вы хотите добавить какие-либо изображения, гиперссылки, или адаптивный контент, то HTML придется кстати. Сегодня самым популярным типом писем является универсальная почта MIME (Multipurpose Internet Mail Extensions (универсальные почтовые интернет расширения), включающая HTML и текст. MIME письма обрабатываются модулем Python под названием email.mime. Вы можете обратиться к документации для дополнительной информации.

Так как не все почтовые клиенты отображают HTML содержимое по умолчанию, и некоторые пользователи предпочитают получать только текстовые письма из соображений безопасности, важно уметь вносить текстовую альтернативу HTML сообщениям. Так как почтовый клиент сначала будет обрабатывать последнее составное вложение, убедитесь в том, что вносите HTML сообщение после текстовой версии.

В нашем примере ниже, наши объекты MIMEText() будут содержать HTML и текстовую версии нашего сообщение, и экземпляр MIMEMultipart("alternative") соединяет их в одно сообщение с двумя альтернативными опциями рендеринга:

В данном примере, вы сначала определяете обычный текст, и HTML сообщение как строковые литералы, и затем сохраняете их как plain/html объекты MIMEText. Затем это можно внести в таком же порядке в сообщение MIMEMultipart("alternative") и отправить через ваше безопасное подключение с почтовым сервером. Обратите внимание на то, что следует внести HTML сообщение после текстовой альтернативы, так как почтовый клиент попытается отобразить последнюю подчасть в первую очередь.

Прикрепление вложений при помощи пакета email

Чтобы отправлять бинарные файлы на почтовый сервер, который создан для работы с текстовыми данными, сначала их нужно закодировать перед отправкой. Обычно это делается при помощи base64, который шифрует бинарные данные в читаемые символы ASCII.

Пример кода ниже показывает, как отправить письмо с PDF файлом в качестве вложения:

Сообщение MIMEultipart() принимает параметры в форме RFC5233-стиля пар ключ/значение, которые хранятся в словаре и передаются методу .add_header основного класса Message.

Ознакомьтесь с документацией модуля Python под названием email.mime, чтобы узнать больше об использовании классов MIME.

Отправка нескольких персонализированных писем из smtplib

Представьте, что вам нужно отправить письма членам вашей компании, чтобы напомнить о тех или иных платежах. Или, возможно вам нужно разослать своим студентам персонализированные письма с оценками их недавних работ. Такие задачи — проще простого для Python.

Создание CSV файла с релевантными персональными данными

Простая отправная точка для отправки множества персонализированных писем — это создание CSV (Сomma-Separated Values т.е. значения через запятую) файла, который содержит все необходимые персональные данные. (Убедитесь в том, что не распространяет чужие приватные данные без разрешения). Файл CSV может быть рассмотрен как простая таблица, где первая строка зачастую содержит заголовки столбцов.

Ниже указано содержимое файла contacts_file.csv, который я сохранил в той же папке, что и мой код Python. Он содержит имена, адреса, и оценки определенной группы лиц. Я использовал конструкции my+modifier@gmail.com, чтобы убедиться в том, что все письма попадают на мою личную почту, адрес которой — my@gmail.com (в данной статье):

При создании CSV файла, убедитесь в том, что вы разделили ваши значения запятой, без каких-либо пробелов.

Цикл по строкам для отправки нескольких писем

Пример кода ниже показывает, как открыть файл CSV и зациклить его по его строкам контента (за исключением заглавного ряда). Чтобы убедиться в том, что код работает правильно, перед тем как вы отправите письма всем контактам, я ввел Отправка письма для … для каждого контакта. Позже это можно заменить функционалом, который на деле отсылает письма:

В примере выше, использование open(filename) в качестве файла гарантирует, что ваш файл закроется в конце блока кода. Наш csv.reader() упрощает чтение CSV файла построчно и извлекает его значения. Строка next(reader) пропускает заглавный ряд, так что следующие строки с name, email, grade в рендере: разбивает последующие строки на каждой запятой, и хранит итоговые значения в строках имя, почта и оценка для каждого контакта.

Если значения в вашем файле CSV содержат пробелы (на любой из сторон), вы можете убрать их при помощи метода .strip().

Персонализированный контент в письмах smtplib Python

Вы можете добавить персонализированный контент в сообщение, используя str.format() для заполнения фигурных скобок. Например, "Привет, {name} ты {result} экзамен".format(name="Мария", result="сдала") даст вам "Привет, Мария ты сдала экзамен".

Начиная с Python 3.6, форматирование строк может быть выполнено более элегантно благодаря f-строкам, но для этого нужны фигурные скобки были определены перед этими f-строками. Чтобы определить почтовое сообщение в начале скрипта, и заполнить фигурные скобки для каждого контакта при цикле по CSV файлу, используется метод .format().

Держа это в уме, вы можете настроить общее тело письма с заполнителями, которые могут быть адаптированы для определенных лиц.

Пример персонализированных email рассылки через smtplib Python

Следующий пример кода позволит вам отправлять персонализированные письма нескольким контактам. Он запускает цикл по файлу CSV с названием, почтой, и оценкой для каждого контакта, как и в вышеуказанном примере.

Общее сообщение определено в начале скрипта, и для каждого контакта в CSV файле, фигурные скобки {name} и {grade} являются заполненными, а персонализированное письмо отправляется через безопасное подключение с сервером Gmail, как мы видели ранее:

Библиотека Yagmail для отправки писем из Python

Существует несколько библиотек, разработанных для упрощения отправки писем, такие как Envelopes, Flanker и Yagmail. Yagmail разработан специально для работы с Gmail, и эта библиотека значительно упрощает процесс отправки писем, благодаря дружелюбному API, как вы можете видеть в примере кода ниже:

Этот пример кода отправляет письмо с PDF вложением в виде нескольких строк, необходимых для нашего примера, с использованием email и smtplib.

При настройке Yagmail, вы можете внести свою проверку Gmail в связку ключей вашей ОС, как указано в документации. Если вы не сделаете этого, Yagmail попросит вас ввести пароль при необходимости, и хранить его в связке ключей автоматически.

Почтовые сервисы для рассылки писем

Если вы планируете отправлять большие объемы писем, и хотите видеть статистику писем, а также надежную доставку, возможно стоит рассмотреть вариант сторонних почтовых сервисов. Кстати, все указанные сервисы имеют ценник на отправку больших объемов писем, однако имеют и бесплатные функции, так что вы можете спокойно ими пользоваться. Некоторые из этих бесплатных опций действительны неограниченное время и могут быть более чем достаточными для ваших почтовых нужд.

Внизу расположен обзор бесплатных функций у некоторых из самых крупных почтовых сервисов.

Провайдер \ бесплатный план

  • SendPulse 6000 писем в месяц бесплатно
  • Sendinblue 300 писем/день
  • Mailgun первые 10,000 писем бесплатно
  • Mailjet 200 писем/день
  • Amazon SES 62,000 писем/месяц

Вы можете провести исследование, чтобы узнать, какой провайдер лучше всего подходит для ваших нужд, или просто попробовать несколько бесплатных планов, чтобы узнать, какой API вам лучше всего подходит.

Подведём итоги

Теперь вы можете запустить безопасное SMTP подключение и отправить несколько персонализированных писем людям в вашем локальном списке!

Вы научились отправлять HTML письма с альтернативным текстом и прикреплять файлы в ваши письма. Пакет Yagmail упрощает все эти задачи когда вы используете аккаунт Gmail. Если вы планируете отправлять большие объемы писем, стоит принять во внимание сторонние почтовые сервисы.