Как отправить письмо (email) с помощью Python
Отправка почты выполняется с помощью smtplib Python с использованием Простой сервер протокола передачи почты (SMTP). Модуль smtplib определяет объект сеанса клиента SMTP, который можно использовать для отправки почты на любой Интернет-компьютер с помощью SMTP или ESMTP-прослушивателя.
Объекты электронной почты и MIME
Многоцелевые расширения электронной почты Интернета (MIME) — это интернет-стандарт, который расширяется по ограниченным возможностям электронной почты и, в частности, позволяет вставлять в сообщение документы (такие как изображения, звук и текст).
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText fromaddr = "youraddress@gmail.com" toaddr = "some other email address" msg = MIMEMultipart() msg['From'] = fromaddr msg['To'] = toaddr msg['Subject'] = "Test Subject" body = "Write your message here" msg.attach(MIMEText(body, 'plain')) server = smtplib.SMTP('smtp.gmail.com:587') server.starttls() server.login(fromaddr, "your password") text = msg.as_string() server.sendmail(fromaddr, toaddr, text) server.quit()
SMTPAuthenticationError при отправке почты с использованием gmail
Иногда при отправке электронной почты с использованием адреса gmail вы можете увидеть следующее сообщение об ошибке:
raise SMTPAuthenticationError(code, resp) smtplib.SMTPAuthenticationError.
Это связано с тем, что Google блокирует попытки входа из приложений, которые не используют современные стандарты безопасности (упомянутые на их странице поддержки). Однако вы можете включить / выключить эту функцию безопасности, перейдя по ссылке ниже:
Перейдите по этой ссылке и выберите «Включить»
Кроме того, Google блокирует ip при попытке отправить электронное письмо с необычного местоположения, поэтому вы можете разблокировать следующую ссылку
Настройки SMTP Gmail
Если вы используете Gmail для своей работы или учетной записи школы, обратитесь к администратору за правильной настройкой SMTP.
Как отправить письмо с помощью SMTPlib
SMTP — Simple Mail Transfer Protocol (Простой Протокол Передачи Почты). Но слово простой совсем не значит, что есть крутой. SMTP — самый популярный протокол для отправки почты между серверами.
По итогу этого туториала вы сможете правильно оформить своё письмо и отправить его по почте.
1. Оформите письмо с помощью заголовков
Чтобы отправить письмо, ваша программа должна связаться с сервером почтового сервиса (Gmail, Yandex, Mail.ru и т.д.) и передать ему всю нужную информацию: кому, от кого, что в письме. Протокол устанавливает правила, как должно выглядеть такое сообщение:
From: Адрес отправителя To: Адрес получателя Subject: Заголовок письма Content-Type: text/plain; charset="UTF-8"; Начало вашего текста .
Например, если нужно отправить письмо Привет! с адреса mymail@gmail.com на адрес friend@gmail.com с заголовком Важно! , сообщение должно выглядеть так:
From: mymail@gmail.com To: friend@gmail.com Subject: Важно! Content-Type: text/plain; charset="UTF-8"; Привет!
2. Закодируйте письмо
Русский язык не поддерживается в протоколе SMTP, поэтому письмо надо предварительно закодировать в UTF-8 . Вот как это делается:
letter = """\ From: mymail@gmail.com To: friend@gmail.com Subject: Важно! Content-Type: text/plain; charset="UTF-8"; Привет!""" letter = letter.encode("UTF-8") print(letter)
Вот что выведет этот код:
b'From: mymail@gmail.com\nTo: friend@gmail.com\nSubject: \xd0\x92\xd0\xb0\xd0\xb6\xd0\xbd\xd0\xbe!\nContent-Type: text/plain; charset="UTF-8";\n\n\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82!'
3. Подключитесь к почтовому сервису
С письмом понятно, но как же передать всё это серверу? Чтобы с ним общаться, нужно знать его адрес. Почтовые сайты сами публикуют адреса своих SMTP серверов.
Адреса для нескольких популярных сервисов:
| Сайт | Адрес сервера |
|---|---|
| Яндекс.Почта | smtp.yandex.ru:465 |
| GMail | smtp.gmail.com:465 |
| Mail.ru | smtp.mail.ru:465 |
Для примера возьмём Gmail. В первую очередь свяжемся с сервером:
import smtplib server = smtplib.SMTP_SSL('smtp.gmail.com:465')
Затем зайдём в свой почтовый ящик. Для этого передайте методу .login() свои логин и пароль:
import smtplib server = smtplib.SMTP_SSL('smtp.gmail.com:465') server.login(login, password)
4. Отправьте письмо
Теперь, когда письмо закодировано, его можно наконец-то отправить. Метод .sendmail() ждёт от вас 3 значения: от кого, кому и что передать. Да, вы уже указали это в письме, но придётся указать второй раз:
import smtplib server = smtplib.SMTP_SSL('smtp.gmail.com:465') server.login(login, password) server.sendmail(email_from, email_to, message) server.quit()
Обратите внимание, что в конце мы прощаемся с сервером методом .quit() , чтобы он больше не ждал от нас писем. Это правило хорошего тона. Соблюдать его не обязательно, но бездушной машине будет приятно.
Бонус: если хочется отправить письмо через Gmail
При запуске кода вы можете получить ошибку SSL такого вида:
smtplib ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1131)
Проблема связана с устаревшей версией протокола шифрования SSL. Чинится ошибка добавлением ещё нескольких строк кода с явным указанием номера версии. Подробно проблема обсуждается на StackOverflow.
... server = smtplib.SMTP('smtp.gmail.com:587') import ssl # переместите в шапку файла context = ssl.SSLContext(ssl.PROTOCOL_TLS) server.ehlo() server.starttls(context=context) server.ehlo() ...
При запуске код либо заработает, либо вывалится ошибка с кодом 535-5.7.8 :
SMTPAuthenticationError 535-5.7.8 Username and Password not accepted
Эта ошибка связана с настройками безопасности на Gmail. Зайдите из-под своего аккаунта на страницу Ненадежные приложения и разрешите доступ “Небезопасным приложениям”. Подробно проблема обсуждается на StackOverlfow.
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.
Как отправить письмо на почту с помощью Python?
Подскажите, понадобилось на python отправлять сообщение на почту yandex.
Нашел код, но вылетает ошибка.
Почитал, написано что ошибка может вылетать, так как пароль может быть не в кодировке utf-8.
Пишу в коде для password, addr_from, addr_to это: encode(encoding=’utf-8′) — ноль эмоций.
Подскажите, как тогда исправить ошибку?
import smtplib # Импортируем библиотеку по работе с SMTP # Добавляем необходимые подклассы - MIME-типы from email.mime.multipart import MIMEMultipart # Многокомпонентный объект from email.mime.text import MIMEText # Текст/HTML addr_from = "[email protected]" addr_to = "[email protected]" password = "pass" # пароль от почты addr_from msg = MIMEMultipart() # Создаем сообщение msg['From'] = addr_from # Адресат msg['To'] = addr_to # Получатель msg['Subject'] = 'Тема сообщения' # Тема сообщения body = "Текст сообщения" msg.attach(MIMEText(body, 'plain')) # Добавляем в сообщение текст server = smtplib.SMTP_SSL('smtp.yandex.ru', 465) # Создаем объект SMTP # server.starttls() # Начинаем шифрованный обмен по TLS server.login(addr_from, password) # Получаем доступ server.send_message(msg) # Отправляем сообщение server.quit() # Выходим
smtplib.SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed: This user does not have access rights to this service')
Python: Как отправить письмо на электронную почту с вложением
Рано или поздно практически у каждого разработчика возникает задача отправки электронной почты. Часто это связано с необходимостью информирования получателя о наступлении какого-нибудь события.
Материалы данной статьи используются в статье о камере для Raspberry Pi 3, в разделе о построении простой системы безопасности, суть которой заключается в отправке фотографии пользователю по электронке, при детектировании движения в зоне действия датчика.
Для отправки письма по электронной почте используется штатная, предустановленная в системе, библиотека smtplib :
import smtplib
Для получения справки о любом импортированном классе или библиотеке, в интерпретаторе Python, после непосредственно импорта, нужно выполнить команду:
>>> import smtplib >>> help (smtplib)
Или из скетча — вывод в консоль через функцию print() :
import smtplib print ( help (smtplib))
- Gmail — https://support.google.com/mail/answer/7126229?hl=ru
- Mail.ru — https://help.mail.ru/mail-help/mailer/popsmtp
- Yandex — https://yandex.ru/support/mail-new/mail-clients.html
Для упрощения работы с письмами понадобится пакет email . Он позволяет работать с сообщениями электронной почты как с отдельными объектами. Пакет содержит также подклассы, описывающие различные MIME-типы. Для работы понадобятся 2 из них — MIMEMultipart и MIMEText :
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
Общий шаблон отправки сообщения выглядит так:
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() # Выходим
Если необходимо добавить HTML-фрагмент, нужно присоединить к объекту msg ещё один подкласс:
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-кода
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() # Выходим
В случае проблем с кодировкой, для тех полей, которым это необходимо, её необходимо указывать явно:
msg.attach(MIMEText(body, ‘html’ , ‘utf-8’ )) # или msg[ ‘Subject’ ] = Header( ‘Тема сообщения’ , ‘utf-8’ )
При включении режима отладки server.set_debuglevel(True) вся информация о процессе будет выводиться в консоль оболочки Shell. Это скажется на производительности, особенно в случаях вложения в отправление файлов.
При наличии вложений, использовать отладку server.set_debuglevel(True) не рекомендуется!
По такому же принципу к сообщению добавляются файлы — создаются экземпляры соответствующих подклассов и присоединяются к объекту msg . Код для включения различных типов файлов представлен ниже. Также необходимо импортировать дополнительные 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 # Аудио # . 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) # Присоединяем файл к сообщению
После вынесения функционала отправки сообщения в отдельную функцию, полный код с примером использования будет выглядеть так:
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)
