Отправка почты из Python с использованием SMTP

118

Я использую следующий метод для отправки почты из Python с использованием SMTP. Это правильный метод использования или есть ошибки, которые мне не хватает?

from smtplib import SMTP
import datetime

debuglevel = 0

smtp = SMTP()
smtp.set_debuglevel(debuglevel)
smtp.connect('YOUR.MAIL.SERVER', 26)
smtp.login('USERNAME@DOMAIN', 'PASSWORD')

from_addr = "John Doe <john@doe.net>"
to_addr = "foo@bar.com"

subj = "hello"
date = datetime.datetime.now().strftime( "%d/%m/%Y %H:%M" )

message_text = "Hello\nThis is a mail from your server\n\nBye\n"

msg = "From: %s\nTo: %s\nSubject: %s\nDate: %s\n\n%s" 
        % ( from_addr, to_addr, subj, date, message_text )

smtp.sendmail(from_addr, to_addr, msg)
smtp.quit()
Эли Бендерский
источник
2
Убедитесь, что вы правильно указали дату и время. Я нашел следующую функцию весьма полезной, которая дает вам идеально отформатированное значение для Date-Header: docs.python.org/py3k/library/…
BastiBen
вот пример кода, демонстрирующий, как отправлять изображения встроенными (плюс электронная почта с частями HTML и обычного текста) . Он также показывает, как настроить параметры ssl в старых версиях Python.
jfs
2
Обратите внимание, что есть доступные библиотеки-оболочки, которые значительно сокращают количество кода для отправки электронных писем (например, yagmail )
PascalVKooten

Ответы:

111

Скрипт, который я использую, очень похож; Я размещаю это здесь как пример того, как использовать модули email. * Для генерации сообщений MIME; так что этот сценарий можно легко изменить, чтобы прикрепить изображения и т. д.

Я полагаюсь на своего интернет-провайдера, чтобы добавить заголовок даты и времени.

Мой интернет-провайдер требует, чтобы я использовал безопасное соединение smtp для отправки почты, я полагаюсь на модуль smtplib (загружаемый по адресу http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

Как и в вашем сценарии, имя пользователя и пароль (указанные ниже фиктивные значения), используемые для аутентификации на SMTP-сервере, представлены в исходном тексте в виде обычного текста. Это слабое место в системе безопасности; но лучшая альтернатива зависит от того, насколько тщательно вы должны (хотите?) относиться к их защите.

=======================================

#! /usr/local/bin/python


SMTPserver = 'smtp.att.yahoo.com'
sender =     'me@my_email_domain.net'
destination = ['recipient@her_email_domain.com']

USERNAME = "USER_NAME_FOR_INTERNET_SERVICE_PROVIDER"
PASSWORD = "PASSWORD_INTERNET_SERVICE_PROVIDER"

# typical values for text_subtype are plain, html, xml
text_subtype = 'plain'


content="""\
Test message
"""

subject="Sent from Python"

import sys
import os
import re

from smtplib import SMTP_SSL as SMTP       # this invokes the secure SMTP protocol (port 465, uses SSL)
# from smtplib import SMTP                  # use this for standard SMTP protocol   (port 25, no encryption)

# old version
# from email.MIMEText import MIMEText
from email.mime.text import MIMEText

try:
    msg = MIMEText(content, text_subtype)
    msg['Subject']=       subject
    msg['From']   = sender # some SMTP servers will do this automatically, not all

    conn = SMTP(SMTPserver)
    conn.set_debuglevel(False)
    conn.login(USERNAME, PASSWORD)
    try:
        conn.sendmail(sender, destination, msg.as_string())
    finally:
        conn.quit()

except:
    sys.exit( "mail failed; %s" % "CUSTOM_ERROR" ) # give an error message
Винсент Маркетти
источник
1
@Vincent: не удалось отправить почту; Объект 'module' не имеет атрибута 'SSLFakeSocket' - с использованием Gmail :(
RadiantHex
Это похоже на проблему с версией или импортом, чтобы помочь отследить: какая версия Python у вас установлена? - Вам нужно подключиться к вашему SMTP-серверу через SSL (и если да, то импортируете ли вы ssmtplib, как указано выше)? Можете ли вы импортировать smtplib непосредственно из интерактивного python, если да, то определен ли класс smtplib.SSLFakeSocket? Надеюсь, я смогу помочь
Винсент Маркетти
2
Используйте smtplib.SMTP_SSL (стандарт в последних версиях Python) для создания соединения вместо ssmtplib.STMP_SSL (сторонний модуль, упомянутый выше). Обратите внимание, что стандартный модуль начинается с единственной буквы «s». Это сработало для меня.
Хулио Горге
2
заменить from ssmtplib import SMTP_SSL as SMTPна from smtplib import SMTP_SSL as SMTP, и этот пример будет работать из стандартной библиотеки Python.
Адам Матан
9
Добавить msg['To'] = ','.join(destination), иначе пункт назначения не отображается в Gmail
Таха Джахангир
88

Метод, который я обычно использую ... не сильно отличается, но немного

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

msg = MIMEMultipart()
msg['From'] = 'me@gmail.com'
msg['To'] = 'you@gmail.com'
msg['Subject'] = 'simple email in python'
message = 'here is the email'
msg.attach(MIMEText(message))

mailserver = smtplib.SMTP('smtp.gmail.com',587)
# identify ourselves to smtp gmail client
mailserver.ehlo()
# secure our email with tls encryption
mailserver.starttls()
# re-identify ourselves as an encrypted connection
mailserver.ehlo()
mailserver.login('me@gmail.com', 'mypassword')

mailserver.sendmail('me@gmail.com','you@gmail.com',msg.as_string())

mailserver.quit()

это оно

madman2890
источник
Если вы используете двухэтапную аутентификацию, вам необходимо сначала создать пароль для конкретного приложения и заменить им свой обычный пароль. См. Раздел « Вход с использованием паролей приложений»
Suzana
2
Я согласен, это лучший ответ, и его следует принять. Тот, который действительно принят, хуже.
HelloWorld
6
Для python3 используйте:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
art
21

Также, если вы хотите выполнить smtp-аутентификацию с TLS, а не с SSL, вам просто нужно изменить порт (используйте 587) и выполнить smtp.starttls (). Это сработало для меня:

...
smtp.connect('YOUR.MAIL.SERVER', 587)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login('USERNAME@DOMAIN', 'PASSWORD')
...

источник
6

Основная проблема, которую я вижу, заключается в том, что вы не обрабатываете никаких ошибок: .login () и .sendmail () имеют задокументированные исключения, которые они могут генерировать, и похоже, что .connect () должен каким-то образом указать, что это было невозможно подключиться - вероятно, исключение вызвано базовым кодом сокета.

pjz
источник
6

Убедитесь, что у вас нет брандмауэров, блокирующих SMTP. Когда я в первый раз попытался отправить электронное письмо, оно было заблокировано брандмауэром Windows и McAfee - на то, чтобы найти их обоих, потребовалась целая вечность.

Марк Рэнсом
источник
6

Как насчет этого?

import smtplib

SERVER = "localhost"

FROM = "sender@example.com"
TO = ["user@example.com"] # must be a list

SUBJECT = "Hello!"

TEXT = "This message was sent with Python's smtplib."

# Prepare actual message

message = """\
From: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

# Send the mail

server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
Сатиш
источник
4

следующий код отлично работает для меня:

import smtplib

to = 'mkyong2002@yahoo.com'
gmail_user = 'mkyong2002@gmail.com'
gmail_pwd = 'yourpassword'
smtpserver = smtplib.SMTP("smtp.gmail.com",587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo() # extra characters to permit edit
smtpserver.login(gmail_user, gmail_pwd)
header = 'To:' + to + '\n' + 'From: ' + gmail_user + '\n' + 'Subject:testing \n'
print header
msg = header + '\n this is test msg from mkyong.com \n\n'
smtpserver.sendmail(gmail_user, to, msg)
print 'done!'
smtpserver.quit()

Ссылка: http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/

Абдул Маджид
источник
1
В Flask есть фреймворк для электронной почты: из flask.ext.mail import Mail. Я устраняю его и думал, что вернусь к коду Python, чтобы посмотреть, смогу ли я заставить что-то работать. Мне понравился этот ответ, потому что он был голым. Ах да, и это сработало!
Внимание: предыдущая версия ответа включала строку: smtpserver.close()Должно быть:, smtpserver.quit()потому close()что TLS-соединение не прерывается должным образом! close()будет вызван во время quit().
aronadaal
Привет, у меня возникли проблемы с выполнением вышеуказанных команд. когда я использую smtpserver.starttls (), я получаю сообщение об ошибке SMTP «SMTPServerDisconnected: соединение неожиданно закрыто: [Errno 10054]» .. сообщается в stackoverflow.com/questions/46094175/…
fazkan
3

Убедитесь, что вы форматируете дату в правильном формате - RFC2822 .

Дуглас Лидер
источник
3

Пример кода, который я сделал для отправки почты с использованием SMTP.

import smtplib, ssl

smtp_server = "smtp.gmail.com"
port = 587  # For starttls
sender_email = "sender@email"
receiver_email = "receiver@email"
password = "<your password here>"
message = """ Subject: Hi there

This message is sent from Python."""


# Create a secure SSL context
context = ssl.create_default_context()

# Try to log in to server and send email
server = smtplib.SMTP(smtp_server,port)

try:
    server.ehlo() # Can be omitted
    server.starttls(context=context) # Secure the connection
    server.ehlo() # Can be omitted
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, message)
except Exception as e:
    # Print any error messages to stdout
    print(e)
finally:
    server.quit()
Hariharan AR
источник
2

Видите все эти длинные ответы? Пожалуйста, позвольте мне заняться саморекламой, изложив все это в нескольких строках.

Импорт и подключение:

import yagmail
yag = yagmail.SMTP('john@doe.net', host = 'YOUR.MAIL.SERVER', port = 26)

Тогда это просто однострочный:

yag.send('foo@bar.com', 'hello', 'Hello\nThis is a mail from your server\n\nBye\n')

Он фактически закроется, когда выйдет за рамки (или его можно закрыть вручную). Кроме того, это позволит вам зарегистрировать свое имя пользователя в связке ключей, так что вам не нужно будет записывать свой пароль в свой сценарий (это действительно беспокоило меня перед написанием yagmail!)

Чтобы узнать о пакете / установке, советах и ​​уловках, пожалуйста, посмотрите git или pip , доступные как для Python 2, так и для Python 3.

PascalVKooten
источник
@PascalvKoolen Я установил yagmail и попытался подключиться, указав свой адрес электронной почты и пароль. но это дало мне ошибку аутентификации
fazkan
0

ты можешь сделать это

import smtplib
from email.mime.text import MIMEText
from email.header import Header


server = smtplib.SMTP('mail.servername.com', 25)
server.ehlo()
server.starttls()

server.login('username', 'password')
from = 'me@servername.com'
to = 'mygfriend@servername.com'
body = 'That A Message For My Girl Friend For tell Him If We will go to eat Something This Nigth'
subject = 'Invite to A Diner'
msg = MIMEText(body,'plain','utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = Header(from, 'utf-8')
msg['To'] = Header(to, 'utf-8')
message = msg.as_string()
server.sendmail(from, to, message)
Skiller Dz
источник
0

Вот рабочий пример для Python 3.x

#!/usr/bin/env python3

from email.message import EmailMessage
from getpass import getpass
from smtplib import SMTP_SSL
from sys import exit

smtp_server = 'smtp.gmail.com'
username = 'your_email_address@gmail.com'
password = getpass('Enter Gmail password: ')

sender = 'your_email_address@gmail.com'
destination = 'recipient_email_address@gmail.com'
subject = 'Sent from Python 3.x'
content = 'Hello! This was sent to you via Python 3.x!'

# Create a text/plain message
msg = EmailMessage()
msg.set_content(content)

msg['Subject'] = subject
msg['From'] = sender
msg['To'] = destination

try:
    s = SMTP_SSL(smtp_server)
    s.login(username, password)
    try:
        s.send_message(msg)
    finally:
        s.quit()

except Exception as E:
    exit('Mail failed: {}'.format(str(E)))
отметка
источник
0

На основе этого примера я сделал следующую функцию:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def send_email(host, port, user, pwd, recipients, subject, body, html=None, from_=None):
    """ copied and adapted from
        /programming/10147455/how-to-send-an-email-with-gmail-as-provider-using-python#12424439
    returns None if all ok, but if problem then returns exception object
    """

    PORT_LIST = (25, 587, 465)

    FROM = from_ if from_ else user 
    TO = recipients if isinstance(recipients, (list, tuple)) else [recipients]
    SUBJECT = subject
    TEXT = body.encode("utf8") if isinstance(body, unicode) else body
    HTML = html.encode("utf8") if isinstance(html, unicode) else html

    if not html:
        # Prepare actual message
        message = """From: %s\nTo: %s\nSubject: %s\n\n%s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    else:
                # /programming/882712/sending-html-email-using-python#882770
        msg = MIMEMultipart('alternative')
        msg['Subject'] = SUBJECT
        msg['From'] = FROM
        msg['To'] = ", ".join(TO)

        # Record the MIME types of both parts - text/plain and text/html.
        # utf-8 -> /programming/5910104/python-how-to-send-utf-8-e-mail#5910530
        part1 = MIMEText(TEXT, 'plain', "utf-8")
        part2 = MIMEText(HTML, 'html', "utf-8")

        # Attach parts into message container.
        # According to RFC 2046, the last part of a multipart message, in this case
        # the HTML message, is best and preferred.
        msg.attach(part1)
        msg.attach(part2)

        message = msg.as_string()


    try:
        if port not in PORT_LIST: 
            raise Exception("Port %s not one of %s" % (port, PORT_LIST))

        if port in (465,):
            server = smtplib.SMTP_SSL(host, port)
        else:
            server = smtplib.SMTP(host, port)

        # optional
        server.ehlo()

        if port in (587,): 
            server.starttls()

        server.login(user, pwd)
        server.sendmail(FROM, TO, message)
        server.close()
        # logger.info("SENT_EMAIL to %s: %s" % (recipients, subject))
    except Exception, ex:
        return ex

    return None

если вы передадите только, bodyтогда будет отправлено обычное текстовое сообщение, но если вы передадите htmlаргумент вместе с bodyаргументом, будет отправлено электронное письмо в формате html (с откатом к текстовому содержимому для почтовых клиентов, которые не поддерживают типы html / mime).

Пример использования:

ex = send_email(
      host        = 'smtp.gmail.com'
   #, port        = 465 # OK
    , port        = 587  #OK
    , user        = "xxx@gmail.com"
    , pwd         = "xxx"
    , from_       = 'xxx@gmail.com'
    , recipients  = ['yyy@gmail.com']
    , subject     = "Test from python"
    , body        = "Test from python - body"
    )
if ex: 
    print("Mail sending failed: %s" % ex)
else:
    print("OK - mail sent"

Btw. Если вы хотите использовать Gmail в качестве тестового или производственного SMTP-сервера, включите временный или постоянный доступ к менее защищенным приложениям:

Роберт Луджо
источник