标签归档:smtplib

如何使用Python发送电子邮件?

问题:如何使用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()

但是,如果我尝试将其包装在这样的函数中:

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

谁能帮我理解为什么?

This code works and sends me an email just fine:

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

However if I try to wrap it in a function like this:

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

and call it I get the following errors:

 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

Can anyone help me understand why?


回答 0

我建议您使用标准软件包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

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

正如你所看到的,头部ToMIMEText对象必须是由用逗号分隔的电子邮件地址的字符串。另一方面,该sendmail函数的第二个参数必须是字符串列表(每个字符串是一个电子邮件地址)。

因此,如果您有三个电子邮件地址: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)部分使列表中的单个字符串以逗号分隔。

从您的问题中我收集到,您还没有阅读过Python教程 -如果您想在Python上学到任何东西,这是必须的-对于标准库来说,该文档非常有用。

I recommend that you use the standard packages email and smtplib together to send email. Please look at the following example (reproduced from the Python documentation). Notice that if you follow this approach, the “simple” task is indeed simple, and the more complex tasks (like attaching binary objects or sending plain/HTML multipart messages) are accomplished very rapidly.

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

For sending email to multiple destinations, you can also follow the example in the Python documentation:

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

As you can see, the header To in the MIMEText object must be a string consisting of email addresses separated by commas. On the other hand, the second argument to the sendmail function must be a list of strings (each string is an email address).

So, if you have three email addresses: person1@example.com, person2@example.com, and person3@example.com, you can do as follows (obvious sections omitted):

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

the ",".join(to) part makes a single string out of the list, separated by commas.

From your questions I gather that you have not gone through the Python tutorial – it is a MUST if you want to get anywhere in Python – the documentation is mostly excellent for the standard library.


回答 1

好吧,您想要一个最新的答案。

这是我的答案:

当我需要使用python进行邮件发送时,我会使用mailgun API,这让发送邮件整理得很头疼。他们有一个出色的app / 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!"})

您还可以跟踪事件等,请参阅快速入门指南

希望这个对你有帮助!

Well, you want to have an answer that is up-to-date and modern.

Here is my answer:

When I need to mail in Python, I use the mailgun API wich get’s a lot of the headaches with sending mails sorted out. They have a wonderfull app/api that allows you to send 5,000 free emails per month.

Sending an email would be like this:

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!"})

You can also track events and lots more, see the quickstart guide.

I hope you find this useful!


回答 2

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

I’d like to help you with sending emails by advising the yagmail package (I’m the maintainer, sorry for the advertising, but I feel it can really help!).

The whole code for you would be:

import yagmail
yag = yagmail.SMTP(FROM, 'pass')
yag.send(TO, SUBJECT, TEXT)

Note that I provide defaults for all arguments, for example if you want to send to yourself, you can omit TO, if you don’t want a subject, you can omit it also.

Furthermore, the goal is also to make it really easy to attach html code or images (and other files).

Where you put contents you can do something like:

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']

Wow, how easy it is to send attachments! This would take like 20 lines without yagmail ;)

Also, if you set it up once, you’ll never have to enter the password again (and have it safely stored). In your case you can do something like:

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

which is much more concise!

I’d invite you to have a look at the github or install it directly with pip install yagmail.


回答 3

存在压痕问题。下面的代码将起作用:

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

There is indentation problem. The code below will work:

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


回答 4

这是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='xx@example.com'):
    # 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=['12345@qq.com', '12345@126.com'],
          subject='hello', message='Your analysis has done!')

以下内容仅适用于中国用户:

如果使用126/163网状邮箱,则需要设置“客户端授权密码”,如下所示:

参考:https : //stackoverflow.com/a/41470149/2803344 https://docs.python.org/3/library/email.examples.html#email-examples

Here is an example on Python 3.x, much simpler than 2.x:

import smtplib
from email.message import EmailMessage
def send_mail(to_email, subject, message, server='smtp.example.cn',
              from_email='xx@example.com'):
    # 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.')

call this function:

send_mail(to_email=['12345@qq.com', '12345@126.com'],
          subject='hello', message='Your analysis has done!')

below may only for Chinese user:

If you use 126/163, 网易邮箱, you need to set”客户端授权密码”, like below:

ref: https://stackoverflow.com/a/41470149/2803344 https://docs.python.org/3/library/email.examples.html#email-examples


回答 5

在函数中缩进代码(可以)时,您也缩进了原始消息字符串的行。但是前导空格意味着标题行的折叠(串联),如RFC 2822-Internet消息格式的 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:and Subject:标头,因为这些名称仅在行首识别。而是smtplib假设发送者的电子邮件地址很长:

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

这将无法正常工作,因此您的异常也随之而来。

解决方案很简单:只需保留message字符串即可。这可以通过一个函数(如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放在函数外部。

While indenting your code in the function (which is ok), you did also indent the lines of the raw message string. But leading white space implies folding (concatenation) of the header lines, as described in sections 2.2.3 and 3.2.3 of RFC 2822 – Internet Message Format:

Each header field is logically a single line of characters comprising the field name, the colon, and the field body. For convenience however, and to deal with the 998/78 character limitations per line, the field body portion of a header field can be split into a multiple line representation; this is called “folding”.

In the function form of your sendmail call, all lines are starting with white space and so are “unfolded” (concatenated) and you are trying to send

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

Other than our mind suggests, smtplib will not understand the To: and Subject: headers any longer, because these names are only recognized at the beginning of a line. Instead smtplib will assume a very long sender email address:

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

This won’t work and so comes your Exception.

The solution is simple: Just preserve the message string as it was before. This can be done by a function (as Zeeshan suggested) or right away in the source code:

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

Now the unfolding does not occur and you send

From: monty@python.com
To: jon@mycompany.com
Subject: Hello!

This message was sent with Python's smtplib.

which is what works and what was done by your old code.

Note that I was also preserving the empty line between headers and body to accommodate section 3.5 of the RFC (which is required) and put the include outside the function according to the Python style guide PEP-0008 (which is optional).


回答 6

可能是在您的消息中添加了标签。打印出消息,然后再将其传递给sendMail。

It’s probably putting tabs into your message. Print out message before you pass it to sendMail.


回答 7

确保您已授予发件人和收件人的权限,以发送电子邮件和接收来自电子邮件帐户中未知来源(外部来源)的电子邮件。

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)

Make sure you have granted permission for both Sender and Receiver to send email and receive email from Unknown sources(External Sources) in Email Account.

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)


回答 8

自从我刚弄清楚这是怎么回事以来,我以为我在这里输入了两位。

看来您在SERVER连接设置上没有指定端口,当我尝试连接到不使用默认端口25的SMTP服务器时,这对我有一点影响。

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

另一个要问自己的问题是,您是否允许SMTP服务器本身上的SMTP连接?对于某些网站,例如GMAIL和ZOHO,您必须实际进入并激活电子邮件帐户中的IMAP连接。您的邮件服务器可能不允许不来自“ localhost”的SMTP连接?需要研究的东西。

最后一件事是您可能想尝试在TLS上启动连接。现在,大多数服务器都需要这种身份验证。

您会看到我在电子邮件中塞入了两个“收件人”字段。msg [‘TO’]和msg [‘FROM’] msg词典项目允许在电子邮件本身的标题中显示正确的信息,您可以在“收件人” /“发件人”字段中在电子邮件的接收端看到该标题(您可以甚至可以在此处添加“答复”字段。“收件人”和“发件人”字段本身就是服务器所需要的。

这是我在一个函数中使用的代码,它对我有用,它使用本地计算机和远程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()

Thought I’d put in my two bits here since I have just figured out how this works.

It appears that you don’t have the port specified on your SERVER connection settings, this effected me a little bit when I was trying to connect to my SMTP server that isn’t using the default port: 25.

According to the smtplib.SMTP docs, your ehlo or helo request/response should automatically be taken care of, so you shouldn’t have to worry about this (but might be something to confirm if all else fails).

Another thing to ask yourself is have you allowed SMTP connections on your SMTP server itself? For some sites like GMAIL and ZOHO you have to actually go in and activate the IMAP connections within the email account. Your mail server might not allow SMTP connections that don’t come from ‘localhost’ perhaps? Something to look into.

The final thing is you might want to try and initiate the connection on TLS. Most servers now require this type of authentication.

You’ll see I’ve jammed two TO fields into my email. The msg[‘TO’] and msg[‘FROM’] msg dictionary items allows the correct information to show up in the headers of the email itself, which one sees on the receiving end of the email in the To/From fields (you might even be able to add a Reply To field in here. The TO and FROM fields themselves are what the server requires. I know I’ve heard of some email servers rejecting emails if they don’t have the proper email headers in place.

This is the code I’ve used, in a function, that works for me to email the content of a *.txt file using my local computer and a remote SMTP server (ZOHO as shown):

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

回答 9

值得注意的是,SMTP模块支持上下文管理器,因此不需要手动调用quit(),这将确保即使有异常也总是调用它。

    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
        server.ehlo()
        server.login(user, password)
        server.sendmail(from, to, body)

It’s worth noting that the SMTP module supports the context manager so there is no need to manually call quit(), this will guarantee it is always called even if there is an exception.

    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
        server.ehlo()
        server.login(user, password)
        server.sendmail(from, to, body)

回答 10

就您的代码而言,似乎没有什么根本上的错误,只是不清楚,您实际上是如何调用该函数的。我能想到的是,当服务器没有响应时,您将收到此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方法)。

As far your code is concerned, there doesn’t seem to be anything fundamentally wrong with it except that, it is unclear how you’re actually calling that function. All I can think of is that when your server is not responding then you will get this SMTPServerDisconnected error. If you lookup the getreply() function in smtplib (excerpt below), you will get an idea.

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.
    """

check an example at https://github.com/rreddy80/sendEmails/blob/master/sendEmailAttachments.py that also uses a function call to send an email, if that’s what you’re trying to do (DRY approach).


如何使用python smtplib向多个收件人发送电子邮件?

问题:如何使用python smtplib向多个收件人发送电子邮件?

经过大量搜索后,我无法找到如何使用smtplib.sendmail发送给多个收件人的方法。问题是每次发送邮件时,邮件标题似乎都包含多个地址,但实际上只有第一个收件人会收到电子邮件。

问题似乎在于email.Message模块期望的smtplib.sendmail()功能与功能不同。

简而言之,要发送给多个收件人,您应该将标题设置为以逗号分隔的电子邮件地址的字符串。但是,该sendmail()参数to_addrs应为电子邮件地址列表。

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import smtplib

msg = MIMEMultipart()
msg["Subject"] = "Example"
msg["From"] = "me@example.com"
msg["To"] = "malcom@example.com,reynolds@example.com,firefly@example.com"
msg["Cc"] = "serenity@example.com,inara@example.com"
body = MIMEText("example email body")
msg.attach(body)
smtp = smtplib.SMTP("mailhost.example.com", 25)
smtp.sendmail(msg["From"], msg["To"].split(",") + msg["Cc"].split(","), msg.as_string())
smtp.quit()

After much searching I couldn’t find out how to use smtplib.sendmail to send to multiple recipients. The problem was every time the mail would be sent the mail headers would appear to contain multiple addresses, but in fact only the first recipient would receive the email.

The problem seems to be that the email.Message module expects something different than the smtplib.sendmail() function.

In short, to send to multiple recipients you should set the header to be a string of comma delimited email addresses. The sendmail() parameter to_addrs however should be a list of email addresses.

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import smtplib

msg = MIMEMultipart()
msg["Subject"] = "Example"
msg["From"] = "me@example.com"
msg["To"] = "malcom@example.com,reynolds@example.com,firefly@example.com"
msg["Cc"] = "serenity@example.com,inara@example.com"
body = MIMEText("example email body")
msg.attach(body)
smtp = smtplib.SMTP("mailhost.example.com", 25)
smtp.sendmail(msg["From"], msg["To"].split(",") + msg["Cc"].split(","), msg.as_string())
smtp.quit()

回答 0

确实有效,我花了大量时间尝试多种变体。

import smtplib
from email.mime.text import MIMEText

s = smtplib.SMTP('smtp.uk.xensource.com')
s.set_debuglevel(1)
msg = MIMEText("""body""")
sender = 'me@example.com'
recipients = ['john.doe@example.com', 'john.smith@example.co.uk']
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = ", ".join(recipients)
s.sendmail(sender, recipients, msg.as_string())

This really works, I spent a lot of time trying multiple variants.

import smtplib
from email.mime.text import MIMEText

s = smtplib.SMTP('smtp.uk.xensource.com')
s.set_debuglevel(1)
msg = MIMEText("""body""")
sender = 'me@example.com'
recipients = ['john.doe@example.com', 'john.smith@example.co.uk']
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = ", ".join(recipients)
s.sendmail(sender, recipients, msg.as_string())

回答 1

msg['To']需要是一个字符串:

msg['To'] = "a@b.com, b@b.com, c@b.com"

虽然recipientsin sendmail(sender, recipients, message)需要是一个列表:

sendmail("a@a.com", ["a@b.com", "b@b.com", "c@b.com"], "Howdy")

The msg['To'] needs to be a string:

msg['To'] = "a@b.com, b@b.com, c@b.com"

While the recipients in sendmail(sender, recipients, message) needs to be a list:

sendmail("a@a.com", ["a@b.com", "b@b.com", "c@b.com"], "Howdy")

回答 2

您需要了解电子邮件的可见地址和投递之间的区别。

msg["To"]本质上是印刷在信件上的东西。它实际上没有任何作用。除了您的电子邮件客户端(与常规邮递员一样)之外,您还将假定这是您要将电子邮件发送给的人。

但是,实际交付可能会大不相同。所以你可以将电子邮件(或副本)放入完全不同的人的邮箱中。

有多种原因。例如转发。的To:头字段不上转发更改,但是,电子邮件被放入不同的邮箱。

smtp.sendmail现在,该命令将负责实际交付。email.Message仅是信件的内容,而不是交货的内容。

在低级中SMTP,您需要一个个地给接收者一个地址,这就是为什么地址列表(不包括名称!)才是明智的API的原因。

对于标题,它还可以包含例如名称,例如To: First Last <email@addr.tld>, Other User <other@mail.tld>因此,不建议您使用代码示例,因为它将无法传递此邮件,因为仅将其拆分给,您,您仍然没有有效的地址!

You need to understand the difference between the visible address of an email, and the delivery.

msg["To"] is essentially what is printed on the letter. It doesn’t actually have any effect. Except that your email client, just like the regular post officer, will assume that this is who you want to send the email to.

The actual delivery however can work quite different. So you can drop the email (or a copy) into the post box of someone completely different.

There are various reasons for this. For example forwarding. The To: header field doesn’t change on forwarding, however the email is dropped into a different mailbox.

The smtp.sendmail command now takes care of the actual delivery. email.Message is the contents of the letter only, not the delivery.

In low-level SMTP, you need to give the receipients one-by-one, which is why a list of adresses (not including names!) is the sensible API.

For the header, it can also contain for example the name, e.g. To: First Last <email@addr.tld>, Other User <other@mail.tld>. Your code example therefore is not recommended, as it will fail delivering this mail, since just by splitting it on , you still not not have the valid adresses!


回答 3

这个对我有用。

import smtplib
from email.mime.text import MIMEText

s = smtplib.SMTP('smtp.uk.xensource.com')
s.set_debuglevel(1)
msg = MIMEText("""body""")
sender = 'me@example.com'
recipients = 'john.doe@example.com,john.smith@example.co.uk'
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = recipients
s.sendmail(sender, recipients.split(','), msg.as_string())

It works for me.

import smtplib
from email.mime.text import MIMEText

s = smtplib.SMTP('smtp.uk.xensource.com')
s.set_debuglevel(1)
msg = MIMEText("""body""")
sender = 'me@example.com'
recipients = 'john.doe@example.com,john.smith@example.co.uk'
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = recipients
s.sendmail(sender, recipients.split(','), msg.as_string())

回答 4

我尝试了下面的方法,它就像一个魅力:)

rec_list =  ['first@example.com', 'second@example.com']
rec =  ', '.join(rec_list)

msg['To'] = rec

send_out = smtplib.SMTP('localhost')
send_out.sendmail(me, rec_list, msg.as_string())

I tried the below and it worked like a charm :)

rec_list =  ['first@example.com', 'second@example.com']
rec =  ', '.join(rec_list)

msg['To'] = rec

send_out = smtplib.SMTP('localhost')
send_out.sendmail(me, rec_list, msg.as_string())

回答 5

所以实际上问题是SMTP.sendmail和email.MIMEText需要两个不同的东西。

email.MIMEText设置电子邮件正文的“ To:”标头。它仅用于向另一端的人显示结果,并且像所有电子邮件头一样,必须为单个字符串。(请注意,它实际上与实际收到邮件的人没有任何关系。)

另一方面,SMTP.sendmail为SMTP协议设置邮件的“信封”。它需要一个Python字符串列表,每个字符串都有一个地址。

因此,您需要做的就是合并收到的两份回复。将msg [‘To’]设置为单个字符串,但将原始列表传递给sendmail:

emails = ['a.com','b.com', 'c.com']
msg['To'] = ', '.join( emails ) 
....
s.sendmail( msg['From'], emails, msg.as_string())

So actually the problem is that SMTP.sendmail and email.MIMEText need two different things.

email.MIMEText sets up the “To:” header for the body of the e-mail. It is ONLY used for displaying a result to the human being at the other end, and like all e-mail headers, must be a single string. (Note that it does not actually have to have anything to do with the people who actually receive the message.)

SMTP.sendmail, on the other hand, sets up the “envelope” of the message for the SMTP protocol. It needs a Python list of strings, each of which has a single address.

So, what you need to do is COMBINE the two replies you received. Set msg[‘To’] to a single string, but pass the raw list to sendmail:

emails = ['a.com','b.com', 'c.com']
msg['To'] = ', '.join( emails ) 
....
s.sendmail( msg['From'], emails, msg.as_string())

回答 6

我想出了这个可导入的模块功能。在此示例中,它使用gmail电子邮件服务器。它分为标题和消息,因此您可以清楚地看到发生了什么:

import smtplib

def send_alert(subject=""):

    to = ['email@one.com', 'email2@another_email.com', 'a3rd@email.com']
    gmail_user = 'me@gmail.com'
    gmail_pwd = 'my_pass'
    smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
    smtpserver.ehlo()
    smtpserver.starttls()
    smtpserver.ehlo
    smtpserver.login(gmail_user, gmail_pwd)
    header = 'To:' + ", ".join(to) + '\n' + 'From: ' + gmail_user + '\n' + 'Subject: ' + subject + '\n'
    msg = header + '\n' + subject + '\n\n'
    smtpserver.sendmail(gmail_user, to, msg)
    smtpserver.close()

I came up with this importable module function. It uses the gmail email server in this example. Its split into header and message so you can clearly see whats going on:

import smtplib

def send_alert(subject=""):

    to = ['email@one.com', 'email2@another_email.com', 'a3rd@email.com']
    gmail_user = 'me@gmail.com'
    gmail_pwd = 'my_pass'
    smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
    smtpserver.ehlo()
    smtpserver.starttls()
    smtpserver.ehlo
    smtpserver.login(gmail_user, gmail_pwd)
    header = 'To:' + ", ".join(to) + '\n' + 'From: ' + gmail_user + '\n' + 'Subject: ' + subject + '\n'
    msg = header + '\n' + subject + '\n\n'
    smtpserver.sendmail(gmail_user, to, msg)
    smtpserver.close()

回答 7

几个月前我弄清楚了,然后发表了博客。摘要是:

如果要使用smtplib向多个收件人发送电子邮件,请使用email.Message.add_header('To', eachRecipientAsString)添加它们,然后在调用sendmail方法时,use email.Message.get_all('To')将消息发送给所有收件人。抄送和密件抄送收件人的同上。

I figured this out a few months back and blogged about it. The summary is:

If you want to use smtplib to send email to multiple recipients, use email.Message.add_header('To', eachRecipientAsString) to add them, and then when you invoke the sendmail method, use email.Message.get_all('To') send the message to all of them. Ditto for Cc and Bcc recipients.


回答 8

下面的解决方案为我工作。它成功地将电子邮件发送给多个收件人,包括“抄送”和“密件抄送”。

toaddr = ['mailid_1','mailid_2']
cc = ['mailid_3','mailid_4']
bcc = ['mailid_5','mailid_6']
subject = 'Email from Python Code'
fromaddr = 'sender_mailid'
message = "\n  !! Hello... !!"

msg['From'] = fromaddr
msg['To'] = ', '.join(toaddr)
msg['Cc'] = ', '.join(cc)
msg['Bcc'] = ', '.join(bcc)
msg['Subject'] = subject

s.sendmail(fromaddr, (toaddr+cc+bcc) , message)

The solution below worked for me. It successfully sends an email to multiple recipients, including “CC” and “BCC.”

toaddr = ['mailid_1','mailid_2']
cc = ['mailid_3','mailid_4']
bcc = ['mailid_5','mailid_6']
subject = 'Email from Python Code'
fromaddr = 'sender_mailid'
message = "\n  !! Hello... !!"

msg['From'] = fromaddr
msg['To'] = ', '.join(toaddr)
msg['Cc'] = ', '.join(cc)
msg['Bcc'] = ', '.join(bcc)
msg['Subject'] = subject

s.sendmail(fromaddr, (toaddr+cc+bcc) , message)

回答 9

那么,在方法本asnwer方法并没有为我工作。我不知道,也许这是Python3(我正在使用3.4版本)或gmail相关问题,但是经过一番尝试之后,对我有用的解决方案是

s.send_message(msg)

代替

s.sendmail(sender, recipients, msg.as_string())

Well, the method in this asnwer method did not work for me. I don’t know, maybe this is a Python3 (I am using the 3.4 version) or gmail related issue, but after some tries, the solution that worked for me, was the line

s.send_message(msg)

instead of

s.sendmail(sender, recipients, msg.as_string())

回答 10

我使用python 3.6,以下代码对我有用

email_send = 'xxxxx@xxx.xxx,xxxx@xxx.xxx'
server.sendmail(email_user,email_send.split(','),text)    

I use python 3.6 and the following code works for me

email_send = 'xxxxx@xxx.xxx,xxxx@xxx.xxx'
server.sendmail(email_user,email_send.split(','),text)    

回答 11

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def sender(recipients): 

    body = 'Your email content here'
    msg = MIMEMultipart()

    msg['Subject'] = 'Email Subject'
    msg['From'] = 'your.email@gmail.com'
    msg['To'] = (', ').join(recipients.split(','))

    msg.attach(MIMEText(body,'plain'))

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    server.login('your.email@gmail.com', 'yourpassword')
    server.send_message(msg)
    server.quit()

if __name__ == '__main__':
    sender('email_1@domain.com,email_2@domain.com')

它仅对我有用send_message函数,并在列表中使用接收函数python 3.6中的join函数。

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def sender(recipients): 

    body = 'Your email content here'
    msg = MIMEMultipart()

    msg['Subject'] = 'Email Subject'
    msg['From'] = 'your.email@gmail.com'
    msg['To'] = (', ').join(recipients.split(','))

    msg.attach(MIMEText(body,'plain'))

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    server.login('your.email@gmail.com', 'yourpassword')
    server.send_message(msg)
    server.quit()

if __name__ == '__main__':
    sender('email_1@domain.com,email_2@domain.com')

It only worked for me with send_message function and using the join function in the list whith recipients, python 3.6.


回答 12

您可以在文本文件上写收件人电子邮件时尝试使用此方法

from email.mime.text import MIMEText
from email.header import Header
import smtplib

f =  open('emails.txt', 'r').readlines()
for n in f:
     emails = n.rstrip()
server = smtplib.SMTP('smtp.uk.xensource.com')
server.ehlo()
server.starttls()
body = "Test Email"
subject = "Test"
from = "me@example.com"
to = emails
msg = MIMEText(body,'plain','utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] =  Header(from, 'utf-8')
msg['To'] = Header(to, 'utf-8')
text = msg.as_string()
try:
   server.send(from, emails, text)
   print('Message Sent Succesfully')
except:
   print('There Was An Error While Sending The Message')

you can try this when you write the recpient emails on a text file

from email.mime.text import MIMEText
from email.header import Header
import smtplib

f =  open('emails.txt', 'r').readlines()
for n in f:
     emails = n.rstrip()
server = smtplib.SMTP('smtp.uk.xensource.com')
server.ehlo()
server.starttls()
body = "Test Email"
subject = "Test"
from = "me@example.com"
to = emails
msg = MIMEText(body,'plain','utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] =  Header(from, 'utf-8')
msg['To'] = Header(to, 'utf-8')
text = msg.as_string()
try:
   server.send(from, emails, text)
   print('Message Sent Succesfully')
except:
   print('There Was An Error While Sending The Message')