Как отправить электронное письмо с Python?
Этот код работает и отправляет мне письмо просто отлично:
import smtplib
#SERVER = "localhost"
FROM = '[email protected]'
TO = ["[email protected]"] # must be a list
SUBJECT = "Hello!"
TEXT = "This message was sent with Python smtplib."
# Prepare actual message
message = """\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
# Send the mail
server = smtplib.SMTP('myserver')
server.sendmail(FROM, TO, message)
server.quit()
Однако, если я попытаюсь обернуть его в такую функцию:
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
import smtplib
"""this is some test documentation in the function"""
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()
и назовите его, я получаю следующие ошибки:
Traceback (most recent call last):
File "C:/Python31/mailtest1.py", line 8, in <module>
sendmail.sendMail(sender,recipients,subject,body,server)
File "C:/Python31\sendmail.py", line 13, in sendMail
server.sendmail(FROM, TO, message)
File "C:\Python31\lib\smtplib.py", line 720, in sendmail
self.rset()
File "C:\Python31\lib\smtplib.py", line 444, in rset
return self.docmd("rset")
File "C:\Python31\lib\smtplib.py", line 368, in docmd
return self.getreply()
File "C:\Python31\lib\smtplib.py", line 345, in getreply
raise SMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected: Connection unexpectedly closed
Может ли кто-нибудь помочь мне понять, почему?
Ответы
Ответ 1
Я рекомендую вам использовать стандартные пакеты email
и smtplib
вместе для отправки электронной почты. Пожалуйста, посмотрите на следующий пример (воспроизведенный из документации по Python). Обратите внимание, что если следовать этому подходу, "простая" задача действительно проста, а более сложные задачи (например, присоединение двоичных объектов или отправка простых/HTML-сообщений из нескольких частей) выполняются очень быстро.
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.mime.text import MIMEText
# Open a plain text file for reading. For this example, assume that
# the text file contains only ASCII characters.
with open(textfile, 'rb') as fp:
# Create a text/plain message
msg = MIMEText(fp.read())
# me == the sender email address
# you == the recipient email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('localhost')
s.sendmail(me, [you], msg.as_string())
s.quit()
Для отправки электронной почты нескольким получателям вы также можете следовать примеру в документации по Python:
# Import smtplib for the actual sending function
import smtplib
# Here are the email package modules we'll need
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
# Create the container (outer) email message.
msg = MIMEMultipart()
msg['Subject'] = 'Our family reunion'
# me == the sender email address
# family = the list of all recipients' email addresses
msg['From'] = me
msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'
# Assume we know that the image files are all in PNG format
for file in pngfiles:
# Open the files in binary mode. Let the MIMEImage class automatically
# guess the specific image type.
with open(file, 'rb') as fp:
img = MIMEImage(fp.read())
msg.attach(img)
# Send the email via our own SMTP server.
s = smtplib.SMTP('localhost')
s.sendmail(me, family, msg.as_string())
s.quit()
Как видите, заголовок To
в объекте MIMEText
должен быть строкой, состоящей из адресов электронной почты, разделенных запятыми. С другой стороны, вторым аргументом функции sendmail
должен быть список строк (каждая строка является адресом электронной почты).
Итак, если у вас есть три адреса электронной почты: [email protected]
, [email protected]
и [email protected]
, вы можете сделать следующее (очевидные разделы опущены):
to = ["[email protected]", "[email protected]", "[email protected]"]
msg['To'] = ",".join(to)
s.sendmail(me, to, msg.as_string())
часть ",".join(to)
создает из списка одну строку, разделенную запятыми.
Из ваших вопросов я понимаю, что вы не прошли учебник по Python - это ОБЯЗАТЕЛЬНО, если вы хотите получить что-нибудь в Python - документация в основном превосходна для стандартной библиотеки.
Ответ 2
Ну, вы хотите получить ответ, который является современным и современным.
Вот мой ответ:
Когда мне нужно отправить почту на python, я использую mailgun API, который получает много головных болей при рассылке рассылок. У них есть замечательное приложение /api, которое позволяет отправлять 10000 писем в месяц бесплатно.
Отправка сообщения электронной почты будет таким:
def send_simple_message():
return requests.post(
"https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
auth=("api", "YOUR_API_KEY"),
data={"from": "Excited User <[email protected]_DOMAIN_NAME>",
"to": ["[email protected]", "[email protected]_DOMAIN_NAME"],
"subject": "Hello",
"text": "Testing some Mailgun awesomness!"})
Вы также можете отслеживать события и многое другое, см. руководство по быстрому запуску.
Надеюсь, вы найдете это полезным!
Ответ 3
Я хочу помочь вам с отправкой электронных писем, сообщив о пакете yagmail (я сторонник, извините за рекламу, но я чувствую, что это может действительно помочь!).
Весь код для вас:
import yagmail
yag = yagmail.SMTP(FROM, 'pass')
yag.send(TO, SUBJECT, TEXT)
Обратите внимание, что я предоставляю значения по умолчанию для всех аргументов, например, если вы хотите отправить себя, вы можете опустить TO
, если вы не хотите тему, вы также можете ее опустить.
Кроме того, цель состоит также в том, чтобы сделать очень легко прикрепить html-код или изображения (и другие файлы).
Когда вы помещаете содержимое, вы можете сделать что-то вроде:
contents = ['Body text, and here is an embedded image:', 'http://somedomain/image.png',
'You can also find an audio file attached.', '/local/path/song.mp3']
Ничего себе, как легко отправлять вложения! Это займет 20 строк без yagmail;)
Кроме того, если вы установите его один раз, вам больше не придется вводить пароль (и безопасно хранить его). В вашем случае вы можете сделать что-то вроде:
import yagmail
yagmail.SMTP().send(contents = contents)
который намного более краток!
Я бы пригласил вас посмотреть github или установить его непосредственно с помощью pip install yagmail
.
Ответ 4
Есть проблема с отступом. Код ниже будет работать:
import textwrap
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
import smtplib
"""this is some test documentation in the function"""
message = textwrap.dedent("""\
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()
Ответ 5
Попробуйте следующее:
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
import smtplib
"""this is some test documentation in the function"""
message = """\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
# Send the mail
server = smtplib.SMTP(SERVER)
"New part"
server.starttls()
server.login('username', 'password')
server.sendmail(FROM, TO, message)
server.quit()
Он работает для smtp.gmail.com
Ответ 6
Отклоняя код в функции (это нормально), вы также отступали строки строки необработанного сообщения. Но ведущее белое пространство подразумевает складывание (конкатенацию) строк заголовка, как описано в разделах 2.2.3 и 3.2.3 RFC 2822 - Формат интернет-сообщений:
Каждое поле заголовка логически представляет собой одну строку символов, содержащую имя поля, двоеточие и тело тела. Для удобства однако, и для устранения ограничений на 998/78 символов в строке, часть тела поля поля заголовка может быть разделена на несколько линейное представление; это называется "складыванием".
В форме функции вашего вызова sendmail
все строки начинаются с пробела и поэтому "разворачиваются" (конкатенированы), и вы пытаетесь отправить
From: [email protected] To: [email protected] Subject: Hello! This message was sent with Python smtplib.
Кроме нашего разума, smtplib
больше не будет понимать заголовки To:
и Subject:
, потому что эти имена распознаются только в начале строки. Вместо этого smtplib
будет принимать очень длинный адрес электронной почты отправителя:
[email protected] To: [email protected] Subject: Hello! This message was sent with Python smtplib.
Это не сработает, и наступает ваше исключение.
Решение прост: просто сохраните строку message
, как было раньше. Это можно сделать с помощью функции (как предложил Зиесан) или сразу в исходном коде:
import smtplib
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
"""this is some test documentation in the function"""
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()
Теперь разворачивание не происходит, и вы отправляете
From: [email protected]
To: [email protected]
Subject: Hello!
This message was sent with Python smtplib.
что и работает, и что было сделано с помощью старого кода.
Обратите внимание, что я также сохранял пустую строку между заголовками и телом, чтобы разместить раздел 3.5 RFC (который требуется) и поставить включить вне функции в соответствии с руководством по стилю Python PEP-0008 (что необязательно).
Ответ 7
Вероятно, он помещает вкладки в ваше сообщение. Распечатайте сообщение, прежде чем передавать его в sendMail.
Ответ 8
Вот пример на Python 3.x
, гораздо проще, чем 2.x
:
import smtplib
from email.message import EmailMessage
def send_mail(to_email, subject, message, server='smtp.example.cn',
from_email='[email protected]'):
# import smtplib
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ', '.join(to_email)
msg.set_content(message)
print(msg)
server = smtplib.SMTP(server)
server.set_debuglevel(1)
server.login(from_email, 'password') # user & password
server.send_message(msg)
server.quit()
print('successfully sent the mail.')
вызов этой функции:
send_mail(to_email=['[email protected]', '[email protected]'],
subject='hello', message='Your analysis has done!')
ниже может быть только для китайского пользователя:
Если вы используете 126/163, 网易 邮箱, вам нужно установить "客户 端 授权 密码", как показано ниже:
ref: fooobar.com/questions/32644/...
https://docs.python.org/3/library/email.examples.html#email-examples
Ответ 9
Убедитесь, что вы предоставили разрешение отправителю и получателю отправлять электронную почту и получать электронную почту из неизвестных источников (внешних источников) в учетной записи электронной почты.
import smtplib
#Ports 465 and 587 are intended for email client to email server communication - sending email
server = smtplib.SMTP('smtp.gmail.com', 587)
#starttls() is a way to take an existing insecure connection and upgrade it to a secure connection using SSL/TLS.
server.starttls()
#Next, log in to the server
server.login("#email", "#password")
msg = "Hello! This Message was sent by the help of Python"
#Send the mail
server.sendmail("#Sender", "#Reciever", msg)
Ответ 10
Как и ваш код, в нем нет ничего принципиально неправильного, кроме того, неясно, как вы на самом деле называете эту функцию. Все, о чем я могу думать, это то, что когда ваш сервер не отвечает, вы получите эту ошибку SMTPServerDisconnected. Если вы посмотрите на функцию getreply() в smtplib (выдержка ниже), вы получите представление.
def getreply(self):
"""Get a reply from the server.
Returns a tuple consisting of:
- server response code (e.g. '250', or such, if all goes well)
Note: returns -1 if it can't read response code.
- server response string corresponding to response code (multiline
responses are converted to a single, multiline string).
Raises SMTPServerDisconnected if end-of-file is reached.
"""
проверьте пример https://github.com/rreddy80/sendEmails/blob/master/sendEmailAttachments.py, который также использует вызов функции для отправки электронной почты, если это то, что вы пытаетесь сделать ( DRY).
Ответ 11
Думал, что я поставил бы свои два бита, так как я только что понял, как это работает.
Похоже, что у вас нет порта, указанного в настройках подключения SERVER, это немного меня немного улучшило, когда я пытался подключиться к моему SMTP-серверу, который не использует порт по умолчанию: 25.
В соответствии с документами smtplib.SMTP, ваш запрос или ответ ehlo или helo автоматически следует позаботиться, поэтому вам не стоит беспокоиться об этом (но может быть что-то подтвердить, если все остальное не работает).
Еще одна вещь, которую вы задаете себе, - разрешить ли вам SMTP-соединения на вашем SMTP-сервере? Для некоторых сайтов, таких как GMAIL и ZOHO, вы должны фактически подключиться и активировать IMAP-соединения в учетной записи электронной почты. Возможно, ваш почтовый сервер не разрешает соединения SMTP, которые не происходят из "localhost"? Что-то посмотреть.
Последнее, что вы можете попробовать и инициировать подключение к TLS. Большинство серверов теперь требуют такого типа аутентификации.
Вы увидите, что я забил два поля TO в свой адрес электронной почты. Значения слов msg ['TO'] и msg ['FROM'] msg позволяют отображать правильную информацию в заголовках самого электронного письма, которое видно на получающем конце письма в полях To/From (вы может даже быть в состоянии добавить ответ на поле здесь. Поля TO и FROM сами являются тем, что требуется серверу. Я знаю, что слышал о том, что некоторые серверы электронной почты отклоняют электронные письма, если у них нет правильных заголовков электронной почты.
Это код, который я использовал в функции, которая работает для отправки по электронной почте содержимого файла *.txt с помощью моего локального компьютера и удаленного SMTP-сервера (ZOHO, как показано):
def emailResults(folder, filename):
# body of the message
doc = folder + filename + '.txt'
with open(doc, 'r') as readText:
msg = MIMEText(readText.read())
# headers
TO = '[email protected]'
msg['To'] = TO
FROM = '[email protected]'
msg['From'] = FROM
msg['Subject'] = 'email subject |' + filename
# SMTP
send = smtplib.SMTP('smtp.zoho.com', 587)
send.starttls()
send.login('[email protected]', 'password')
send.sendmail(FROM, TO, msg.as_string())
send.quit()