В нашем блоге мы много пишем о создании email-рассылок и работе с электронной почтой. В современном мире люди получают множество писем, а у некоторых даже есть несколько почтовых ящиков. Все это усложняет процесс их администрирования, что вынуждает искать пути решения проблемы. Не так давно мы рассказывали о том, как инженер из США упорядочивал свои письма с помощью нейронной сети (1, 2), а сегодня речь пойдет об автоматизации отправки писем для разных почтовых ящиков.

Редактор издания Motherboard Майкл Берн (Michael Byrne) написал материал о том, как отправлять электронные письма для различных почтовых ящиков с помощью Python. Мы представляем вашему вниманию адаптированный перевод этой заметки.

Берн пишет, что у него есть целых пять электронных ящиков: один личный, два университетских и два рабочих. Есть ещё и шестой, который он иногда использует, когда нужно быстро где-то зарегистрироваться. Немалая часть жизни журналиста состоит из быстрого просмотра и сортировки электронных писем, их удаления, добавления в избранное, и даже чтения этих писем и ответа на них. Берн говорит, что даже не хочет задумываться о том, сколько на все это уходит времени каждый день.

Журналист признается, что однажды в шутку подумал, что ему надо нанять помощника для управления своей электронной почтой. Это, в свою очередь, привело к размышлениям о том, какие указания такому сотруднику надо было бы давать: «Если в письме есть то-то и то-то, сделай одно, или если вот это так, сделай кое-что другое». Это был бы определённый набор правил, применённый к письмам.

Но когда я вижу словосочетание «набор правил», я сразу думаю о написании компьютерных программ. Пролистывая свои письма, я понимаю, что было бы разумно воплотить моего помощника в компьютерном коде.

Тем не менее, чтобы сделать это, необходимо каким-то образом связать электронные ящики с программой для чтения писем. Это делается довольно просто. На самом деле, электронные письма – это набор текстовых протоколов для передачи информации между сетями; как и весь остальной интернет, в общем. Всё это лишь несколько уровней протоколов. То, как мы представляем себе электронную почту, отображает лишь ее интерфейс.

Даже если вы не хотите создавать сортирующую письма программу, управлять электронными письмами как набором данных довольно интересно. Берн решил использовать для решения задачи Python, так как этот язык действительно хорош для лёгкого и интуитивного создания подобных вещей, и подходит даже для не-программистов. Последующие инструкции частично основаны на главе про автоматизацию электронной почты из книги Эла Свейгарта (Al Sweigart) «Automate the Boring Stuff with Python», которую журналист очень рекомендую и как введение в программирование, и как справочное руководство для тех, кто хочет повеселиться с автоматизацией. Эта книга доступна бесплатно под лицензией Creative Commons на automatetheboringstuff.com.

Для начала потребуется скачать Python (если он еще не установлен). Также потребуется любой простой текстовый редактор. Отлично подойдет Sublime Text — его можно скачать здесь. ST не бесплатный, но в тестовом режиме им можно пользоваться бесконечно, хоть иногда и будет появляться предложение о покупке. Но своих денег он стоит.

Python можно использовать в двух режимах. Первый – это командный интерпретатор, где пользователь вводит команды или сниппеты на Python в консоль, и они сразу же выполняются (например, print(«Hello, World!»)). Второй режим – это скрипты на Python. По сути, это просто набор команд на Python в одном или нескольких файлах, которые могут быть вызваны одновременно из консоли. Фактически, эти файлы – это программы: иногда маленькие и простые (как то, что мы рассмотрим дальше), они могут разрастаться до больших проектов.

Если вы только что скачали Python, вам нужно сделать ещё две вещи перед тем, как начать. Первое: прочтите краткое руководство про написание «Hello, World!» на Python. Второе: уделите пять минут прочтению руководства по использованию модулей в Python. Установка и импорт расширений Python производятся предельно просто.

Итак, начнём.

0) Протоколы для получения почты: краткое руководство


Существуют три основных протокола для работы с электронной почтой. Самый старый из них называется POP (Post Office Protocol). Его суть в том, что программное обеспечение для работы с электронной почтой (не браузер) подключается к удалённому серверу, скачивает письма на компьютер пользователя, и они становятся доступны без подключения к интернету. Это было хорошей идеей в те времена, когда к интернету подключались нечасто, и было нормальным не иметь выхода в Сеть, но в настоящее время такого почти не бывает.

Текущим стандартом доступа к электронным ящикам является протокол IMAP (Internet Message Access Protocol). Он намного быстрее и больше соответствует тому, как интернет используется в наши дни. Он позволяет нескольким пользователям подключаться к одному ящику и поддерживает их соединение в течение всей сессии.
Веб-браузеры получают доступ к электронной почте с помощью дополнительного протокола – HTTP, но в основе лежат всё те же POP и IMAP.

В основном для получения писем с сервера используются POP (актуальная версия POP3) и IMAP. Но для того чтобы отправить письмо, нужен другой протокол – SMTP (Simple Mail Transfer Protocol). Всё потому, что нельзя просто отправить письмо получателю. Его нужно отправить на сервер, с которого получатель это письмо скачает, используя IMAP и POP3.

1) Подключение SMTP-модуля Python


Для начала нам нужен подходящий модуль Python. Smtplib поставляется вместе с Python, поэтому не нужно предпринимать дополнительных действий, достаточно просто ввести эту строку в консоль:

import smtplib

Для получения справки по модулю (и чтобы удостовериться, что он подключился), можно использовать функцию help:

help(smtplib)

Следует отметить, что эта функция работает с любым модулем.

2) Подключение к серверу электронной почты


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

В данном случае функция, возвращающая необходимый объект, принимает два параметра или аргумента. Первый аргумент содержит доменное имя, то есть адрес электронной почты, начинающийся с «smtp», как показано ниже. Второй аргумент – это номер порта, к которому будет осуществляться подключение на сервере электронной почты. Он почти всегда принимает значение 587 в соответствии со стандартом шифрования TLS. Очень редко встречаются сервисы, использующие порт 465.

Итак, нужно написать следующее:

smtpObj = smtplib.SMTP('smtp.gmail.com', 587)

Получается, что переменная smtpObj является объектом типа SMTP. В этом можно убедиться, если ввести имя переменной в консоль и подтвердить ввод. На экране появятся адрес её ячейки памяти и тип (при условии, что вы ввели предыдущую команду правильно). Переменную smtpObj можно назвать, как угодно, лишь бы это было допустимое в Python имя переменной.

3) Шифрование


Следующее, что нужно сделать для установления соединения, это «сказать» SMTP-объекту, что сообщение должно быть зашифровано. Для этого следует ввести в консоль эту строку и нажать Enter:

smtpObj.starttls()

Вот что мы сделали: мы сообщили Gmail, что хотим, чтобы наше соединение шифровалось с помощью протокола TLS (Transport Layer Security), который на сегодняшний день является стандартом для интернет-коммуникаций. Сам по себе TLS не является криптографическим алгоритмом, он скорее сообщает, что необходимо использовать шифрование или соединение не должно быть установлено.

В ответ вы должны получить подтверждение:

2.0.0 Ready to start TLS 

Важный момент — если пропустить этот шаг и сразу перейти к авторизации, то на экране появятся сообщения об ошибках. Всё потому, что Gmail применяет шифрование с использованием протокола HTTPS, то есть всё тот же НТТР, «обёрнутый» в дополнительный TLS-протокол.

5) Авторизация


Для того чтобы авторизоваться, нужно всего лишь написать

smtpObj.login('justkiddingboat@gmail.com','just123kidding')

На данном этапе пароль от электронной почты, так сказать, улетает в неизвестность, что довольно опасно. Это не проблема на локальном компьютере, но если вы действительно автоматизируете работу с электронной почтой с помощью скрипта на Python, то нужно проявить осторожность и дважды подумать, прежде чем публиковать код скрипта где-либо или загружать файл с ним на сторонние площадки.

5) Отправка сообщения


Плюс использования сред с командным интерпретатором заключается в том, что даже при отсутствии какой-либо информации — например, описания отправки письма — можно спросить об этом сам интерпретатор. Для этого нужно просто ввести следующую команду:

help(smtpObj)

Немного поскроллив страницу можно увидеть нужный метод:



Интерпретатор даже выведет пример его использования:



Заметьте, что в примере выше отсутствует команда авторизации. Это связано с тем, что программа подключалась к компьютеру пользователя, а не к удалённому серверу электронной почты. Для нашего случая напишем следующее:

smtpObj.sendmail("justkiddingboat@gmail.com","michael.byrne@vice.com","go to bed!")


Сработало!



6) Завершение соединения


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

smtpObj.quit()

Естественно, отправка сообщений – это всего лишь малая часть того, что можно делать с электронной почтой с помощью Python. Берн советует продолжить обучение с книгой Свейгарта, чтобы узнать, как работать с электронной почтой, используя IMAP.

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

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

Комментарии (8)


  1. dezconnect
    19.04.2016 13:05
    +9

    Ждем статей на хабре в духе «Как написать Hello, world На Python/PHP/VisualBasic»


  1. Nicknnn
    19.04.2016 13:40

    Для прочитавших статью.
    Попробовали? Поигрались? И достаточно. А теперь идём сюда Python email и изучаем как правильно составляется письмо, чтоб оно не улетало в спам и не выглядело «странно».


  1. fareloz
    19.04.2016 18:10

    Если хотите отправлять через gmail и у вас стоит двухфаторная авторизация (по номеру телефона) — не забудьте создать «пароль для приложения» и использовать его в скрипте


  1. asakasinsky
    19.04.2016 18:26

    Такая важная часть, как заголовки, совсем не освещена.

    По ссылке я выложил скрипт из рабочей системы рассылки писем в фоновом режиме. Может использоваться как sendmail, так и smtp.
    https://gist.github.com/asakasinsky/1e4fc7a2b809ff8c01da0cbcf9ba9e1c

    mailer.py — это celery-задача, в которую передаётся шаблон письма html и plain-text, тема рассылки, список получателей, и отправитель.
    sendmail.py — реализация отправления письма

    В качестве MTA используется postfix, настроенный по этой инструкции:
    https://github.com/asakasinsky/Development-book/blob/master/UsefulThings/MailServerSettings.md

    Решение наколенное и местами очень корявое, но оно оказалось способным рассылать несколько десятков тысяч писем. Нет ничего более постоянного, чем временное решение.


  1. ALexhha
    20.04.2016 18:58

    > Для того чтобы авторизоваться, нужно всего лишь написать
    > smtpObj.login('justkiddingboat@gmail.com','just123kidding')

    это аутентификация, а не авторизация. Почему то многие часто путают авторизацию и аутентификацию.

    Аутентификация — проверка логина и пароля по определенному алгоритму, например, PLAIN/LOGIN/CRAM-MD5.

    Авторизация — проверка прав пользователя, который прошел аутентификацию. Например, мы разрешаем отправлять пользователю justkiddingboat@gmail.com письма только на один адрес user@example.com


  1. anton44eg
    20.04.2016 18:58
    +1

    Пожалуйста, используйте PEP8. Это одна из вещей, которая делает Python прекрасным


  1. tessio
    20.04.2016 18:59

    Ровно это же написано в документации… docs.python.org/3/library/smtplib.html


  1. saw_tooth
    20.04.2016 18:59

    Статья несомненно полезная для совсем новичков, но я думаю переводчику следовало б добавить какие-либо решения или возможности от себя: рассылка, или может поддержку шаблонов писем. В данном контексте это перевод документации модуля, не более…