如何用Python发送电子邮件?

这个代码工作,并发送给我一个电子邮件就好了:

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

但是,如果我试图把它包装在这样的function:

 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 

任何人都可以帮我理解为什么?

我build议你使用标准包emailsmtplib一起发送电子邮件。 请看下面的例子(从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 COMMASPACE = ', ' # 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'] = COMMASPACE.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必须是由逗号分隔的电子邮件地址组成的string。 另一方面, sendmail函数的第二个参数必须是一个string列表(每个string是一个电子邮件地址)。

所以,如果你有三个电子邮件地址: person1@example.comperson2@example.comperson3@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)部分使得列表之外的单个string以逗号分隔。

从你的问题我收集,你没有通过Python教程 – 这是必须的,如果你想在Python中得到任何地方 – 文档大多是标准库的优秀。

那么,你想有一个最新的和现代的答案。

这是我的答案:

当我需要用python邮件时,我使用mailgun API,因为发送邮件的时候会遇到很多麻烦。 他们有一个惊人的应用程序/ api,可以让你免费发送每月10,000封电子邮件。

发送电子邮件会是这样的:

 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 <mailgun@YOUR_DOMAIN_NAME>", "to": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"], "subject": "Hello", "text": "Testing some Mailgun awesomness!"}) 

您还可以跟踪事件和更多,请参阅快速入门指南 。

我希望你觉得这个有用!

我想通过build议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;)

另外,如果您设置了一次,则不必再次input密码(并且已经安全地存储)。 在你的情况下,你可以做这样的事情:

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

尝试这个:

 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

在缩进函数中的代码(这是正确的)的同时,您也缩进了原始消息string的行。 但是领先的白色空间意味着标题行的折叠(级联),如RFC 2822的第2.2.3和3.2.3节所述- 互联网消息格式 :

每个标题字段在逻辑上是由字段名称,冒号和字段正文组成的一行字符。 然而,为了方便起见,为了处理每行998/78字符限制,可以将头字段的字段主体部分拆分成多行表示; 这被称为“折叠”。

sendmail调用的函数forms中,所有行都以空格开始,所以“展开”(连接),您正在尝试发送

 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. 

这不会工作,所以你的例外。

解决scheme很简单:只保留messagestring,就像以前一样。 这可以通过一个函数(Zeeshanbuild议)或者在源代码中完成:

 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 (这是可选的)将函数包含在函数之外。

这可能是把标签放在你的消息。 在将邮件传递给sendMail之前打印出邮件。

就你的代码而言,似乎没有任何根本性的错误,除此之外,还不清楚你是如何调用这个函数的。 所有我能想到的是,当你的服务器没有响应,那么你会得到这个SMTPServerDisconnected错误。 如果你在smtplib中查找getreply()函数(摘录如下),你会得到一个想法。

 def getreply(self): """Get a reply from the server. Returns a tuple consisting of: - server response code (eg '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方法),也使用函数调用来发送电子邮件。;

因为我刚才知道这是如何工作的,所以我想在这里放两个字。

看起来你没有在你的SERVER连接设置中指定端口,当我试图连接到我的SMTP服务器,而不是使用默认端口时,这有点影响了我:25。

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

还有一件事要问自己,是否允许SMTP服务器上的SMTP连接? 对于像GMAIL和ZOHO的一些网站,您必须真正进入并激活电子邮件帐户中的IMAP连接。 您的邮件服务器可能不允许不是来自“localhost”的SMTP连接? 有什么东西要看。

最后一点是你可能想尝试在TLS上启动连接。 现在大多数服务器都需要这种authentication。

你会看到我已经堵塞了两个TO字段到我的电子邮件。 msg ['TO']和msg ['FROM'] msg字典项目允许正确的信息显示在电子邮件本身的标题中,在收件人/发件人字段甚至可以在这里添加一个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()