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

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

有人能告诉我为什么吗?


当前回答

使用gmail的另一个实现让我们说:

import smtplib

def send_email(email_address: str, subject: str, body: str):
"""
send_email sends an email to the email address specified in the
argument.

Parameters
----------
email_address: email address of the recipient
subject: subject of the email
body: body of the email
"""

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("email_address", "password")
server.sendmail("email_address", email_address,
                "Subject: {}\n\n{}".format(subject, body))
server.quit()

其他回答

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

使用gmail的另一个实现让我们说:

import smtplib

def send_email(email_address: str, subject: str, body: str):
"""
send_email sends an email to the email address specified in the
argument.

Parameters
----------
email_address: email address of the recipient
subject: subject of the email
body: body of the email
"""

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("email_address", "password")
server.sendmail("email_address", email_address,
                "Subject: {}\n\n{}".format(subject, body))
server.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方法)。

在缩进函数中的代码时(这是可以的),还缩进了原始消息字符串的行。但是前导空白意味着标题行的折叠(连接),如RFC 2822 - Internet Message Format的2.2.3和3.2.3节所述:

每个报头字段在逻辑上是由一行字符组成的 字段名、冒号和字段主体。为了方便 但是,为了处理每行998/78个字符的限制, 报头字段的字段主体部分可以分成多个 线表示;这叫做“折叠”。

在sendmail调用的函数形式中,所有行都以空白开始,因此是“展开的”(连接),您正在尝试发送

From: monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

与我们的想法不同,smtplib将不再理解To:和Subject:头文件,因为这些名称只在一行的开头被识别。相反,smtplib将假设一个非常长的发送者电子邮件地址:

monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

这将不起作用,因此出现异常。

解决方案很简单:只保留原来的消息字符串。这可以通过一个函数来完成(正如Zeeshan建议的那样),也可以直接在源代码中完成:

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: monty@python.com
To: jon@mycompany.com
Subject: Hello!

This message was sent with Python's smtplib.

这就是您的旧代码所做的工作。

请注意,我还保留了标题和正文之间的空行,以适应RFC的第3.5节(这是必需的),并根据Python风格指南PEP-0008(这是可选的)将include放在函数之外。

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

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