01 |
Рано или поздно практически у каждого разработчика возникает задача отправки электронной почты. Часто это связано с необходимостью информирования получателя о наступлении какого-нибудь события. |
|
02 | На заметку: |
Материалы данной статьи используются в статье о камере для Raspberry Pi 3, в разделе о построении простой системы безопасности, суть которой заключается в отправке фотографии пользователю по электронке, при детектировании движения в зоне действия датчика.
|
|
03 |
Для отправки письма по электронной почте используется штатная, предустановленная в системе, библиотека smtplib: |
|
04 | Python |
1 import smtplib |
|
05 | На заметку: |
Для получения справки о любом импортированном классе или библиотеке, в интерпретаторе Python, после непосредственно импорта, нужно выполнить команду:
1 2 >>> import smtplib
>>> help(smtplib) Или из скетча — вывод в консоль через функцию print(): 1 2 import smtplib
print(help(smtplib)) |
|
06 |
Для отправки писем можно использовать любой имеющийся у пользователя почтовый ящик. Настройки каждого почтового провайдера открыто предоставляются каждым из них: |
|
07 |
Для упрощения работы с письмами понадобится пакет email. Он позволяет работать с сообщениями электронной почты как с отдельными объектами. Пакет содержит также подклассы, описывающие различные MIME-типы. Для работы понадобятся 2 из них — MIMEMultipart и MIMEText: |
|
08 | Python |
1 2 3 import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText |
|
09 |
Общий шаблон отправки сообщения выглядит так: |
|
10 | Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import smtplib # Импортируем библиотеку по работе с SMTP
# Добавляем необходимые подклассы - MIME-типы
from email.mime.multipart import MIMEMultipart # Многокомпонентный объект
from email.mime.text import MIMEText # Текст/HTML
from email.mime.image import MIMEImage # Изображения
addr_from = "from_address@mail.com" # Адресат
addr_to = "to_address@mail.com" # Получатель
password = "pass" # Пароль
msg = MIMEMultipart() # Создаем сообщение
msg['From'] = addr_from # Адресат
msg['To'] = addr_to # Получатель
msg['Subject'] = 'Тема сообщения' # Тема сообщения
body = "Текст сообщения"
msg.attach(MIMEText(body, 'plain')) # Добавляем в сообщение текст
server = smtplib.SMTP('smtp-server', 587) # Создаем объект SMTP
server.set_debuglevel(True) # Включаем режим отладки - если отчет не нужен, строку можно закомментировать
server.starttls() # Начинаем шифрованный обмен по TLS
server.login(addr_from, password) # Получаем доступ
server.send_message(msg) # Отправляем сообщение
server.quit() # Выходим |
|
11 |
Если необходимо добавить HTML-фрагмент, нужно присоединить к объекту msg ещё один подкласс: |
|
12 | Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import smtplib # Импортируем библиотеку по работе с SMTP
# Добавляем необходимые подклассы - MIME-типы
from email.mime.multipart import MIMEMultipart # Многокомпонентный объект
from email.mime.text import MIMEText # Текст/HTML
from email.mime.image import MIMEImage # Изображения
addr_from = "from_address@gmail.com" # Адресат
addr_to = "to_address@gmail.com" # Получатель
password = "pass" # Пароль
msg = MIMEMultipart() # Создаем сообщение
msg['From'] = addr_from # Адресат
msg['To'] = addr_to # Получатель
msg['Subject'] = 'Тема сообщения' # Тема сообщения
body = "Текст сообщения"
msg.attach(MIMEText(body, 'plain')) # Добавляем в сообщение текст
html = """\
<html>
<head></head>
<body>
<p>
Фрагмент HTML-кода
</p>
</body>
</html>
"""
msg.attach(MIMEText(html, 'html', 'utf-8')) # Добавляем в сообщение HTML-фрагмент
server = smtplib.SMTP('smtp-server', 587) # Создаем объект SMTP
server.set_debuglevel(True) # Включаем режим отладки - если отчет не нужен, строку можно закомментировать
server.starttls() # Начинаем шифрованный обмен по TLS
server.login(addr_from, password) # Получаем доступ
server.send_message(msg) # Отправляем сообщение
server.quit() # Выходим |
|
13 | На заметку: |
В случае проблем с кодировкой, для тех полей, которым это необходимо, её необходимо указывать явно:
1 2 3 msg.attach(MIMEText(body, 'html', 'utf-8'))
# или
msg['Subject'] = Header('Тема сообщения', 'utf-8') |
|
14 | Важно: |
При включении режима отладки server.set_debuglevel(True) вся информация о процессе будет выводиться в консоль оболочки Shell. Это скажется на производительности, особенно в случаях вложения в отправление файлов.
При наличии вложений, использовать отладку server.set_debuglevel(True) не рекомендуется! |
|
15 |
По такому же принципу к сообщению добавляются файлы — создаются экземпляры соответствующих подклассов и присоединяются к объекту msg. Код для включения различных типов файлов представлен ниже. Также необходимо импортировать дополнительные MIME-типы, энкодеры и библиотеки: |
|
16 | Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import mimetypes # Импорт класса для обработки неизвестных MIME-типов, базирующихся на расширении файла
from email import encoders # Импортируем энкодер
from email.mime.base import MIMEBase # Общий тип
from email.mime.text import MIMEText # Текст/HTML
from email.mime.image import MIMEImage # Изображения
from email.mime.audio import MIMEAudio # Аудио
# ...
filepath="full_file_path_with_filename" # Имя файла в абсолютном или относительном формате
filename = os.path.basename(filepath) # Только имя файла
if os.path.isfile(filepath): # Если файл существует
ctype, encoding = mimetypes.guess_type(filepath) # Определяем тип файла на основе его расширения
if ctype is None or encoding is not None: # Если тип файла не определяется
ctype = 'application/octet-stream' # Будем использовать общий тип
maintype, subtype = ctype.split('/', 1) # Получаем тип и подтип
if maintype == 'text': # Если текстовый файл
with open(filepath) as fp: # Открываем файл для чтения
file = MIMEText(fp.read(), _subtype=subtype) # Используем тип MIMEText
fp.close() # После использования файл обязательно нужно закрыть
elif maintype == 'image': # Если изображение
with open(filepath, 'rb') as fp:
file = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
elif maintype == 'audio': # Если аудио
with open(filepath, 'rb') as fp:
file = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
else: # Неизвестный тип файла
with open(filepath, 'rb') as fp:
file = MIMEBase(maintype, subtype) # Используем общий MIME-тип
file.set_payload(fp.read()) # Добавляем содержимое общего типа (полезную нагрузку)
fp.close()
encoders.encode_base64(file) # Содержимое должно кодироваться как Base64
file.add_header('Content-Disposition', 'attachment', filename=filename) # Добавляем заголовки
msg.attach(file) # Присоединяем файл к сообщению |
|
17 |
После вынесения функционала отправки сообщения в отдельную функцию, полный код с примером использования будет выглядеть так: |
|
18 | Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import smtplib # Импортируем библиотеку по работе с SMTP
import os # Функции для работы с операционной системой, не зависящие от используемой операционной системы
# Добавляем необходимые подклассы - MIME-типы
import mimetypes # Импорт класса для обработки неизвестных MIME-типов, базирующихся на расширении файла
from email import encoders # Импортируем энкодер
from email.mime.base import MIMEBase # Общий тип
from email.mime.text import MIMEText # Текст/HTML
from email.mime.image import MIMEImage # Изображения
from email.mime.audio import MIMEAudio # Аудио
from email.mime.multipart import MIMEMultipart # Многокомпонентный объект
def send_email(addr_to, msg_subj, msg_text, files):
addr_from = "my_addr@server.ru" # Отправитель
password = "password" # Пароль
msg = MIMEMultipart() # Создаем сообщение
msg['From'] = addr_from # Адресат
msg['To'] = addr_to # Получатель
msg['Subject'] = msg_subj # Тема сообщения
body = msg_text # Текст сообщения
msg.attach(MIMEText(body, 'plain')) # Добавляем в сообщение текст
process_attachement(msg, files)
#======== Этот блок настраивается для каждого почтового провайдера отдельно ===============================================
server = smtplib.SMTP_SSL('smtp.server.ru', 465) # Создаем объект SMTP
#server.starttls() # Начинаем шифрованный обмен по TLS
#server.set_debuglevel(True) # Включаем режим отладки, если не нужен - можно закомментировать
server.login(addr_from, password) # Получаем доступ
server.send_message(msg) # Отправляем сообщение
server.quit() # Выходим
#==========================================================================================================================
def process_attachement(msg, files): # Функция по обработке списка, добавляемых к сообщению файлов
for f in files:
if os.path.isfile(f): # Если файл существует
attach_file(msg,f) # Добавляем файл к сообщению
elif os.path.exists(f): # Если путь не файл и существует, значит - папка
dir = os.listdir(f) # Получаем список файлов в папке
for file in dir: # Перебираем все файлы и...
attach_file(msg,f+"/"+file) # ...добавляем каждый файл к сообщению
def attach_file(msg, filepath): # Функция по добавлению конкретного файла к сообщению
filename = os.path.basename(filepath) # Получаем только имя файла
ctype, encoding = mimetypes.guess_type(filepath) # Определяем тип файла на основе его расширения
if ctype is None or encoding is not None: # Если тип файла не определяется
ctype = 'application/octet-stream' # Будем использовать общий тип
maintype, subtype = ctype.split('/', 1) # Получаем тип и подтип
if maintype == 'text': # Если текстовый файл
with open(filepath) as fp: # Открываем файл для чтения
file = MIMEText(fp.read(), _subtype=subtype) # Используем тип MIMEText
fp.close() # После использования файл обязательно нужно закрыть
elif maintype == 'image': # Если изображение
with open(filepath, 'rb') as fp:
file = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
elif maintype == 'audio': # Если аудио
with open(filepath, 'rb') as fp:
file = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
else: # Неизвестный тип файла
with open(filepath, 'rb') as fp:
file = MIMEBase(maintype, subtype) # Используем общий MIME-тип
file.set_payload(fp.read()) # Добавляем содержимое общего типа (полезную нагрузку)
fp.close()
encoders.encode_base64(file) # Содержимое должно кодироваться как Base64
file.add_header('Content-Disposition', 'attachment', filename=filename) # Добавляем заголовки
msg.attach(file) # Присоединяем файл к сообщению
# Использование функции send_email()
addr_to = "xxxx@server.ru" # Получатель
files = ["file1_path", # Список файлов, если вложений нет, то files=[]
"file2_path",
"dir1_path"] # Если нужно отправить все файлы из заданной папки, нужно указать её
send_email(addr_to, "Тема сообщения", "Текст сообщения", files) |
|
19 |
Результат: |
|
21 |
Но здесь нужно учитывать, что для разных почтовых провайдеров необходимо модифицировать строки отправки сообщения в соответствии с предоставляемыми настройками. О них далее. |
|
22 |
Gmail Компания Google очень беспокоится о безопасности своих пользователей, поэтому перед тем как начинать отправку сообщений, необходимо разрешить доступ к аккаунту для ненадежных приложений: |
|
24 |
Фрагмент кода для отправки почты, с использованием аккаунта ...@gmail.com: |
|
25 | Python |
1 2 3 4 5 server = smtplib.SMTP('smtp.gmail.com', 587) # Создаем объект SMTP
server.starttls() # Начинаем шифрованный обмен по TLS
server.login(addr_from, password) # Получаем доступ
server.send_message(msg) # Отправляем сообщение
server.quit() # Выходим |
|
26 |
Mail.ru Несмотря на то, что Mail.ru указывает использовать порт 465 для обращения к SMTP-серверу, для корректной работы необходимо указывать порт 25: |
|
27 | Python |
1 2 3 4 5 server = smtplib.SMTP_SSL('smtp.mail.ru', 25) # Создаем объект SMTP
#server.starttls() # Начинаем шифрованный обмен по TLS
server.login(addr_from, password) # Получаем доступ
server.send_message(msg) # Отправляем сообщение
server.quit() # Выходим |
|
28 |
Yandex У Yandex используется порт 465 для обращения к SMTP-серверу (TLS не используется): |
|
29 | Python |
1 2 3 4 5 server = smtplib.SMTP_SSL('smtp.yandex.ru', 465) # Создаем объект SMTP
#server.starttls() # Начинаем шифрованный обмен по TLS
server.login(addr_from, password) # Получаем доступ
server.send_message(msg) # Отправляем сообщение
server.quit() # Выходим |
|
30 |
Что почитать: |
|
31 |
Похожие запросы:
|
|