MyTetra Share
Делитесь знаниями!
Работа с почтой - модули email / smtplib в Python
Время создания: 29.07.2019 23:51
Текстовые метки: Python, python-scripts.com, send-email-smtp-python
Раздел: !Закладки - Python - python-scripts.com
Запись: xintrea/mytetra_db_adgaver_new/master/base/1516450568g3ej43zfn6/text.html на raw.githubusercontent.com

python-scripts.com

Работа с почтой - модули email / smtplib в Python

автор

13-19 минут


Пайтон содержит несколько действительно полезных модулей, которые можно использовать для создания электронной рассылки. Это модули email и smtplib. Вместо того чтобы рассматривать различные методы в этих двух модулях, мы уделим больше времени на то, как их, собственно, использовать. В частности, мы рассмотрим следующие этапы работы:

  • Основы работы с почтой;
  • Как выполнять рассылку нескольким адресатам за раз;
  • Как отправлять письма, используя строки TO, CC и BCC
  • Как создавать содержимое и тело письма при помощи модуля email.

Начнем!

Основы работы с почтой – как отправлять письма при помощи smtplib

Модуль smtplib весьма интуитивен в пользовании. Давайте проведем небольшой пример, который покажет, как при помощи данного модуля отправлять почту. Сохраните нижеизложенный код в файле на вашем жестком диске:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import smtplib

SUBJECT = "Test email from Python"

TO = "mike@someAddress.org"

FROM = "python@mydomain.com"

text = "Python 3.4 rules them all!"

BODY = "\r\n".join((

    "From: %s" % FROM,

    "To: %s" % TO,

    "Subject: %s" % SUBJECT ,

    "",

    text

))

server = smtplib.SMTP(HOST)

server.sendmail(FROM, [TO], BODY)

server.quit()

Мы выполнили импорт двух модулей, smtplib и string. Две трети этого кода используются для настройки почты. Большая часть переменных прекрасно объясняют сами себя, так что мы сфокусируемся на BODY. Мы воспользуемся модулем string, чтобы скомбинировать все переменные в единую строку, в которой каждая строчка заканчивается“/r”, а новая начинается с “/n”. После вывода BODY вы получите следующую картину:


'From: python@mydomain.com\r\nTo: mike@mydomain.com\r\nSubject: Test email from \

Python\r\n\r\nblah blah blah'

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


server.login(username, password)

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


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

import smtplib

def send_email(host, subject, to_addr, from_addr, body_text):

    """

    Send an email

    """

    BODY = "\r\n".join((

        "From: %s" % from_addr,

        "To: %s" % to_addr,

        "Subject: %s" % subject ,

        "",

        body_text

    ))

    server = smtplib.SMTP(host)

    server.sendmail(from_addr, [to_addr], BODY)

    server.quit()

if __name__ == "__main__":

    subject = "Test email from Python"

    to_addr = "mike@someAddress.org"

    from_addr = "python@mydomain.com"

    body_text = "Python rules them all!"

    send_email(host, subject, to_addr, from_addr, body_text)

Теперь вы видите, насколько маленький код на самом деле, если взглянуть на саму функцию. Всего 13 строчек. Мы можем сделать его еще короче, если не будем добавлять каждый элемент в BODY в его собственной строке, но это будет не так читаемо. Сейчас мы создадим файл config, чтобы сберечь информацию сервера и адреса.

Зачем? К примеру, в работе вам может понадобиться несколько почтовых серверов для рассылки писем, или если почтовый сервер обновился, и название теперь новое. В таком случае нам нужно только изменить файл config, а не менять сам код. То же самое может понадобиться, если ваша компания была куплена, или слилась с другой. Давайте взглянем на файл config (сохраните его под названием email.ini):


[smtp]

server = some.server.com

from_addr = python@mydomain.com

Это очень простой файл config. В нем есть секция, под названием smtp, в которой у нас есть два объекта: server и from_addr. Мы воспользуемся configObj для чтения этого файла и вернемся к словарю Пайтон. Вот обновленная версия кода (сохраните её под именем smtp_config.py):


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

import os

import smtplib

import sys

from configparser import ConfigParser

def send_email(subject, to_addr, body_text):

    """

    Send an email

    """

    base_path = os.path.dirname(os.path.abspath(__file__))

    config_path = os.path.join(base_path, "email.ini")

    if os.path.exists(config_path):

        cfg = ConfigParser()

        cfg.read(config_path)

    else:

        print("Config not found! Exiting!")

        sys.exit(1)

    host = cfg.get("smtp", "server")

    from_addr = cfg.get("smtp", "from_addr")

    BODY = "\r\n".join((

        "From: %s" % from_addr,

        "To: %s" % to_addr,

        "Subject: %s" % subject ,

        "",

        body_text

    ))

    server = smtplib.SMTP(host)

    server.sendmail(from_addr, [to_addr], BODY)

    server.quit()

if __name__ == "__main__":

    subject = "Test email from Python"

    to_addr = "mike@someAddress.org"

    body_text = "Python rules them all!"

    send_email(subject, to_addr, body_text)

Мы добавили в этот код небольшую проверку. Нам нужно взять путь, в котором находится сам скрипт, который представляет base_path. Далее мы комбинируем данный путь с названием файла для получения окончательного пути к файлу config. После этого мы проверим, существует ли данный файл. Если да, мы создаем ConfigParser, если нет, мы выводим сообщение и выходим из скрипта. Мы можем добавить обработчик исключений в рамках вызова ConfigParser.read() чтобы проверить, что файл существует, но поврежден, или у нас закрыт к нему доступ, что и будет причиной исключения. Это будет небольшой проект, который вы можете выполнить самостоятельно. В любом случае, представим, что все хорошо и объект ConfigParser был успешно создан. Теперь мы можем извлечь хост и информацию from_addr при помощи обычного синтаксиса ConfigParser.

Теперь мы готовы к тому, чтобы научиться отправлять несколько писем сразу.

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

Давайте немного модифицируем предыдущий пример так, чтобы отправить несколько писем!


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

import os

import smtplib

import sys

from configparser import ConfigParser

def send_email(subject, body_text, emails):

    """

    Send an email

    """

    base_path = os.path.dirname(os.path.abspath(__file__))

    config_path = os.path.join(base_path, "email.ini")

    if os.path.exists(config_path):

        cfg = ConfigParser()

        cfg.read(config_path)

    else:

        print("Config not found! Exiting!")

        sys.exit(1)

    host = cfg.get("smtp", "server")

    from_addr = cfg.get("smtp", "from_addr")

    BODY = "\r\n".join((

        "From: %s" % from_addr,

        "To: %s" % ', '.join(emails),

        "Subject: %s" % subject ,

        "",

        body_text

    ))

    server = smtplib.SMTP(host)

    server.sendmail(from_addr, emails, BODY)

    server.quit()

if __name__ == "__main__":

    emails = ["mike@someAddress.org", "someone@gmail.com"]

    subject = "Test email from Python"

    body_text = "Python rules them all!"

    send_email(subject, body_text, emails)

Обратите внимание на то, что в этом примере мы убрали параметр to_addr и добавили параметр emails, который является списком электронных почтовых адресов. Чтобы это заработало, нам нужно создать разделенную запятыми строку в части BODY под названием «To:» ,а также указать список адресов в методе sendmail. Таким образом, мы получаем рабочую, разделенную запятыми строку: ’, ‘.join(emails). Ничего сложного, не правда ли?

Рассылка писем при помощи строчек TO, CC и BCC

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


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

import os

import smtplib

import sys

from configparser import ConfigParser

def send_email(subject, body_text, to_emails, cc_emails, bcc_emails):

    """

    Send an email

    """

    base_path = os.path.dirname(os.path.abspath(__file__))

    config_path = os.path.join(base_path, "email.ini")

    if os.path.exists(config_path):

        cfg = ConfigParser()

        cfg.read(config_path)

    else:

        print("Config not found! Exiting!")

        sys.exit(1)

    host = cfg.get("smtp", "server")

    from_addr = cfg.get("smtp", "from_addr")

    BODY = "\r\n".join((

        "From: %s" % from_addr,

        "To: %s" % ', '.join(to_emails),

        "CC: %s" % ', '.join(cc_emails),

        "BCC: %s" % ', '.join(bcc_emails),

        "Subject: %s" % subject ,

        "",

        body_text

    ))

    emails = to_emails + cc_emails + bcc_emails

    server = smtplib.SMTP(host)

    server.sendmail(from_addr, emails, BODY)

    server.quit()

if __name__ == "__main__":

    emails = ["mike@somewhere.org"]

    cc_emails = ["someone@gmail.com"]

    bcc_emails = ["schmuck@newtel.net"]

    subject = "Test email from Python"

    body_text = "Python rules them all!"

    send_email(subject, body_text, emails, cc_emails, bcc_emails)

В этом коде мы указали три списка, каждый из которых содержит по одному электронному адресу. Мы создали поля CC и BCC таким же образом, как делали это ранее, с той разницей, что теперь нам нужно соединить три списка в один, чтобы мы могли указать полученный список методу sendmail(). На разных форумах пишут, что некоторые почтовые клиенты обрабатывают поле BCC нечётно, из-за чего получатель может видеть содержимое списка ВСС через заголовки писем. Однако мы точно знаем, что Gmail успешно удаляет ВСС данные из заголовка письма.

Теперь мы готовы перейти к модулю email!

Добавление вложения \ тела письма при помощи модуля email

Теперь мы возьмем все то, чему мы научились в предыдущих разделах и смешаем их вместе с модулем email, чтобы отправлять письма с прикрепленными файлами. Модуль email позволяет прикреплять вложения к письму очень просто. Вот код:


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

import os

import smtplib

import sys

from configparser import ConfigParser

from email import encoders

from email.mime.text import MIMEText

from email.mime.base import MIMEBase

from email.mime.multipart import MIMEMultipart

from email.utils import formatdate

#----------------------------------------------------------------------

def send_email_with_attachment(subject, body_text, to_emails, cc_emails, bcc_emails, file_to_attach):

    """

    Send an email with an attachment

    """

    base_path = os.path.dirname(os.path.abspath(__file__))

    config_path = os.path.join(base_path, "email.ini")

    header = 'Content-Disposition', 'attachment; filename="%s"' % file_to_attach

    # get the config

    if os.path.exists(config_path):

        cfg = ConfigParser()

        cfg.read(config_path)

    else:

        print("Config not found! Exiting!")

        sys.exit(1)

    # extract server and from_addr from config

    host = cfg.get("smtp", "server")

    from_addr = cfg.get("smtp", "from_addr")

    # create the message

    msg = MIMEMultipart()

    msg["From"] = from_addr

    msg["Subject"] = subject

    msg["Date"] = formatdate(localtime=True)

    if body_text:

        msg.attach( MIMEText(body_text) )

    msg["To"] = ', '.join(to_emails)

    msg["cc"] = ', '.join(cc_emails)

    attachment = MIMEBase('application', "octet-stream")

    try:

        with open(file_to_attach, "rb") as fh:

            data = fh.read()

        attachment.set_payload( data )

        encoders.encode_base64(attachment)

        attachment.add_header(*header)

        msg.attach(attachment)

    except IOError:

        msg = "Error opening attachment file %s" % file_to_attach

        print(msg)

        sys.exit(1)

    emails = to_emails + cc_emails

    server = smtplib.SMTP(host)

    server.sendmail(from_addr, emails, msg.as_string())

    server.quit()

if __name__ == "__main__":

    emails = ["mike@someAddress.org", "nedry@jp.net"]

    cc_emails = ["someone@gmail.com"]

    bcc_emails = ["anonymous@circe.org"]

    subject = "Test email with attachment from Python"

    body_text = "This email contains an attachment!"

    path = "/path/to/some/file"

    send_email_with_attachment(subject, body_text, emails,cc_emails, bcc_emails, path)

В данном коде мы переименовали нашу функцию и добавили новый аргумент file_to_attach. Нам также нужно добавить заголовок и создать объект MIMEMultipart. Заголовок может быть создан в любое время, перед тем как мы добавим вложение. Мы добавим элементы в объект MIMEMultipart (msg) также, как и ключевые слова в словарь. Обратите внимание на то, что нам нужно использовать метод formatdate модуля email, чтобы ввести данные правильного формата. Чтобы добавить тело письма, нам нужно создать экземпляр MIMEText. Как вы могли заметить, мы не добавляем информацию BCC, но вы можете легко это сделать, следуя условиям написанного выше кода. Далее мы добавляем вложение. Мы размещаем его в обработчике исключений и используем оператор with для извлечения файла и помещения его в наш объект MIMEBase. Наконец мы добавляем его в переменную msg и отправляем. Обратите внимание на то, что нам нужно конвертировать msg в методе sendmail в строку.

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

Теперь вы знаете, как отправлять почту при помощи Python. Для тех из вас, кто любит мини проекты, вы можете вернуться назад и добавить обработку дополнительную ошибку в кодовой части server.sendmail, если что-то не так пойдет во время процесса работы, типа ошибки SMTPAuthenticationError или SMTPConnectError. Мы можем также увеличить обработку ошибок во время прикрепления файла к телу письма, чтобы уловить другие ошибки. Наконец, мы можем взять списки различных писем, чтобы создать один нормальный, в котором отсутствуют дубликаты адресов. Это очень важно, если мы читаем список электронных адресов из файла. Также обратите внимание на то, что адрес from – не настоящий. Мы можем подделывать письма при помощи Пайтона и других языков программирование, однако это крайне неэтично, а в некоторых странах еще и нелегально. Имейте ввиду! Используйте свои знания правильно и пользуйтесь Пайтоном для удовольствия и с пользой.


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования