I am trying to send an email including an attachment via Python from my Raspberry Pi.
The following code (email.py) works when I'm using sudo python3 email.py but does not via sudo python email.py.
######WRITE EMAIL AND SEND
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import locale
locale.setlocale(locale.LC_TIME, "de_DE")
attachment = 0
fromaddr = 'MAIL#gmail.com'
toaddr = ['MAIL#gmail.com']
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = ", ".join(toaddr)
msg['Subject'] = 'ÄÖÜäöü'
body = 'Ääüäöü'
msg.attach(MIMEText(body, 'plain',_charset='latin-1'))
filename = 'Picture'
for file in os.listdir('/path/to/Pictures/'):
if file.__contains__('.png'):
a_file=file
attachment = open('/path/to/pi/Pictures/'+a_file, 'rb')
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename= %s' % filename)
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, 'Password')
text = msg.as_string()
print ('# Sending mail')
server.sendmail(fromaddr, toaddr, text)
server.quit()
print('# Mail Sent')
The Error I am getting when using the python method is:
SyntaxError: Non ASCII character \xc3 in file email.py on line XX but no encoding declared; see htttp://python.org/dev/peps/pep-0263/ for details.
The Umlaute ÄÖÜ... are causing the problem.
I know that different python versions use different encodings as default and I python3 uses utf-8.
Somehow with python email.pyanother encoding is used and I don't know how to change it.
I would like to know where I'd have to add specific encoding instructions into the code so that the code works on both python versions.
Python2 uses ASCII as default encoding. However, you can define the encoding to be used.
Add the following line to your script in order to hint your python to use a utf-8 encoding.
#coding=utf-8
You are not getting any error in case python3 because it uses utf-8 as default encoding.
Related
I want to send an email with attachment (for example a text file) with python. Is this possible with the stdlib or do I have to download and install other packages?
I would like to do this with the stdlib.
thx. :)
You can try this:
# 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.
fp = open(textfile, 'rb')
# Create a text/plain message
msg = MIMEText(fp.read())
fp.close()
# 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.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
I found this code from another website repository and its used to send emails using python and attach's a file as well. It encodes the file in to base64 brfore sending it. I've tested the code before using an '.xlsx' file and it was sent with out a problem. But now the program doesnt send it for some reason. The file is in the same folder as the code.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "FROM EMAIL"
toaddr = "TO EMAIL"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "SUBJECT"
body = "MESSAGE"
msg.attach(MIMEText(body, 'plain'))
filename = "05-11-2016 - Saturday.xlsx"
attachment = open("05-11-2016 - Saturday", "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "PASSWORD")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
When i run it ths is the error that is outputted:
line 21, in <module>
attachment = open("05-11-2016 - Saturday", "rb")
FileNotFoundError: [Errno 2] No such file or directory: '05-11-2016 - Saturday'
Any help would be appreciated.
you have defined filename in the line above - so why don't you use it? :)
(you forgot the extension 'xlsx' in the open statement)
You now have learned the usefullnes of the DRY-principle:
http://wiki.c2.com/?DontRepeatYourself
By typing it twice, you can change the filename definition and not notice, that the open uses another file...
I just ran your code using my credentials and made a small txt file in the same directory as the code to replicate your conditions. Here's what you need to modify:
filename = "ExplicitFileName.txt"
attachment = open("/USE/COMPLETE/PATH/TO/FILE/ExplicitFileName.txt", "rb")
Or as Ilja pointed out the DRY principle you could do it like this:
filename = "ExplicitFileName.txt"
attachment = open("/COMPLETE/PATH/TO/FILE/" + filename, "rb")
Both of these will work just fine.
I've just started learning Python and I'm trying to code a bot where it emails a HTML message along with a .docx (Microsoft Word) attachment. Here's my code and it works fine, but I'm confused with a few of the parameters.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import os
#Email Variables
myemail = "myemail#hotmail.com"
recipient = "recipientemail#hotmail.com"
#Specifying MIME variables to include in email header
mime_details = MIMEMultipart('mixed')
mime_details['Subject'] = "This is my email subject!"
mime_details['From'] = myemail
mime_details['To'] = recipient
#Creating body of message
html_body = """\
<html>\
<p>\
My email message!
</p>\
</html>\
"""
#Attaching File To Email
os.chdir('C:\\Users\Kyle\Desktop\')
openfile = open('testfile.docx', 'rb')
doc = MIMEApplication(openfile.read(), _subtype='vnd.openxmlformats-officedocument.wordprocessingml.document')
doc.add_header('Content-Disposition', 'attachment', filename='My Content.docx')
mime_details.attach(doc)
openfile.close()
#Recording MIME types of email parts
htmlpart = MIMEText(html_body, _subtype='html')
#Attaching parts to message container
mime_details.attach(htmlpart)
#Sending message via SMTP server
s = smtplib.SMTP(host='smtp.live.com', port=587)
s.ehlo()
s.starttls()
s.login(myemail, 'password')
s.sendmail(myemail, recipient, mime_details.as_string())
s.quit()
I have a few questions regarding the code above, and I would greatly appreciate it if you can help me clear whatever confused thoughts I have regarding the modules above.
A) The add_header module
mime_details['Subject'] = "This is my email subject!"
mime_details['From'] = myemail
mime_details['To'] = recipient
As you can see from the snippet above, I clearly defined each header variable in the MIMEMultipart envelope. According to Python's docs, these values will be added to the header directly. I tried using the add_header() method directly as an alternative, something like:
mime_details.add_header(Subject = "This is my email subject!", To = recipient, From = myemail)
But it gave me errors. Any idea why?
B) At the last few lines of my code, I had to append a .as_string() to the payload I was sending. I tried taking it out but it gave me a TypeError: expected string or buffer.
The Python docs give me this:
as_string(unixfrom=False, maxheaderlen=0, policy=None)
Return the entire message flattened as a string.
I assume that I have to append this in every case? the mime_details object has two parts to it - the HTML message and the .docx file. Both will be converted to strings? What about image files?
C) When I open my file to attach, I read it in 'rb' mode.
Here's the code:
openfile = open('testfile.docx', 'rb')
I tried using 'r' but it raises an error. I've read up on this and 'rb' mode simply opens the file in binary. Why would it make sense to open a .docx file in binary mode? Am I to use 'rb' mode for ALL non.txt files?
D) Finally, I've seen some people use base64 encoding for attachments. I've searched around and a particularly popular script over here is below (from How to send email attachments with Python):
import smtplib, os
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, text, files=[], server="localhost", port=587, username='', password='', isTls=True):
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:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="{0}"'.format(os.path.basename(f)))
msg.attach(part)
smtp = smtplib.SMTP(server, port)
if isTls: smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.quit()
Why does content need to be encoded in base64? Does this apply to all files and is a general thing to be added, or can I ignore this? What situations am I to invoke that method?
Finally, being a noob at Python, some of my code above may be redundant\badly structured. If you have any tips\suggestions on how I can improve my simply script, please do let me know.
Thank you!
Edit question for new issue
I was able to get Email But it was delay from server side.**
I am writing very small application for sending email with attachment of excel file in python. it contain multiple worksheet and each worksheet contain graph. I received email but it looks like File was corrupted.
is it possible to attach Excel which contain graph( size also upto 2MB)
# -*- coding: iso-8859-1 -*-
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from smtplib import SMTP
import smtplib,email,email.encoders,email.mime.text,email.mime.base
msg = MIMEMultipart()
msg['Subject'] = 'Email From Python Abhishek'
msg['From'] = 'xyz.com'
msg['To'] = 'abc.com'
fileMsg = email.mime.base.MIMEBase('application','vnd.ms-excel')
fileMsg.set_payload(file('Final.xlsx').read())
email.encoders.encode_base64(fileMsg)
fileMsg.add_header('Content-Disposition','attachment;filename=Final.xlsx')
msg.attach(fileMsg)
smtp = SMTP("email exchange server",25)
#(I was able to connect with exchange server using Telnet http://www.exchangeinbox.com/article.aspx?i=93)
# Start the server:
smtp.ehlo()
I have commented below code as per one internet posting. it suggest that if you
are sending internal Email you may not require login and password.I also do not
want to write password as it is violate company policy
if I remove comment from line. it give me error for bad authentication.
#smtp.login("abc", "password")
smtp.sendmail(msg['From'],msg['To'],msg.as_string())
#server.quit()
Here is a script that I have used for sending email from a gmail account, it should work for others in theory, but I have only tested with gmail. You can call it from the command line passing in the arguements listed in main or you can call the mail function directly from another Python module:
#!/usr/bin/python
# currently set up and tested on gmail only
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os, sys, base64
def mail(gmail_user, enc_pwd, to, subject, body, attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject
msg.attach(MIMEText(body, 'html'))
if attach:
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)
mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, base64.b64decode(enc_pwd))
mailServer.sendmail(gmail_user, to, msg.as_string())
mailServer.close()
def main():
if len(sys.argv) <6:
print "Usage: send_email.py <from> <enc_pwd> <to> <subject> <body> " \
"[<attachments>]"
print "Note: Email is being sent in html mode, so any newlines should " \
"be sent as <br/>"
if len(sys.argv) > 1:
print "\nThe following arguements were received:"
for i in sys.argv:
print i
else:
gmail_user = sys.argv[1]
gmail_pwd = sys.argv[2]
to = sys.argv[3]
subject = sys.argv[4]
body = sys.argv[5]
attach = None
if len(sys.argv) >= 7:
attach = sys.argv[6]
mail(gmail_user, gmail_pwd, to, subject, body, attach)
if __name__ == '__main__':
main()
Let me know if you have any questions
I'm using the following function to send an email message with two attachments in my python script:
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
...
def sendMail(sender_name, to, subject, text, files=None,server="localhost"):
assert type(to)==list
if files:
assert type(files)==list
print "Files: ",files
fro = sender_name
msg = MIMEMultipart()
msg['From'] = fro
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
if files:
for file in files:
# ************** File attaching - Start **************
part = MIMEBase('application', "octet-stream")
part.set_payload( open(file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
msg.attach(part)
# ************** File attaching - End **************
server.set_debuglevel(1)
server.ehlo()
server.starttls()
server.ehlo()
server.sendmail(fro, to, msg.as_string())
server.quit()
I get the mail, and the attachments are there, but for some reason, they are truncated a bit. My guess is I'm missing something in the encoding process.
For example:
Attachment 1: Original file byte count is 1433902, while the new byte count is 1433600
Attachment 2: Original file byte count is 2384703, while the new byte count is 2383872
Any ideas?
Found the problem. Turns out I tried sending the files before the buffer of the writing process was fully flushed.
So, it was a synchronization issue and not an encoding issue.
Sorry about that, and thanks for the help guys!
Could it be related to your current base64.MAXBINSIZE? Encoders.encode_base64 uses base64.encodestring internally. The default value for base64.MAXBINSIZE is 57, can always try setting it larger: base64.MAXBINSIZE = 65536
If the file is already written--be sure to .close() the file and re-open()/.read() it for the payload.
My issues stemmed from timing and this solved the issue for me.