这段代码工作,并向我发送电子邮件就好:

import smtplib
#SERVER = "localhost"

FROM = 'monty@python.com'

TO = ["jon@mycompany.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('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

有人能告诉我为什么吗?


当前回答

我想我应该把我的两个比特放在这里,因为我刚刚明白了它是如何工作的。

似乎你没有在你的服务器连接设置上指定端口,这影响了我一点,当我试图连接到我的SMTP服务器,没有使用默认端口:25。

根据smtplib。SMTP文档,您的ehlo或helo请求/响应应该自动处理,所以您不必担心这一点(但如果其他都失败了,可能需要确认)。

另一个问题是你是否允许在你的SMTP服务器上进行SMTP连接?对于像GMAIL和ZOHO这样的网站,你必须实际进入并激活电子邮件帐户中的IMAP连接。您的邮件服务器可能不允许SMTP连接不是来自'localhost'也许?一些值得调查的事情。

最后一件事是你可能想尝试在TLS上发起连接。现在大多数服务器都需要这种类型的身份验证。

您将看到我在电子邮件中插入了两个TO字段。msg['TO']和msg['FROM'] msg字典项允许正确的信息显示在电子邮件本身的标题中,这可以在电子邮件的接收端的TO / FROM字段中看到(你甚至可以在这里添加一个Reply TO字段)。TO和FROM字段本身就是服务器所需要的。我知道我听说过一些电子邮件服务器拒绝邮件,如果他们没有适当的电子邮件标题。

这是我使用的代码,在一个函数中,为我工作,使用我的本地计算机和远程SMTP服务器(ZOHO所示)发送*.txt文件的内容:

def emailResults(folder, filename):

    # body of the message
    doc = folder + filename + '.txt'
    with open(doc, 'r') as readText:
        msg = MIMEText(readText.read())

    # headers
    TO = 'to_user@domain.com'
    msg['To'] = TO
    FROM = 'from_user@domain.com'
    msg['From'] = FROM
    msg['Subject'] = 'email subject |' + filename

    # SMTP
    send = smtplib.SMTP('smtp.zoho.com', 587)
    send.starttls()
    send.login('from_user@domain.com', 'password')
    send.sendmail(FROM, TO, msg.as_string())
    send.quit()

其他回答

就你的代码而言,它似乎没有任何根本性的错误,除了,不清楚你实际上是如何调用这个函数的。我能想到的是,当您的服务器没有响应时,您将得到这个SMTPServerDisconnected错误。如果您查找smtplib中的getreply()函数(摘自下面),您将得到一个概念。

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方法)。

import smtplib, ssl

port = 587  # For starttls
smtp_server = "smtp.office365.com"
sender_email = "170111018@student.mit.edu.tr"
receiver_email = "professordave@hotmail.com"
password = "12345678"
message = """\
Subject: Final exam

Teacher when is the final exam?"""

def SendMailf():
    context = ssl.create_default_context()
    with smtplib.SMTP(smtp_server, port) as server:
        server.ehlo()  # Can be omitted
        server.starttls(context=context)
        server.ehlo()  # Can be omitted
        server.login(sender_email, password)
        server.sendmail(sender_email, receiver_email, message)
        print("mail send")

它可能会在你的信息中添加标签。在你把它传递给sendMail之前打印出消息。

我想通过建议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']

哇,发送附件是多么简单啊!如果没有yagmail,这大概需要20行;)

此外,如果你设置了一次,你就永远不必再输入密码(并安全地保存密码)。在你的情况下,你可以这样做:

import yagmail
yagmail.SMTP().send(contents = contents)

这样更简洁!

我建议你看看github,或者直接用pip install yagmail安装它。

有压痕问题。下面的代码将工作:

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()