how to send email attachement using python 2.7 - python

I am getting error when using this code to send email using localhost ip, any suggestion how to solve the socket error?
def SendTMail(self):
# Import the email modules we'll need
# Open a plain text file for reading. For this example, assume that
# the text file contains only ASCII characters.
#try:
fp = open('testint.txt', 'rb')
# Create a text/plain message
msg = MIMEText(fp.read())
testfile = 'TESTING REPORT'
fp.close()
me = '124#hotmail.co.uk'
you = '123#live.com'
msg['Subject'] = 'The contents of %s' % testfile
msg['From'] = me
msg['To'] = you
# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('192.168.1.3')
s.sendmail(me, [you], msg.as_string())
s.quit()
the error is shown below:
File "x:\example.py", line 6, in SendTMail s = smtplib.SMTP('192.168.1.3')
File "x:\Python27\lib\smtplib.py", line 251, in init (code, msg) = self.connect(host, port)
File "x:\Python27\lib\smtplib.py", line 311, in connect self.sock = self._get_socket(host, port, self.timeout)
File "x:\Python27\lib\smtplib.py", line 286, in _get_socket return socket.create_connection((host, port), timeout)
File "x:\Python27\lib\socket.py", line 571, in create_connection raise err –
error: [Errno 10051] A socket operation was attempted to an unreachable network

Before posting raw code, I'd like to add an small explanation as per the conversation that took place in the comments to your question.
smtplib connects to an existing SMTP server. You can see it more like an Outlook Express. Outlook is a client (or a Mail User Agent, if you wanna get fancy). It doesn't send emails by itself. It connects to whatever SMTP server it has configured among its accounts and tells that server "Hey, I'm user xxx#hotmail.com (and here's my password to prove it). Could you send this for me?"
If you wanted to, having your own SMTP server is doable (for instance, in Linux, an easily configurable SMTP server would be Postfix, and I'm sure there are many for Windows) Once you set one up, it'll start listening for incoming connections in its port 25 (usually) and, if whatever bytes come through that port follow the SMTP protocol, it'll send it to its destination. IMHO, this isn't such a great idea (nowadays). The reason is that now, every (decent) email provider will consider emails coming from unverified SMTP servers as spam. If you want to send emails, is much better relying in a well known SMTP server (such as the one at smtp.live.com, the ones hotmail uses), authenticate against it with your username and password, and send your email relying (as in SMTP Relay) on it.
So this said, here's some code that sends an HTML text with an attachment borrajax.jpeg to an email account relying on smtp.live.com.
You'll need to edit the code below to set your hotmail's password (maybe your hotmail's username as well, if it's not 124#hotmail.co.uk as shown in your question) and email recipients. I removed mines from the code after my tests for obvious security reasons... for me :-D and I put back the ones I saw in your question. Also, this scripts assumes it'll find a .jpeg picture called borrajax.jpeg in the same directory where the Python script is being run:
import smtplib
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
def send_mail():
test_str="This is a test"
me="124#hotmail.co.uk"
me_password="XXX" # Put YOUR hotmail password here
you="123#live.com"
msg = MIMEMultipart()
msg['Subject'] = test_str
msg['From'] = me
msg['To'] = you
msg.preamble = test_str
msg_txt = ("<html>"
"<head></head>"
"<body>"
"<h1>Yey!!</h1>"
"<p>%s</p>"
"</body>"
"</html>" % test_str)
msg.attach(MIMEText(msg_txt, 'html'))
with open("borrajax.jpeg") as f:
msg.attach(MIMEImage(f.read()))
smtp_conn = smtplib.SMTP("smtp.live.com", timeout=10)
print "connection stablished"
smtp_conn.starttls()
smtp_conn.ehlo_or_helo_if_needed()
smtp_conn.login(me, me_password)
smtp_conn.sendmail(me, you, msg.as_string())
smtp_conn.quit()
if __name__ == "__main__":
send_mail()
When I run the example (as I said, I edited the recipient and the sender) it sent an email to a Gmail account using my (old) hotmail account. This is what I received in my Gmail:
There's a lot of stuff you can do with the email Python module. Have fun!!
EDIT:
Gorramit!! Your comment about attaching a text file wouldn't let me relax!! :-D I had to see it myself. Following what was detailed in this question, I added some code to add a text file as an attachment.
msg_txt = ("<html>"
"<head></head>"
"<body>"
"<h1>Yey!!</h1>"
"<p>%s</p>"
"</body>"
"</html>" % test_str)
msg.attach(MIMEText(msg_txt, 'html'))
with open("borrajax.jpeg", "r") as f:
msg.attach(MIMEImage(f.read()))
#
# Start new stuff
#
with open("foo.txt", "r") as f:
txt_attachment = MIMEText(f.read())
txt_attachment.add_header('Content-Disposition',
'attachment',
filename=f.name)
msg.attach(txt_attachment)
#
# End new stuff
#
smtp_conn = smtplib.SMTP("smtp.live.com", timeout=10)
print "connection stablished"
And yep, it works... I have a foo.txt file in the same directory where the script is run and it sends it properly as an attachment.

Related

send email using SMTP SSL/Port 465

I need to send email using SMTP SSL/Port 465 with my bluehost email.I can't find working code in google i try more than 5 codes. So, please any have working code for sending email using SMTP SSL/port 465 ?
Jut to clarify the solution from dave here is how i got mine to work with my SSL server (i'm not using gmail but still same). Mine emails if a specific file is not there (for internal purposes, that is a bad thing)
import smtplib
import os.path
from email.mime.text import MIMEText
if (os.path.isfile("filename")):
print "file exists, all went well"
else:
print "file not exists, emailing"
msg = MIMEText("WARNING, FILE DOES NOT EXISTS, THAT MEANS UPDATES MAY DID NOT HAVE BEEN RUN")
msg['Subject'] = "WARNING WARNING ON FIRE FIRE FIRE!"
#put your host and port here
s = smtplib.SMTP_SSL('host:port')
s.login('email','serverpassword')
s.sendmail('from','to', msg.as_string())
s.quit()
print "done"
For SSL port 465, you need to use SMTP_SSL, rather than just SMTP.
See here for more info.
https://docs.python.org/2/library/smtplib.html
You should never post a question like this. Please let us know what you have done, any tries? Any written code etc.
Anyways I hope this helps
import smtplib
fromaddr = 'uremail#gmail.com'
toaddrs = 'toaddress#ymail.com'
msg = "I was bored!"
# Credentials
password = 'password'
# The actual mail send
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(fromaddr,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
print "done"

Send anonymous mail from local machine

I was using Python for sending an email using an external SMTP server. In the code below, I tried using smtp.gmail.com to send an email from a gmail id to some other id. I was able to produce the output with the code below.
import smtplib
from email.MIMEText import MIMEText
import socket
socket.setdefaulttimeout(None)
HOST = "smtp.gmail.com"
PORT = "587"
sender= "somemail#gmail.com"
password = "pass"
receiver= "receiver#somedomain.com"
msg = MIMEText("Hello World")
msg['Subject'] = 'Subject - Hello World'
msg['From'] = sender
msg['To'] = receiver
server = smtplib.SMTP()
server.connect(HOST, PORT)
server.starttls()
server.login(sender,password)
server.sendmail(sender,receiver, msg.as_string())
server.close()
But I have to do the same without the help of an external SMTP server. How can do the same with Python?
Please help.
The best way to achieve this is understand the Fake SMTP code it uses the great smtpd module.
#!/usr/bin/env python
"""A noddy fake smtp server."""
import smtpd
import asyncore
class FakeSMTPServer(smtpd.SMTPServer):
"""A Fake smtp server"""
def __init__(*args, **kwargs):
print "Running fake smtp server on port 25"
smtpd.SMTPServer.__init__(*args, **kwargs)
def process_message(*args, **kwargs):
pass
if __name__ == "__main__":
smtp_server = FakeSMTPServer(('localhost', 25), None)
try:
asyncore.loop()
except KeyboardInterrupt:
smtp_server.close()
To use this, save the above as fake_stmp.py and:
chmod +x fake_smtp.py
sudo ./fake_smtp.py
If you really want to go into more details, then I suggest that you understand the source code of that module.
If that doesn't work try the smtplib:
import smtplib
SERVER = "localhost"
FROM = "sender#example.com"
TO = ["user#example.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(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
Most likely, you may already have an SMTP server running on the host that you are working on. If you do ls -l /usr/sbin/sendmail does it show that an executable file (or symlink to another file) exists at this location? If so, then you may be able to use this to send outgoing mail. Try /usr/sbin/sendmail recipient#recipientdomain.com < /path/to/file.txt to send the message contained in /path/to/file.txt to recipient#recipientdomain.com (/path/to/file.txt should be an RFC-compliant email message). If that works, then you can use /usr/sbin/sendmail to send mail from your python script - either by opening a handle to /usr/sbin/sendmail and writing the message to it, or simply by executing the above command from your python script by way of a system call.

Trying to send an email with python [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Send email with python
I'm trying so send an email with python but when I run the script it take a minute or two then I get this error:
Traceback (most recent call last):
File "./emailer", line 19, in <module>
server = smtplib.SMTP(SERVER)
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/smtplib.py", line 239, in __init__
(code, msg) = self.connect(host, port)
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/smtplib.py", line 295, in connect
self.sock = self._get_socket(host, port, self.timeout)
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/smtplib.py", line 273, in _get_socket
return socket.create_connection((port, host), timeout)
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/socket.py", line 512, in create_connection
raise error, msg
socket.error: [Errno 60] Operation timed out
This is the script:
#!/usr/bin/env python
import smtplib
SERVER = 'addisonbean.com'
FROM = 'myemail#gmail.com'
TO = ['myemail#gmail.com']
SUBJECT = 'Hello!'
message = """\
Bla
Bla Bla
Bla Bla Bla
Bla Bla Bla Bla
"""
server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
I also tried my site IP address as the server but that did the same thing.
Could someone tell me why it does this and how to fix this? Thanks!
Here's the key bit:
return socket.create_connection((port, host), timeout)
socket.error: [Errno 60] Operation timed out
Python's saying: I can't connect to that server, I've tried but it doesn't seem to respond.
Here's the second key bit:
SERVER = 'addisonbean.com'
That's not a mail server, is it?
While addisonbean.com does listen 25 port and answers 220 accra.dreamhost.com ESMTP - you seems to be behind proxy or some kind of firewall. Can you do telnet addisonbean.com 25 from your console?
It looks like you're hosting your page in dreamhost.com, a hosting provider.
When you set up your account, they probably gave you the chance to create email accounts ending with your domain (yaddayadda#addisonbean.com)
You may want to create one, get the information: host where the SMTP (the "mail server") is located, username, password... And you'll have to fill all that in your script.
I would recommend you start testing with another regular account (Gmail.com, Hotmail Outlook.com) and that you read (quite a bit) about what an SMTP server is (which is the server you'll have to talk to in order to have your email sent)
Here's a simple script that should send emails using a gmail account. Fill the information that is shown with asterisks with your data, see if it works:
#!/usr/bin/env python
import traceback
from smtplib import SMTP
from email.MIMEText import MIMEText
smtpHost = "smtp.gmail.com"
smtpPort = 587
smtpUsername = "***#gmail.com"
smtpPassword = "***"
sender = "***#gmail.com"
def sendEmail(to, subject, content):
retval = 1
if not(hasattr(to, "__iter__")):
to = [to]
destination = to
text_subtype = 'plain'
try:
msg = MIMEText(content, text_subtype)
msg['Subject'] = subject
msg['From'] = sender # some SMTP servers will do this automatically, not all
conn = SMTP(host=smtpHost, port=smtpPort)
conn.set_debuglevel(True)
#conn.login(smtpUsername, smtpPassword)
try:
if smtpUsername is not False:
conn.ehlo()
if smtpPort != 25:
conn.starttls()
conn.ehlo()
if smtpUsername and smtpPassword:
conn.login(smtpUsername, smtpPassword)
else:
print("::sendEmail > Skipping authentication information because smtpUsername: %s, smtpPassword: %s" % (smtpUsername, smtpPassword))
conn.sendmail(sender, destination, msg.as_string())
retval = 0
except Exception, e:
print("::sendEmail > Got %s %s. Showing traceback:\n%s" % (type(e), e, traceback.format_exc()))
retval = 1
finally:
conn.close()
except Exception, e:
print("::sendEmail > Got %s %s. Showing traceback:\n%s" % (type(e), e, traceback.format_exc()))
retval = 1
return retval
if __name__ == "__main__":
sendEmail("***#gmail.com", "Subject: Test", "This is a simple test")
Once you have the equivalent information for your domain (smtpHost, smtpPort, smtpUsername...) it MAY work as well (depends on the port they're using, it may be 25, which is the default for non-encrypted connections... or not... You'll have to check with dreamhost.com for that)
Be aware that (since you're using a hosting that probably shares its SMTP server with other people) your "sender" may be yaddayadda#addisonbean.com but the actual information to connect to the dreamhost.com SMTP servers may be different: I'm guessing the 'smtpUsername' may be the username you use to login in your site admin, the 'smtpHost' may change to something like smtp.dreamhost.com or such... That I don't really know.
You have a lot of resources on how to do that.
You also seem to be a designer or photographer... One of those dudes people concern on how things look on the screen and all... Then you may wanna investigate what MiME emails are. You know... so the email is not sent with text only, but you can put fancy HTML in it... You know what I'm sayin'?

How to forward email using Python

First, let me say, I already know that this was asked at Forwarding an email with python smtplib already.
The reason that I am posting something so closely related to that question is that I have tried using the answers to that question, I have tried changing things, I have searched Google and relentlessly monkeyed with this for about 5 hours now, and I am willing to spend a lot more time on this
-- I just thought one of you might have the answer though :)
My problem is as follows, I am trying to forward an email from my gmail to another gmail, and in running as many python script as I can to try this simple task, I still cannot figure it out.
Here is the code that I am running(this is my modified version of what was posted in the other form):
import smtplib, imaplib, email, string
imap_host = "imap.gmail.com"
imap_port = 993
smtp_host = "smtp.gmail.com"
smtp_port = 587
user = "John.Michael.Dorian.4"
passwd = "mypassword"
msgid = 1
from_addr = "John.Michael.Dorian.4#gmail.com"
to_addr = "myotheremail#gmail.com"
# open IMAP connection and fetch message with id msgid
# store message data in email_data
client = imaplib.IMAP4_SSL(imap_host, imap_port)
client.login(user, passwd)
client.select()
typ, data = client.search(None, 'ALL')
for mail in data[0].split():
typ, data = client.fetch(msgid, "(RFC822)")
email_data = data[0][1]
client.close()
client.logout()
# create a Message instance from the email data
message = email.message_from_string(email_data)
# replace headers (could do other processing here)
message.replace_header("From", from_addr)
message.replace_header("To", to_addr)
print message.as_string()
# open authenticated SMTP connection and send message with
# specified envelope from and to addresses
smtp = smtplib.SMTP(smtp_host, smtp_port)
smtp.set_debuglevel(1)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(user, passwd)
smtp.sendmail(from_addr, to_addr, message.as_string())
smtp.quit()
The return from the SMTP debug says everything went okay, and I know that it is sending because I tried replacing the
smtp.sendmail(from_addr, to_addr, message.as_string())
With
smtp.sendmail(from_addr, to_addr, 'test')
And it worked fine. It prints the message.as_string() fine, and I am at a loss as how to get it to forward the email!
It doesn't have to be with SMTP or IMAP or any of this code(though it would be nice if it was) but I would really like to figure out how to do this.
I know its possible because I managed to do it yesterday, and the computer I was working on(running Windows of course) crashed and the file was gone.
For those of you who are wondering why I do not just set google to forward everything automatically, it is because I want a script that will eventually move a large amount of mail, once.
Thank you everyone!
More than likely, the Received: headers of the original email are causing gmail to drop the message. Try removing all of them before forwarding it.
If that doesn't fix it, print out the headers and code it to remove all of the ones that would not normally be there on a newly composed message.
However, why forward this way? It would be easier to just pull from one IMAP account and push it to another IMAP account directly.
In fact you could use Mozilla Thunderbird to add both accounts and just drag and drop the messages from one to the other.

How to send an email with Python?

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?
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.
When I need to mail in Python, I use the mailgun API which gets a lot of the headaches with sending mails sorted out. They have a wonderful 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'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.
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
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()
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).
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)
It's probably putting tabs into your message. Print out message before you pass it to sendMail.
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)
I haven't been satisfied with the package options for sending emails and I decided to make and open source my own email sender. It is easy to use and capable of advanced use cases.
To install:
pip install redmail
Usage:
from redmail import EmailSender
email = EmailSender(
host="<SMTP HOST ADDRESS>",
port=<PORT NUMBER>,
)
email.send(
sender="me#example.com",
receivers=["you#example.com"],
subject="An example email",
text="Hi, this is text body.",
html="<h1>Hi,</h1><p>this is HTML body</p>"
)
If your server requires a user and a password, just pass user_name and password to the EmailSender.
I have included a lot of features wrapped in the send method:
Include attachments
Include images directly to the HTML body
Jinja templating
Prettier HTML tables out of the box
Documentation:
https://red-mail.readthedocs.io/en/latest/
Source code: https://github.com/Miksus/red-mail
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()
Another implementation using gmail let's say:
import smtplib
def send_email(email_address: str, subject: str, body: str):
"""
send_email sends an email to the email address specified in the
argument.
Parameters
----------
email_address: email address of the recipient
subject: subject of the email
body: body of the email
"""
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("email_address", "password")
server.sendmail("email_address", email_address,
"Subject: {}\n\n{}".format(subject, body))
server.quit()
I wrote a simple function send_email() for email sending with smtplib and email packages (link to my article). It additionally uses dotenv package to loads the sender email and password (please don't keep secrets in the code!). I was using Gmail for email service. The password was the App Password (here is Google docs on how to generate App Password).
import os
import smtplib
from email.message import EmailMessage
from dotenv import load_dotenv
_ = load_dotenv()
def send_email(to, subject, message):
try:
email_address = os.environ.get("EMAIL_ADDRESS")
email_password = os.environ.get("EMAIL_PASSWORD")
if email_address is None or email_password is None:
# no email address or password
# something is not configured properly
print("Did you set email address and password correctly?")
return False
# create email
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = email_address
msg['To'] = to
msg.set_content(message)
# send email
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
smtp.login(email_address, email_password)
smtp.send_message(msg)
return True
except Exception as e:
print("Problem during send email")
print(str(e))
return False
The above approach is OK for simple email sending. If you are looking for more advanced features, such as HTML content or attachments - it, of course, can be hand-coded, but I would recommend using existing packages, for example yagmail.
Gmail has a limit of 500 emails per day. For sending many emails per day please consider transactional email service providers, like Amazon SES, MailGun, MailJet, or SendGrid.
import smtplib
s = smtplib.SMTP(your smtp server, smtp port) #SMTP session
message = "Hii!!!"
s.sendmail("sender", "Receiver", message) # sending the mail
s.quit() # terminating the session
just to complement the answer and so that your mail delivery system can be scalable.
I recommend having a configuration file (it can be .json, .yml, .ini, etc) with the sender's email configuration , password and recipients.
This way you can create different customizable items according to your needs.
Below is a small example with 3 files, config, functions and main. Text-only mailing.
config_email.ini
[email_1]
sender = test#test.com
password = XXXXXXXXXXX
recipients= ["email_2#test.com", "email_2#test.com"]
[email_2]
sender = test_2#test.com
password = XXXXXXXXXXX
recipients= ["email_2#test.com", "email_2#test.com", "email_3#test.com"]
These items will be called from main.py, which will return their respective values.
File with functions functions_email.py:
import smtplib,configparser,json
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def get_credentials(item):
parse = configparser.ConfigParser()
parse.read('config_email.ini')
sender = parse[item]['sender ']
password = parse[item]['password']
recipients= json.loads(parse[item]['recipients'])
return sender,password,recipients
def get_msg(sender,recipients,subject,mail_body):
msg = MIMEMultipart()
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = ', '.join(recipients)
text = """\
"""+mail_body+""" """
part1 = MIMEText(text, "plain")
msg.attach(part1)
return msg
def send_email(msg,sender,password,recipients):
s = smtplib.SMTP('smtp.test.com')
s.login(sender,password)
s.sendmail(sender, recipients, msg.as_string())
s.quit()
File main.py:
from functions_email import *
sender,password,recipients = get_credenciales('email_2')
subject= 'text to subject'
mail_body = 'body....................'
msg = get_msg(sender,recipients ,subject,mail_body)
send_email(msg,sender,password,recipients)
Best regards!
import smtplib, ssl
port = 587 # For starttls
smtp_server = "smtp.office365.com"
sender_email = "170111018#student.mit.edu.tr"
receiver_email = "professordave#hotmail.com"
password = "12345678"
message = """\
Subject: Final exam
Teacher when is the final exam?"""
def SendMailf():
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, port) as server:
server.ehlo() # Can be omitted
server.starttls(context=context)
server.ehlo() # Can be omitted
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
print("mail send")
After a lot of fiddling with the examples e.g here
this now works for me:
import smtplib
from email.mime.text import MIMEText
# SMTP sendmail server mail relay
host = 'mail.server.com'
port = 587 # starttls not SSL 465 e.g gmail, port 25 blocked by most ISPs & AWS
sender_email = 'name#server.com'
recipient_email = 'name#domain.com'
password = 'YourSMTPServerAuthenticationPass'
subject = "Server - "
body = "Message from server"
def sendemail(host, port, sender_email, recipient_email, password, subject, body):
try:
p1 = f'<p><HR><BR>{recipient_email}<BR>'
p2 = f'<h2><font color="green">{subject}</font></h2>'
p3 = f'<p>{body}'
p4 = f'<p>Kind Regards,<BR><BR>{sender_email}<BR><HR>'
message = MIMEText((p1+p2+p3+p4), 'html')
# servers may not accept non RFC 5321 / RFC 5322 / compliant TXT & HTML typos
message['From'] = f'Sender Name <{sender_email}>'
message['To'] = f'Receiver Name <{recipient_email}>'
message['Cc'] = f'Receiver2 Name <>'
message['Subject'] = f'{subject}'
msg = message.as_string()
server = smtplib.SMTP(host, port)
print("Connection Status: Connected")
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.ehlo()
server.login(sender_email, password)
print("Connection Status: Logged in")
server.sendmail(sender_email, recipient_email, msg)
print("Status: Email as HTML successfully sent")
except Exception as e:
print(e)
print("Error: unable to send email")
# Run
sendemail(host, port, sender_email, recipient_email, password, subject, body)
print("Status: Exit")
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).

Categories