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

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

有人能告诉我为什么吗?


当前回答

在摆弄了很多例子之后,例如这里 这对我来说很管用:

import smtplib
from email.mime.text import MIMEText

# SMTP sendmail server mail relay
host = 'mail.server.com'
port = 587 # starttls not SSL 465 e.g gmail, port 25 blocked by most ISPs & AWS
sender_email = 'name@server.com'
recipient_email = 'name@domain.com'
password = 'YourSMTPServerAuthenticationPass'
subject = "Server - "
body = "Message from server"

def sendemail(host, port, sender_email, recipient_email, password, subject, body):
    try:
        p1 = f'<p><HR><BR>{recipient_email}<BR>'
        p2 = f'<h2><font color="green">{subject}</font></h2>'
        p3 = f'<p>{body}'
        p4 = f'<p>Kind Regards,<BR><BR>{sender_email}<BR><HR>'
        
        message = MIMEText((p1+p2+p3+p4), 'html')  
        # servers may not accept non RFC 5321 / RFC 5322 / compliant TXT & HTML typos

        message['From'] = f'Sender Name <{sender_email}>'
        message['To'] = f'Receiver Name <{recipient_email}>'
        message['Cc'] = f'Receiver2 Name <>'
        message['Subject'] = f'{subject}'
        msg = message.as_string()

        server = smtplib.SMTP(host, port)
        print("Connection Status: Connected")
        server.set_debuglevel(1)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(sender_email, password)
        print("Connection Status: Logged in")
        server.sendmail(sender_email, recipient_email, msg)
        print("Status: Email as HTML successfully sent")

    except Exception as e:
            print(e)
            print("Error: unable to send email")

# Run
sendemail(host, port, sender_email, recipient_email, password, subject, body)
print("Status: Exit")

其他回答

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

import smtplib

s = smtplib.SMTP(your smtp server, smtp port) #SMTP session

message = "Hii!!!"

s.sendmail("sender", "Receiver", message) # sending the mail

s.quit() # terminating the session

我建议您使用标准包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's email address
# you == the recipient's 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's 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()

如您所见,MIMEText对象中的报头To必须是由逗号分隔的电子邮件地址组成的字符串。另一方面,sendmail函数的第二个参数必须是一个字符串列表(每个字符串都是一个电子邮件地址)。

所以,如果你有三个电子邮件地址:person1@example.com, person2@example.com和person3@example.com,你可以这样做(明显的部分省略了):

to = ["person1@example.com", "person2@example.com", "person3@example.com"]
msg['To'] = ",".join(to)
s.sendmail(me, to, msg.as_string())

",".join(to)部分从列表中生成一个单独的字符串,用逗号分隔。

从你的问题中,我猜你还没有读过Python教程——如果你想在Python中有所了解,这是必须的——标准库的文档大部分都很出色。

我编写了一个简单的函数send_email(),用于使用smtplib和电子邮件包发送电子邮件(链接到我的文章)。它还使用dotenv包来加载发件人的电子邮件和密码(请不要在代码中保密!)我正在使用Gmail电子邮件服务。密码是应用程序密码(这里是谷歌文档如何生成应用程序密码)。

import os
import smtplib
from email.message import EmailMessage
from dotenv import load_dotenv
_ = load_dotenv()


def send_email(to, subject, message):
    try:
        email_address = os.environ.get("EMAIL_ADDRESS")
        email_password = os.environ.get("EMAIL_PASSWORD")

        if email_address is None or email_password is None:
            # no email address or password
            # something is not configured properly
            print("Did you set email address and password correctly?")
            return False

        # create email
        msg = EmailMessage()
        msg['Subject'] = subject
        msg['From'] = email_address
        msg['To'] = to
        msg.set_content(message)

        # send email
        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
            smtp.login(email_address, email_password)
            smtp.send_message(msg)
        return True
    except Exception as e:
        print("Problem during send email")
        print(str(e))
    return False

以上方法对于简单的电子邮件发送是可行的。如果您正在寻找更高级的功能,例如HTML内容或附件,当然可以手工编码,但我建议使用现有的包,例如yagmail。

Gmail每天限制500封邮件。对于每天发送许多电子邮件,请考虑事务性电子邮件服务提供商,如Amazon SES, MailGun, MailJet或SendGrid。

就你的代码而言,它似乎没有任何根本性的错误,除了,不清楚你实际上是如何调用这个函数的。我能想到的是,当您的服务器没有响应时,您将得到这个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方法)。