Основы программирования в Python

Алла Тамбовцева, НИУ ВШЭ

Как создать рассылку email в Python

Частично основано на следующих источниках:

  • gist от nickoala
  • gist от robulouski

Как отправить email

Сегодня мы посмотрим, как можно рассылать электронные письма средствами Python. Импортируем библиотеку smtplib для доступа к gmail.com и библиотеку email для создания текста письма (а именно, функцию MIMEText).

In [1]:
import smtplib
from email.mime.text import MIMEText

Укажем название хоста и порт для безопасного доступа к gmail.

In [2]:
host = 'smtp.gmail.com'
port = 465

Теперь можем ввести свои логин и пароль:

In [11]:
user = '[email protected]'  
password = '1234'  # your password here

При работе с ящиком gmail в связи с настройками безопасности можно столкнуться с проблемой: Gmail не позволит подключиться к ящику через Python, поскольку посчитает его сторонним подозрительным приложением. Чтобы избежать этого, давайте заранее изменим настройки безопасности (после работы в Python очень рекомендуется вернуть всё на место). Зайдем на почту, кликнем на фотографию, выберем Аккаунт Google, затем Безопасность, и включим доступ в разделе Ненадежные приложения, у которых есть доступ к аккаунту.

Теперь сообщим Python, с какого адреса и кому мы будем отправлять сообщение. Пока я отправлю письмо самой себе, но создам при этом список адресатов to, который можно расширять:

In [5]:
from_user = user
to = ['[email protected]'] 

Сохраним строку с текстом письма в text, а затем превратим его в объект сообщение:

In [6]:
text = 'I did it!'
msg = MIMEText(text)

Посмотрим, что внутри:

In [7]:
print(msg)
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

I did it!

Теперь добавим тему письма, укажем отправителя и получателя:

In [8]:
msg['Subject'] = 'Python'
msg['From'] = from_user
msg['To'] = ', '.join(to)  # склеим всех адресатов в списке (подойдет для рассылки)

Снова посмотрим на сообщение:

In [9]:
print(msg)
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Python
From: [email protected]
To: [email protected]

I did it!

Письмо готово! Осталось его отправить. Подключимся к серверу, введём логин и пароль:

In [12]:
server = smtplib.SMTP_SSL(host, port)
server.login(user, password)
Out[12]:
(235, b'2.7.0 Accepted')

Если вы получили ошибку SMTPAuthenticationError, а адрес почты и пароль указаны верно, проверьте, что вы изменили настройки безопасности.

Отправляем письмо:

In [13]:
server.sendmail(from_user, to, msg.as_string())
Out[13]:
{}

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

Теперь давайте сделаем что-нибудь поинтереснее: прикрепим к письму приложение-картинку (ссылка).

python

Для этого нам понадобится функция MIMEMultipart() для создания письма из нескольким частей и функция MIMEImage() для добавления изображения.

In [14]:
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

Так как изображение будем брать с компьютера, импортируем ещё модуль os (от operation system).

In [15]:
import os

Создадим сообщение из нескольких частей (типа Multipart), добавим тему письма, отправителя и получателя:

In [16]:
msg2 = MIMEMultipart()
msg2['Subject'] = 'Hello from Python'
msg2['From'] = from_user
msg2['To'] = ', '.join(to)

Прикрепим текст письма:

In [17]:
text = "Python is missing you."
text_part = MIMEText(text)
msg2.attach(text_part)

Выберем изображение, которое мы хотим прикрепить и откроем его:

In [18]:
filepath = '/Users/allat/Desktop/python.png'
with open(filepath, 'rb') as f:
    img = MIMEImage(f.read())

Прикрепим изображение к сообщению msg2, предварительно добавив ему название (совпадает с названием файла, как обычно):

In [19]:
img.add_header('Content-Disposition',
               'attachment',
               filename=os.path.basename(filepath))
msg2.attach(img)

Осталось отправить письмо:

In [20]:
server.sendmail(from_user, to, msg2.as_string())
Out[20]:
{}

Готово! Теперь посмотрим, как можно организовать рассылку на основе имён и адресов, сохранённых в таблице. И заодно закидаем питонами тех, кто не пришёл на пары :)

Импортируем библиотеку pandas и функцию sleep для добавления задержки по времени после каждого письма:

In [22]:
import pandas as pd
from time import sleep

Создадим датафрейм из вложенного списка:

In [23]:
students = [['Alla', '[email protected]'],
           ['Not alla', '[email protected]']]
In [24]:
df = pd.DataFrame(students)
df.columns = ['name', 'mail']
df
Out[24]:
name mail
0 Alla [email protected]
1 Not alla [email protected]

Загрузим картинку (ту же, что и в первый раз):

In [25]:
filepath = '/Users/allat/Desktop/python.png'
with open(filepath, 'rb') as f:
    img = MIMEImage(f.read())

img.add_header('Content-Disposition',
               'attachment',
               filename=os.path.basename(filepath))

Напишем цикл для пары имя-адрес в датафрейме df и включим в него шаблон текста письма, в который будет подставляться имя адресата:

In [28]:
for name, mail in zip(df.name, df.mail):
    
    text = f"""Dear {name}, \n 
    Why are you absent? Python is missing you. \n
    We are learning to send emails from Python now, never mind. """
    
    msg = MIMEMultipart()
    text_part = MIMEText(text)
    msg.attach(text_part)
    msg['Subject'] = 'Hello from Python'
    msg['From'] = from_user
    msg['To'] = mail
    
    msg.attach(img)
    
    server.sendmail(from_user, mail, msg.as_string())

Done!