I need for testing purposes to populate few hundred email boxes with various messages, and was going to use smtplib for that. But among other things I need to be able to send messages not only TO specific mailboxes, but CC and BCC them as well. It does not look like smtplib supports CC-ing and BCC-ing while sending emails.
Looking for suggestions how to do CC or BCC sending messages from the python script.
(And — no, I’m not creating a script to spam anyone outside of my testing environment.)
Email headers don’t matter to the smtp server. Just add the CC and BCC recipients to the toaddrs when you send your email. For CC, add them to the CC header.
toaddr = 'buffy@sunnydale.k12.ca.us'
cc = ['alexander@sunydale.k12.ca.us','willow@sunnydale.k12.ca.us']
bcc = ['chairman@slayerscouncil.uk']
fromaddr = 'giles@sunnydale.k12.ca.us'
message_subject = "disturbance in sector 7"
message_text = "Three are dead in an attack in the sewers below sector 7."
message = "From: %s\r\n" % fromaddr
+ "To: %s\r\n" % toaddr
+ "CC: %s\r\n" % ",".join(cc)
+ "Subject: %s\r\n" % message_subject
+ "\r\n"
+ message_text
toaddrs = [toaddr] + cc + bcc
server = smtplib.SMTP('smtp.sunnydale.k12.ca.us')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, message)
server.quit()
回答 1
关键是将收件人添加为sendmail呼叫中的电子邮件ID列表。
import smtplib
from email.mime.multipart importMIMEMultipart
me ="user63503@gmail.com"
to ="someone@gmail.com"
cc ="anotherperson@gmail.com,someone@yahoo.com"
bcc ="bccperson1@gmail.com,bccperson2@yahoo.com"
rcpt = cc.split(",")+ bcc.split(",")+[to]
msg =MIMEMultipart('alternative')
msg['Subject']="my subject"
msg['To']= to
msg['Cc']= cc
msg.attach(my_msg_body)
server = smtplib.SMTP("localhost")# or your smtp server
server.sendmail(me, rcpt, msg.as_string())
server.quit()
Key thing is to add the recipients as a list of email ids in your sendmail call.
import smtplib
from email.mime.multipart import MIMEMultipart
me = "user63503@gmail.com"
to = "someone@gmail.com"
cc = "anotherperson@gmail.com,someone@yahoo.com"
bcc = "bccperson1@gmail.com,bccperson2@yahoo.com"
rcpt = cc.split(",") + bcc.split(",") + [to]
msg = MIMEMultipart('alternative')
msg['Subject'] = "my subject"
msg['To'] = to
msg['Cc'] = cc
msg.attach(my_msg_body)
server = smtplib.SMTP("localhost") # or your smtp server
server.sendmail(me, rcpt, msg.as_string())
server.quit()
toaddr ='buffy@sunnydale.k12.ca.us'
cc =['alexander@sunydale.k12.ca.us','willow@sunnydale.k12.ca.us']
bcc =['chairman@slayerscouncil.uk']
fromaddr ='giles@sunnydale.k12.ca.us'
message_subject ="disturbance in sector 7"
message_text ="Three are dead in an attack in the sewers below sector 7."
message ="From: %s\r\n"% fromaddr
+"To: %s\r\n"% toaddr
+"CC: %s\r\n"%",".join(cc)# don't add this, otherwise "to and cc" receivers will know who are the bcc receivers# + "BCC: %s\r\n" % ",".join(bcc)+"Subject: %s\r\n"% message_subject
+"\r\n"+ message_text
toaddrs =[toaddr]+ cc + bcc
server = smtplib.SMTP('smtp.sunnydale.k12.ca.us')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, message)
server.quit()
And this: “””Notice that the second argument to sendmail(), the recipients, is passed as a list. You can include any number of addresses in the list to have the message delivered to each of them in turn. Since the envelope information is separate from the message headers, you can even BCC someone by including them in the method argument but not in the message header.””” from http://pymotw.com/2/smtplib
toaddr = 'buffy@sunnydale.k12.ca.us'
cc = ['alexander@sunydale.k12.ca.us','willow@sunnydale.k12.ca.us']
bcc = ['chairman@slayerscouncil.uk']
fromaddr = 'giles@sunnydale.k12.ca.us'
message_subject = "disturbance in sector 7"
message_text = "Three are dead in an attack in the sewers below sector 7."
message = "From: %s\r\n" % fromaddr
+ "To: %s\r\n" % toaddr
+ "CC: %s\r\n" % ",".join(cc)
# don't add this, otherwise "to and cc" receivers will know who are the bcc receivers
# + "BCC: %s\r\n" % ",".join(bcc)
+ "Subject: %s\r\n" % message_subject
+ "\r\n"
+ message_text
toaddrs = [toaddr] + cc + bcc
server = smtplib.SMTP('smtp.sunnydale.k12.ca.us')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, message)
server.quit()
回答 3
从2011年11月发布的Python 3.2开始,smtplib具有一个新功能,send_message而不是just sendmail,这使得处理To / CC / BCC更加容易。从Python官方电子邮件示例提取一些修改后,我们得到:
# Import smtplib for the actual sending functionimport smtplib
# Import the email modules we'll needfrom email.message importEmailMessage# Open the plain text file whose name is in textfile for reading.with open(textfile)as fp:# Create a text/plain message
msg =EmailMessage()
msg.set_content(fp.read())# me == the sender's email address# you == the recipient's email address# them == the cc's email address# they == the bcc's email address
msg['Subject']='The contents of %s'% textfile
msg['From']= me
msg['To']= you
msg['Cc']= them
msg['Bcc']= they
# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
As of Python 3.2, released Nov 2011, the smtplib has a new function send_message instead of just sendmail, which makes dealing with To/CC/BCC easier. Pulling from the Python official email examples, with some slight modifications, we get:
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.message import EmailMessage
# Open the plain text file whose name is in textfile for reading.
with open(textfile) as fp:
# Create a text/plain message
msg = EmailMessage()
msg.set_content(fp.read())
# me == the sender's email address
# you == the recipient's email address
# them == the cc's email address
# they == the bcc's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
msg['Cc'] = them
msg['Bcc'] = they
# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
The problem is, the sendmail function treats all those headers the same, meaning they’ll get sent (visibly) to all To: and BCC: users, defeating the purposes of BCC. The solution, as shown in many of the other answers here, was to not include BCC in the headers, and instead only in the list of emails passed to sendmail.
The caveat is that send_message requires a Message object, meaning you’ll need to import a class from email.message instead of merely passing strings into sendmail.
回答 4
TO,CC和BCC之间的区别仅出现在文本标题中。在SMTP级别,每个人都是收件人。
收件人-收件人地址为“收件人:”标题
抄送-有此收件人地址的抄送:标头
密件抄送-根本没有在标题中提到此收件人,但仍然是收件人。
如果你有
TO: abc@company.com
CC: xyz@company.com
BCC: boss@company.com
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
raiseSMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected:Connection unexpectedly closed
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
# Import smtplib for the actual sending functionimport smtplib
# Import the email modules we'll needfrom email.mime.text importMIMEText# 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()
# Import smtplib for the actual sending functionimport smtplib
# Here are the email package modules we'll needfrom email.mime.image importMIMEImagefrom email.mime.multipart importMIMEMultipart# 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 formatfor 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()
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.
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.
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']
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!).
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:
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 importEmailMessagedef 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!')
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.
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).
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)
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()
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)
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.
"""
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.
"""
Send the email to a real SMTP server. If you don’t want to set up your own then you can find companies that will run one for you, such as Google themselves.
I use Gmail as my SMTP server for Django. Much easier than dealing with postfix or whatever other server. I’m not in the business of managing email servers.
NOTE: In 2016 Gmail is not allowing this anymore by default. You can either use an external service like Sendgrid, or you can follow this tutorial from Google to reduce security but allow this option: https://support.google.com/accounts/answer/6010255
from django.core.mail import EmailMessage
email = EmailMessage('Subject', 'Body', to=['def@domain.com'])
email.send()
Then I got “1” as the O/P i.e. Success. And I received the mail too. :)
What is the meaning of domain.com?
回答 4
对于Django 1.7版,如果上述解决方案不起作用,请尝试以下操作
在settings.py中添加
#For email
EMAIL_BACKEND ='django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS =True
EMAIL_HOST ='smtp.gmail.com'
EMAIL_HOST_USER ='sender@gmail.com'#Must generate specific password for your app in [gmail settings][1]
EMAIL_HOST_PASSWORD ='app_specific_password'
EMAIL_PORT =587#This did the trick
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
If you are using gmail for this, setup 2-step verification and Application specific password and copy and paste that password in above EMAIL_HOST_PASSWORD value.
In addition to the DEFAULT_FROM_EMAIL fix others have mentioned, and allowing less-secure apps to access the account, I had to navigate to https://accounts.google.com/DisplayUnlockCaptcha while signed in as the account in question to get Django to finally authenticate.
I went to that URL through a SSH tunnel to the web server to make sure the IP address was the same; I’m not totally sure if that’s necessary but it can’t hurt. You can do that like so: ssh -D 8080 -fN <username>@<host>, then set your web browser to use localhost:8080 as a SOCKS proxy.
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.
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.
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!
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:
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:
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.
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
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 importMIMETextfrom email.header importHeaderimport 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')
I am having problems understanding how to email an attachment using Python. I have successfully emailed simple messages with the smtplib. Could someone please explain how to send an attachment in an email. I know there are other posts online but as a Python beginner I find them hard to understand.
回答 0
这是另一个:
import smtplib
from os.path import basename
from email.mime.application importMIMEApplicationfrom email.mime.multipart importMIMEMultipartfrom email.mime.text importMIMETextfrom email.utils import COMMASPACE, formatdate
def send_mail(send_from, send_to, subject, text, files=None,
server="127.0.0.1"):assert isinstance(send_to, list)
msg =MIMEMultipart()
msg['From']= send_from
msg['To']= COMMASPACE.join(send_to)
msg['Date']= formatdate(localtime=True)
msg['Subject']= subject
msg.attach(MIMEText(text))for f in files or[]:with open(f,"rb")as fil:
part =MIMEApplication(
fil.read(),Name=basename(f))# After the file is closed
part['Content-Disposition']='attachment; filename="%s"'% basename(f)
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
def send_mail(send_from, send_to, subject, text, files=None,
server="127.0.0.1"):
assert isinstance(send_to, list)
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(text))
for f in files or []:
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
# After the file is closed
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
It’s much the same as the first example… But it should be easier to drop in.
回答 1
这是Olipython 3 的修改版本
import smtplib
from pathlib importPathfrom email.mime.multipart importMIMEMultipartfrom email.mime.base importMIMEBasefrom email.mime.text importMIMETextfrom email.utils import COMMASPACE, formatdate
from email import encoders
def send_mail(send_from, send_to, subject, message, files=[],
server="localhost", port=587, username='', password='',
use_tls=True):"""Compose and send email with provided info and attachments.
Args:
send_from (str): from name
send_to (list[str]): to name(s)
subject (str): message title
message (str): message body
files (list[str]): list of file paths to be attached to email
server (str): mail server host name
port (int): port number
username (str): server auth username
password (str): server auth password
use_tls (bool): use TLS mode
"""
msg =MIMEMultipart()
msg['From']= send_from
msg['To']= COMMASPACE.join(send_to)
msg['Date']= formatdate(localtime=True)
msg['Subject']= subject
msg.attach(MIMEText(message))for path in files:
part =MIMEBase('application',"octet-stream")with open(path,'rb')as file:
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition','attachment; filename="{}"'.format(Path(path).name))
msg.attach(part)
smtp = smtplib.SMTP(server, port)if use_tls:
smtp.starttls()
smtp.login(username, password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
Here is the modified version from Oli for python 3
import smtplib
from pathlib import Path
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders
def send_mail(send_from, send_to, subject, message, files=[],
server="localhost", port=587, username='', password='',
use_tls=True):
"""Compose and send email with provided info and attachments.
Args:
send_from (str): from name
send_to (list[str]): to name(s)
subject (str): message title
message (str): message body
files (list[str]): list of file paths to be attached to email
server (str): mail server host name
port (int): port number
username (str): server auth username
password (str): server auth password
use_tls (bool): use TLS mode
"""
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(message))
for path in files:
part = MIMEBase('application', "octet-stream")
with open(path, 'rb') as file:
part.set_payload(file.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="{}"'.format(Path(path).name))
msg.attach(part)
smtp = smtplib.SMTP(server, port)
if use_tls:
smtp.starttls()
smtp.login(username, password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
回答 2
这是我最终使用的代码:
import smtplib
from email.MIMEMultipartimportMIMEMultipartfrom email.MIMEBaseimportMIMEBasefrom email importEncoders
SUBJECT ="Email Data"
msg =MIMEMultipart()
msg['Subject']= SUBJECT
msg['From']= self.EMAIL_FROM
msg['To']=', '.join(self.EMAIL_TO)
part =MIMEBase('application',"octet-stream")
part.set_payload(open("text.txt","rb").read())Encoders.encode_base64(part)
part.add_header('Content-Disposition','attachment; filename="text.txt"')
msg.attach(part)
server = smtplib.SMTP(self.EMAIL_SERVER)
server.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())
username ='my-address@gmail.com'
password ='top-secret'
default_address =['my-address2@gmail.com']
send_mail(send_from= username,
subject="test",
text="text",
send_to=None,
files=# pass a list with the full filepaths here...)
import os.path
import smtplib
from email.mime.multipart importMIMEMultipartfrom email.mime.text importMIMETextfrom email.mime.application importMIMEApplicationdef send_email(subject, message, from_email, to_email=[], attachment=[]):"""
:param subject: email subject
:param message: Body content of the email (string), can be HTML/CSS or plain text
:param from_email: Email address from where the email is sent
:param to_email: List of email recipients, example: ["a@a.com", "b@b.com"]
:param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
"""
msg =MIMEMultipart()
msg['Subject']= subject
msg['From']= from_email
msg['To']=", ".join(to_email)
msg.attach(MIMEText(message,'html'))for f in attachment:with open(f,'rb')as a_file:
basename = os.path.basename(f)
part =MIMEApplication(a_file.read(),Name=basename)
part['Content-Disposition']='attachment; filename="%s"'% basename
msg.attach(part)
email = smtplib.SMTP('your-smtp-host-name.com')
email.sendmail(from_email, to_email, msg.as_string())
Other answers are excellent, though I still wanted to share a different approach in case someone is looking for alternatives.
Main difference here is that using this approach you can use HTML/CSS to format your message, so you can get creative and give some styling to your email. Though you aren’t enforced to use HTML, you can also still use only plain text.
Notice that this function accepts sending the email to multiple recipients and also allows to attach multiple files.
I’ve only tried this on Python 2, but I think it should work fine on 3 as well:
import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
def send_email(subject, message, from_email, to_email=[], attachment=[]):
"""
:param subject: email subject
:param message: Body content of the email (string), can be HTML/CSS or plain text
:param from_email: Email address from where the email is sent
:param to_email: List of email recipients, example: ["a@a.com", "b@b.com"]
:param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
"""
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ", ".join(to_email)
msg.attach(MIMEText(message, 'html'))
for f in attachment:
with open(f, 'rb') as a_file:
basename = os.path.basename(f)
part = MIMEApplication(a_file.read(), Name=basename)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename
msg.attach(part)
email = smtplib.SMTP('your-smtp-host-name.com')
email.sendmail(from_email, to_email, msg.as_string())
I hope this helps! :-)
回答 8
from email.mime.text importMIMETextfrom email.mime.multipart importMIMEMultipartimport smtplib
import mimetypes
import email.mime.application
smtp_ssl_host ='smtp.gmail.com'# smtp.mail.yahoo.com
smtp_ssl_port =465
s = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port)
s.login(email_user, email_pass)
msg =MIMEMultipart()
msg['Subject']='I have a picture'
msg['From']= email_user
msg['To']= email_user
txt =MIMEText('I just bought a new camera.')
msg.attach(txt)
filename ='introduction-to-algorithms-3rd-edition-sep-2010.pdf'#path to file
fo=open(filename,'rb')
attach = email.mime.application.MIMEApplication(fo.read(),_subtype="pdf")
fo.close()
attach.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attach)
s.send_message(msg)
s.quit()
Below is combination of what I’ve found from SoccerPlayer’s post Here and the following link that made it easier for me to attach an xlsx file. Found Here
#! /usr/bin/pythonimport smtplibfrom email.mime.multipart importMIMEMultipartfrom email.mime.text importMIMEText# me == my email address# you == recipient's email address
me ="my@email.com"
you ="your@email.com"# Create message container - the correct MIME type is multipart/alternative.
msg =MIMEMultipart('alternative')
msg['Subject']="Link"
msg['From']= me
msg['To']= you# Create the body of the message (a plain-text and an HTML version).
text ="Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html ="""\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.
</p>
</body>
</html>
"""# Record the MIME types of both parts - text/plain and text/html.
part1 =MIMEText(text,'plain')
part2 =MIMEText(html,'html')# Attach parts into message container.# According to RFC 2046, the last part of a multipart message, in this case# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')# sendmail function takes 3 arguments: sender's address, recipient's address# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()
Here’s an example of how to create an HTML message with an alternative plain text version:
#! /usr/bin/python
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "my@email.com"
you = "your@email.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.
</p>
</body>
</html>
"""
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()
from mailer importMailerfrom mailer importMessage
message =Message(From="me@example.com",To="you@example.com")
message.Subject="An HTML Email"
message.Html="""<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""
sender =Mailer('smtp.example.com')
sender.send(message)
from mailer import Mailer
from mailer import Message
message = Message(From="me@example.com",
To="you@example.com")
message.Subject = "An HTML Email"
message.Html = """<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""
sender = Mailer('smtp.example.com')
sender.send(message)
import smtplib
from email.mime.multipart importMIMEMultipartfrom email.mime.text importMIMEText# me == my email address# you == recipient's email address
me ="my@email.com"
you ="your@email.com"# Create message container - the correct MIME type is multipart/alternative.
msg =MIMEMultipart('alternative')
msg['Subject']="Link"
msg['From']= me
msg['To']= you
# Create the body of the message (a plain-text and an HTML version).
text ="Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html ="""\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.
</p>
</body>
</html>
"""# Record the MIME types of both parts - text/plain and text/html.
part1 =MIMEText(text,'plain')
part2 =MIMEText(html,'html')# Attach parts into message container.# According to RFC 2046, the last part of a multipart message, in this case# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)# Send the message via local SMTP server.
mail = smtplib.SMTP('smtp.gmail.com',587)
mail.ehlo()
mail.starttls()
mail.login('userName','password')
mail.sendmail(me, you, msg.as_string())
mail.quit()
Here is a Gmail implementation of the accepted answer:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "my@email.com"
you = "your@email.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.
</p>
</body>
</html>
"""
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
mail = smtplib.SMTP('smtp.gmail.com', 587)
mail.ehlo()
mail.starttls()
mail.login('userName', 'password')
mail.sendmail(me, you, msg.as_string())
mail.quit()
回答 3
这是发送HTML电子邮件的一种简单方法,只需将Content-Type标头指定为“ text / html”即可:
import email.message
import smtplib
msg = email.message.Message()
msg['Subject']='foo'
msg['From']='sender@test.com'
msg['To']='recipient@test.com'
msg.add_header('Content-Type','text/html')
msg.set_payload('Body of <b>message</b>')# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
s.starttls()
s.login(email_login,
email_passwd)
s.sendmail(msg['From'],[msg['To']], msg.as_string())
s.quit()
def createhtmlmail (html, text, subject, fromEmail):"""Create a mime-message that will render HTML in popular
MUAs, text in better ones"""importMimeWriterimport mimetools
import cStringIO
out = cStringIO.StringIO()# output buffer for our message
htmlin = cStringIO.StringIO(html)
txtin = cStringIO.StringIO(text)
writer =MimeWriter.MimeWriter(out)## set up some basic headers... we put subject here# because smtplib.sendmail expects it to be in the# message body#
writer.addheader("From", fromEmail)
writer.addheader("Subject", subject)
writer.addheader("MIME-Version","1.0")## start the multipart section of the message# multipart/alternative seems to work better# on some MUAs than multipart/mixed#
writer.startmultipartbody("alternative")
writer.flushheaders()## the plain text section#
subpart = writer.nextpart()
subpart.addheader("Content-Transfer-Encoding","quoted-printable")
pout = subpart.startbody("text/plain",[("charset",'us-ascii')])
mimetools.encode(txtin, pout,'quoted-printable')
txtin.close()## start the html subpart of the message#
subpart = writer.nextpart()
subpart.addheader("Content-Transfer-Encoding","quoted-printable")## returns us a file-ish object we can write to#
pout = subpart.startbody("text/html",[("charset",'us-ascii')])
mimetools.encode(htmlin, pout,'quoted-printable')
htmlin.close()## Now that we're done, close our writer and# return the message body#
writer.lastpart()
msg = out.getvalue()
out.close()print msg
return msg
if __name__=="__main__":import smtplib
html ='html version'
text ='TEST VERSION'
subject ="BACKUP REPORT"
message = createhtmlmail(html, text, subject,'From Host <sender@host.com>')
server = smtplib.SMTP("smtp_server_address","smtp_port")
server.login('username','password')
server.sendmail('sender@host.com','target@otherhost.com', message)
server.quit()
Here’s sample code. This is inspired from code found on the Python Cookbook site (can’t find the exact link)
def createhtmlmail (html, text, subject, fromEmail):
"""Create a mime-message that will render HTML in popular
MUAs, text in better ones"""
import MimeWriter
import mimetools
import cStringIO
out = cStringIO.StringIO() # output buffer for our message
htmlin = cStringIO.StringIO(html)
txtin = cStringIO.StringIO(text)
writer = MimeWriter.MimeWriter(out)
#
# set up some basic headers... we put subject here
# because smtplib.sendmail expects it to be in the
# message body
#
writer.addheader("From", fromEmail)
writer.addheader("Subject", subject)
writer.addheader("MIME-Version", "1.0")
#
# start the multipart section of the message
# multipart/alternative seems to work better
# on some MUAs than multipart/mixed
#
writer.startmultipartbody("alternative")
writer.flushheaders()
#
# the plain text section
#
subpart = writer.nextpart()
subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
mimetools.encode(txtin, pout, 'quoted-printable')
txtin.close()
#
# start the html subpart of the message
#
subpart = writer.nextpart()
subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
#
# returns us a file-ish object we can write to
#
pout = subpart.startbody("text/html", [("charset", 'us-ascii')])
mimetools.encode(htmlin, pout, 'quoted-printable')
htmlin.close()
#
# Now that we're done, close our writer and
# return the message body
#
writer.lastpart()
msg = out.getvalue()
out.close()
print msg
return msg
if __name__=="__main__":
import smtplib
html = 'html version'
text = 'TEST VERSION'
subject = "BACKUP REPORT"
message = createhtmlmail(html, text, subject, 'From Host <sender@host.com>')
server = smtplib.SMTP("smtp_server_address","smtp_port")
server.login('username', 'password')
server.sendmail('sender@host.com', 'target@otherhost.com', message)
server.quit()
import yagmail
yag = yagmail.SMTP("me@example.com","mypassword")
html_msg ="""<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""
yag.send("to@example.com","the subject", html_msg)
It will by default send HTML, with automatic fallback for incapable email-readers. It is not the 17th century anymore.
Of course, it can be overridden, but here goes:
import yagmail
yag = yagmail.SMTP("me@example.com", "mypassword")
html_msg = """<p>Hi!<br>
How are you?<br>
Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""
yag.send("to@example.com", "the subject", html_msg)
For installation instructions and many more great features, have a look at the github.
Traceback(most recent call last):File"emailSend.py", line 14,in<module>
server.login(username,password)File"/usr/lib/python2.5/smtplib.py", line 554,in login raiseSMTPException("SMTP AUTH extension not supported by server.")
smtplib.SMTPException: SMTP AUTH extension not supported by server.
I am trying to send email (Gmail) using python, but I am getting following error.
Traceback (most recent call last):
File "emailSend.py", line 14, in <module>
server.login(username,password)
File "/usr/lib/python2.5/smtplib.py", line 554, in login
raise SMTPException("SMTP AUTH extension not supported by server.")
smtplib.SMTPException: SMTP AUTH extension not supported by server.
You need to say EHLO before just running straight into STARTTLS:
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
Also you should really create From:, To: and Subject: message headers, separated from the message body by a blank line and use CRLF as EOL markers.
E.g.
msg = "\r\n".join([
"From: user_me@gmail.com",
"To: user_you@gmail.com",
"Subject: Just a message",
"",
"Why, oh why"
])
回答 1
def send_email(user, pwd, recipient, subject, body):import smtplib
FROM = user
TO = recipient if isinstance(recipient, list)else[recipient]
SUBJECT = subject
TEXT = body
# Prepare actual message
message ="""From: %s\nTo: %s\nSubject: %s\n\n%s
"""%(FROM,", ".join(TO), SUBJECT, TEXT)try:
server = smtplib.SMTP("smtp.gmail.com",587)
server.ehlo()
server.starttls()
server.login(user, pwd)
server.sendmail(FROM, TO, message)
server.close()print'successfully sent the mail'except:print"failed to send mail"
如果要使用端口465,则必须创建一个SMTP_SSL对象:
# SMTP_SSL Example
server_ssl = smtplib.SMTP_SSL("smtp.gmail.com",465)
server_ssl.ehlo()# optional, called by login()
server_ssl.login(gmail_user, gmail_pwd)# ssl server doesn't support or need tls, so don't call server_ssl.starttls()
server_ssl.sendmail(FROM, TO, message)#server_ssl.quit()
server_ssl.close()print'successfully sent the mail'
def send_email(user, pwd, recipient, subject, body):
import smtplib
FROM = user
TO = recipient if isinstance(recipient, list) else [recipient]
SUBJECT = subject
TEXT = body
# Prepare actual message
message = """From: %s\nTo: %s\nSubject: %s\n\n%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
try:
server = smtplib.SMTP("smtp.gmail.com", 587)
server.ehlo()
server.starttls()
server.login(user, pwd)
server.sendmail(FROM, TO, message)
server.close()
print 'successfully sent the mail'
except:
print "failed to send mail"
if you want to use Port 465 you have to create an SMTP_SSL object:
# SMTP_SSL Example
server_ssl = smtplib.SMTP_SSL("smtp.gmail.com", 465)
server_ssl.ehlo() # optional, called by login()
server_ssl.login(gmail_user, gmail_pwd)
# ssl server doesn't support or need tls, so don't call server_ssl.starttls()
server_ssl.sendmail(FROM, TO, message)
#server_ssl.quit()
server_ssl.close()
print 'successfully sent the mail'
smtplib.SMTPAuthenticationError:(535,'5.7.8 Username and Password not accepted. Learn more at\n5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257 g66sm2224117qgf.37 - gsmtp')
SMTPAuthenticationError:(534,'5.7.9 Please log in with your web browser and then try again. Learn more at\n5.7.9 https://support.google.com/mail/bin/answer.py?answer=78754 qo11sm4014232igb.17 - gsmtp')
I ran into a similar problem and stumbled on this question. I got an SMTP Authentication Error but my user name / pass was correct. Here is what fixed it. I read this:
In a nutshell, google is not allowing you to log in via smtplib because it has flagged this sort of login as “less secure”, so what you have to do is go to this link while you’re logged in to your google account, and allow the access:
smtplib.SMTPAuthenticationError: (535, '5.7.8 Username and Password not accepted. Learn more at\n5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257 g66sm2224117qgf.37 - gsmtp')
Still not working? If you still get the SMTPAuthenticationError but now the code is 534, its because the location is unknown. Follow this link:
SMTPAuthenticationError: (534, '5.7.9 Please log in with your web browser and then try again. Learn more at\n5.7.9 https://support.google.com/mail/bin/answer.py?answer=78754 qo11sm4014232igb.17 - gsmtp')
After enabling ‘lesssecureapps’, go for a coffee, come back, and try the ‘DisplayUnlockCaptcha’ link again. From user experience, it may take up to an hour for the change to kick in. Then try the sign-in process again.
#!/usr/bin/env python3# -*- coding: utf-8 -*-# =============================================================================# Created By : Jeromie Kirchoff# Created Date: Mon Aug 02 17:46:00 PDT 2018# =============================================================================# Imports# =============================================================================import smtplib
# =============================================================================# SET EMAIL LOGIN REQUIREMENTS# =============================================================================
gmail_user ='THEFROM@gmail.com'
gmail_app_password ='YOUR-GOOGLE-APPLICATION-PASSWORD!!!!'# =============================================================================# SET THE INFO ABOUT THE SAID EMAIL# =============================================================================
sent_from = gmail_user
sent_to =['THE-TO@gmail.com','THE-TO@gmail.com']
sent_subject ="Where are all my Robot Women at?"
sent_body =("Hey, what's up? friend!\n\n""I hope you have been well!\n""\n""Cheers,\n""Jay\n")
email_text ="""\
From: %s
To: %s
Subject: %s
%s
"""%(sent_from,", ".join(sent_to), sent_subject, sent_body)# =============================================================================# SEND EMAIL OR DIE TRYING!!!# Details: http://www.samlogic.net/articles/smtp-commands-reference.htm# =============================================================================try:
server = smtplib.SMTP_SSL('smtp.gmail.com',465)
server.ehlo()
server.login(gmail_user, gmail_app_password)
server.sendmail(sent_from, sent_to, email_text)
server.close()print('Email sent!')exceptExceptionas exception:print("Error: %s!\n\n"% exception)
This setting is not available for accounts with 2-Step Verification enabled. Such accounts require an application-specific password for less secure apps access.
Not directly related but still worth pointing out is that my package tries to make sending gmail messages really quick and painless. It also tries to maintain a list of errors and tries to point to the solution immediately.
It would literally only need this code to do exactly what you wrote:
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow importInstalledAppFlowfrom google.auth.transport.requests importRequestfrom email.mime.text importMIMETextimport base64
#pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib# If modifying these scopes, delete the file token.pickle.
SCOPES =['https://www.googleapis.com/auth/gmail.readonly','https://www.googleapis.com/auth/gmail.send']def create_message(sender, to, subject, msg):
message =MIMEText(msg)
message['to']= to
message['from']= sender
message['subject']= subject
# Base 64 encode
b64_bytes = base64.urlsafe_b64encode(message.as_bytes())
b64_string = b64_bytes.decode()return{'raw': b64_string}#return {'raw': base64.urlsafe_b64encode(message.as_string())}def send_message(service, user_id, message):#try:
message =(service.users().messages().send(userId=user_id, body=message).execute())print('Message Id: %s'% message['id'])return message
#except errors.HttpError, error:print( 'An error occurred: %s' % error )def main():"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds =None# The file token.pickle stores the user's access and refresh tokens, and is# created automatically when the authorization flow completes for the first# time.if os.path.exists('token.pickle'):with open('token.pickle','rb')as token:
creds = pickle.load(token)# If there are no (valid) credentials available, let the user log in.ifnot creds ornot creds.valid:if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())else:
flow =InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
creds = flow.run_local_server(port=0)# Save the credentials for the next runwith open('token.pickle','wb')as token:
pickle.dump(creds, token)
service = build('gmail','v1', credentials=creds)# Example read operation
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels',[])ifnot labels:print('No labels found.')else:print('Labels:')for label in labels:print(label['name'])# Example write
msg = create_message("from@gmail.com","to@gmail.com","Subject","Msg")
send_message( service,'me', msg)if __name__ =='__main__':
main()
You’ll need create a project with Google’s API interfaces through their website. Next you’ll need to enable the GMAIL API for your app. Create credentials and then download those creds, save it as credentials.json.
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from email.mime.text import MIMEText
import base64
#pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly', 'https://www.googleapis.com/auth/gmail.send']
def create_message(sender, to, subject, msg):
message = MIMEText(msg)
message['to'] = to
message['from'] = sender
message['subject'] = subject
# Base 64 encode
b64_bytes = base64.urlsafe_b64encode(message.as_bytes())
b64_string = b64_bytes.decode()
return {'raw': b64_string}
#return {'raw': base64.urlsafe_b64encode(message.as_string())}
def send_message(service, user_id, message):
#try:
message = (service.users().messages().send(userId=user_id, body=message).execute())
print( 'Message Id: %s' % message['id'] )
return message
#except errors.HttpError, error:print( 'An error occurred: %s' % error )
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
# Example read operation
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
else:
print('Labels:')
for label in labels:
print(label['name'])
# Example write
msg = create_message("from@gmail.com", "to@gmail.com", "Subject", "Msg")
send_message( service, 'me', msg)
if __name__ == '__main__':
main()
There is a gmail API now, which lets you send email, read email and create drafts via REST.
Unlike the SMTP calls, it is non-blocking which can be a good thing for thread-based webservers sending email in the request thread (like python webservers). The API is also quite powerful.
Of course, email should be handed off to a non-webserver queue, but it’s nice to have options.
It’s easiest to setup if you have Google Apps administrator rights on the domain, because then you can give blanket permission to your client. Otherwise you have to fiddle with OAuth authentication and permission.
def send_email(user, password, recipient, subject, body):
gmail_user = user
gmail_pwd = password
FROM = user
TO = recipient if type(recipient)is list else[recipient]
SUBJECT = subject
TEXT = body
# Prepare actual message
message ="""From: %s\nTo: %s\nSubject: %s\n\n%s
"""%(FROM,", ".join(TO), SUBJECT, TEXT)
server = smtplib.SMTP("smtp.gmail.com",587)
server.ehlo()
server.starttls()
server.login(gmail_user, gmail_pwd)
server.sendmail(FROM, TO, message)
server.close()
great answer from @David, here is for Python 3 without the generic try-except:
def send_email(user, password, recipient, subject, body):
gmail_user = user
gmail_pwd = password
FROM = user
TO = recipient if type(recipient) is list else [recipient]
SUBJECT = subject
TEXT = body
# Prepare actual message
message = """From: %s\nTo: %s\nSubject: %s\n\n%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
server = smtplib.SMTP("smtp.gmail.com", 587)
server.ehlo()
server.starttls()
server.login(gmail_user, gmail_pwd)
server.sendmail(FROM, TO, message)
server.close()
Seems like problem of the old smtplib. In python2.7 everything works fine.
Update: Yep, server.ehlo() also could help.
回答 12
import smtplib
fromadd='from@gmail.com'
toadd='send@gmail.com'
msg='''hi,how r u'''
username='abc@gmail.com'
passwd='password'try:
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.login(username,passwd)
server.sendmail(fromadd,toadd,msg)print("Mail Send Successfully")
server.quit()except:print("Error:unable to send mail")
NOTE:https://www.google.com/settings/security/lesssecureapps that should be enabled