I am struggling with sending email with the attachment of excel file by Python.
The problem I am facing now is python change excel file format to '.aaf' format or other unknown formats.
It happens when python sends excel files to specific email addresses, which I guess are intranet mail address. Other personal email addresses(e.g. gmail) have no trouble, no change in file format. The assuming-intranet mail addresses also receieve pdf file with awkward format as well as excel file.
I am digging out any clue to solve it day and night, but can't find any advice related to it. Any help? Below is my code :
note) attachment = file path + file name
def send_mail(mail_list, cc_list, subject, text, attachment):
msg = EmailMessage()
msg["From"] = MY_ID
msg["To"] = ",".join(mail_list)
msg["Cc"] = ",".join(cc_list)
msg["Subject"] = subject
msg.set_content(text)
if attachment:
filename = Path(attachment).name
with open(filename, "rb") as f:
msg.add_attachment(f.read(), maintype="application", subtype="xlsx", filename=filename)
msg.add_header('Content-Disposition', 'attachment; filename='+filename)
with SMTP_SSL("smtp.gmail.com", 465) as smtp:
smtp.login(MY_ID, MY_PW)
smtp.send_message(msg)
A guy left a comment, which seems removed, and it solved the problem. The solution is :
replace the code I wrote
msg.add_attachment(f.read(), maintype="application", subtype="xlsx", filename=filename)
with one below :
msg.add_attachment(f.read(), maintype="application", subtype="vnd.openxmlformats-officedocument.spreadsheetml.sheet", filename=filename)
Related
I am trying to send an email using Python smtplib.
My objective is to include the below info in email
Attachment file #works fine
Paste the contents of a table in message body #works fine
Write a few lines about the table (as text) in message body # not works. instead stores as an attachment
So, I tried the below code
message = MIMEMultipart()
message['Subject'] = 'For your review - files'
message['From'] = 'user2#org.com'
message['To'] = 'user1#org.com'
# code to paste table contents in outlook message window - works fine
body_content = output # this has the pretty table - html table
message.attach(MIMEText(body_content, "html"))
# code to paste the written text in outlook message window - not works. instead of writing the text in outlook body,it stores as an attachment
written_text = """\
Hi,
How are you?"""
message.attach(MIMEText(written_text, "plain"))
# code to attach an csv file to a outlook email - works fine
with open(filename, "rb") as attachment:
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
msg_body = message.as_string()
server = SMTP('internal.org.com', 2089)
server.sendmail(message['From'], message['To'], msg_body)
print("mail sent successfully")
server.quit()
The problem in my code is that it creates a text file (containing the message "Hi, How are you") and sends as an attachment?
But I want "Hi, How are you" as a text message in the main Outlook message window.
The immediate problem is that many email clients assume that text body parts after the first are attachments. You can experiment with adding an explicit Content-Disposition: inline to the part(s) you want rendered as part of the main message, but is there a reason these need to be separate body parts in the first place? Combining the text fragments into a single body part would perhaps make more sense here.
More fundamentally, your email code was written for an older Python version. The email module in the standard library was overhauled in Python 3.6 to be more logical, versatile, and succinct; new code should target the (no longer very) new EmailMessage API. Probably throw away this code and start over with modern code from the Python email examples documentation.
from email.message import EmailMessage
message = EmailMessage()
message['Subject'] = 'For your review - files'
message['From'] = 'user2#org.com'
message['To'] = 'user1#org.com'
message.set_content(output, subtype="html")
written_text = """\
Hi,
How are you?"""
message.add_attachment(
written_text, subtype="plain",
disposition="inline")
with open(filename, "rb") as attachment:
message.add_attachment(
attachment.read(),
maintype="application", subtype="octet-stream",
filename=filename)
with SMTP('internal.org.com', 2089) as server:
server.send_message(message)
print("mail sent successfully")
server.quit()
If the final attachment is really a CSV file, specifying it as application/octet-stream is a bit misleading; the proper MIME type would be text/csv (see also What MIME type should I use for CSV?)
I want to write a function to attach a csv file to an E-Mail with HTML text. Everything works fine. I sends the E-Mail with the text and the attachment with the right information. Only the data format is wrong. I tried different varieties in MIMEBASE('application', 'octet-stream'). This one gives me a '.bin' data which I cannot open on macOS. Others gave me a plain text data which included the right data, but I don't wanna copy it manually into a csv. Does someone have a solution how I get out the data as '.csv'? Most of the solutions I found here just looked like my code below.
Code:
def send_mail(receiver, subject, filepath, attachname):
#login information
port = 123
smtp_server = "test.server.com"
login = "testlogin" # your login
password = "12345678910" # your password
# specify the sender’s and receiver’s email addresses and text in HTML
sender = "testmail#test.com"
receiver = receiver
message = MIMEMultipart()
message["Subject"] = subject
message["From"] = sender
message["To"] = COMMASPACE.join([receiver])
html_text = """\
<html>
<body>
<p>Hi ,<br>
<p>kind regards</p>
<p> This is an automatized Mail </p>
</body>
</html>
"""
# convert both parts to MIMEText objects and add them to the MIMEMultipart message
text = MIMEText(html_text, "html")
message.attach(text)
#add a file as attachment
file = open(filepath, "rb")
att = MIMEBase('application', 'octet-stream')
att.set_payload(file.read())
encoders.encode_base64(att)
att.add_header("Content_Disposition",
'attachment', filename = attachname)
message.attach(att)
try:
#send your message with credentials specified above
with smtplib.SMTP(smtp_server, port) as server:
server.connect(smtp_server, port)
server.ehlo()
server.starttls()
server.ehlo()
server.login(login, password)
server.sendmail(sender, receiver, message.as_string())
# tell the script to report if your message was sent or which errors need to be fixed
print('Sent')
except (gaierror, ConnectionRefusedError):
print('Failed to connect to the server. Bad connection settings?')
except smtplib.SMTPServerDisconnected:
print('Failed to connect to the server. Wrong user/password?')
except smtplib.SMTPException as e:
print('SMTP error occurred: ' + str(e))
send_mail('testmail#test.com', 'TEST', '/Users/Changer/Desktop/test.csv', 'test.csv')
Email clients may use the content type of the attachment part to determine which program is used to open the attachment, so specifying a suitable content type may help.
This code uses the standard library's mimetypes module to try to guess the correct content type of the attachment, based on its name:
import mimetypes
mimetypes.init()
def send_mail(receiver, subject, filepath, attachname):
...
mimetype, _ = mimetypes.guess_type(attachname)
if mimetype is None:
mimetype = 'application/octet-stream'
type_, _, subtype = mimetype.partition('/')
att = MIMEBase(type_, subtype)
...
The above code will generate these headers for the attachment:
b'Content-Type: text/x-comma-separated-values'
b'MIME-Version: 1.0'
b'Content-Transfer-Encoding: base64'
b'Content_Disposition: attachment; filename="test.csv"'
Whether a mac will open a csv with a spreadsheet application (I assume this is what you want) depends on the configuration of the machine (See this blog for an example). If you want to be sure open the file in a spreadsheet it might be more effective to convert it to a spreadsheet format and send the spreadsheet.
The complete script makes a picture with my raspberry pi camera every minute and sends it via email to my adress. The picture is as an attachment in the email but it has no file extension.
1. What do i have to add that the file get the original file extension that they are saved on the raspberry.
Or if its possible:
2. How can I get the pictures embed in the email. This would be much easier so I don`t have to safe them first on my pc.
I hope you all know what I mean, my englich is not the best :)
def sendMail(data):
global texte
mail = MIMEMultipart()
mail['Subject'] = "Pictures from home"
mail['From'] = fromaddr
mail['To'] = toaddr
mail.attach(MIMEText(body, 'plain'))
dat='%s.jpg'%data
attachment = open(dat, 'rb')
image=MIMEImage(attachment.read())
attachment.close()
mail.attach(image)
server = smtplib.SMTP('smtp.web.de', 587)
server.starttls()
server.login(fromaddr, "PASSWORD")
text = mail.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
movepic(data)
To add a filename to the attachment, you need to add the "Content-Disposition" header to that MIME part, i.e. add this to the code:
attachment = open(dat, 'rb')
image=MIMEImage(attachment.read())
attachment.close()
image.add_header('Content-Disposition', 'attachment; filename=filename.extension')
mail.attach(image)
To send the image without saving it to the file, you have to have the image contents and pass them to MIMEImage constructor. You are currently reading them from file in attachment.read().
So, if you can pass the image binary (instead of filename) to the function, like this:
def sendMail(image_binary_data):
then just pass it, like this:
image=MIMEImage(image_binary_data)
image.add_header('Content-Disposition', 'attachment; filename=filename.extension')
mail.attach(image)
BTW, if you are reading the image from file, it's safer to open and read files this way, to be sure it always closes properly:
with open(dat, 'rb') as image_file:
image=MIMEImage(image_file.read())
# no need to close explicitly
I was trying to get a python program send an attachment via Gmail.
I used the sample code found:
Sending email via gmail & python
The problem is when I sent Excel files like .xls, .xlsx, .xlsm to myself, I cannot open the attachments as they were corrupted, even though the original files are fine. But sending .csv works fine. The entire process does not pop up any warnings or error.
Question is: did oauth2.0 or Gmail or MIME mess up the attachment for some formats? And how can I tell the program upload and send attachment without modifying it?
Had similar issue.
The error is probably in encoding file into bytes.
My gmail still sends corrupted file, when I do want to send xlsx, but I managed to get correct email with xls format.
This is my code:
def create_message_with_excel_attachment(sender, to, subject, message_text, file):
message = MIMEMultipart()
message['to'] = to
message['from'] = sender
message['subject'] = subject
msg = MIMEText(message_text)
message.attach(msg)
part = MIMEBase('application', "vnd.ms-excel")
part.set_payload(open(file, "rb").read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename=file)
message.attach(part)
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
return {'raw': raw}
def send_message(service, user_id, message):
message = (service.users().messages().send(userId=user_id, body=message).execute())
try:
print ('Message Id: %s' % message['id'])
return message
except:
print ('An error occurred:')
I am sending mail from a linux box from a directory path which has three csv files. I want to attach all three in my email. Below is the script.
def mailer(sender, to, path):
msg = MIMEMultipart()
msg['Subject'] = 'UMR_EOD_RECONCILLATIONS'
msg['From'] = sender
msg['To'] = to
for file in os.listdir(path):
f = open( path + file, 'rb')
csv = MIMEText(f.read())
f.close()
msg.attach(csv)
mailer = smtplib.SMTP('localhost')
mailer.sendmail(sender,to, msg.as_string())
mailer.quit()
I have been scratching my head for a while and tried multiple times but still facing below issues.
The files which are attached are text files i.e. .txt extension, I want is to be csv
The files have funny names ATT00001.txt and ATT00002.txt which remains the same.
The third file is never attached to the mail it contents are outputted in the body and it's the damn same file however times I may try.
I have tried setting below but to no avail.
msg["Content-Disposition"] = "attachment; filename=" + file + ";"
msg.add_header('Content-Disposition', 'attachment', filename=file)
1) The first text object will be displayed as the email message. So, add an extra text object first.
2) CSV files should be transmitted as content-type: text/csv, not content-type: text/plain.
#UNTESTED
def mailer(sender, to, path):
msg = MIMEMultipart()
msg['Subject'] = 'UMR_EOD_RECONCILLATIONS'
msg['From'] = sender
msg['To'] = to
msg.attach(MIMEText('Here are the reports you asked for.'))
for file in os.listdir(path):
f = open( path + file, 'rb')
csv = MIMEText(f.read(), 'csv')
f.close()
csv.add_header('Content-Disposition', 'attachment', filename=file)
msg.attach(csv)
mailer = smtplib.SMTP('localhost')
mailer.sendmail(sender,to, msg.as_string())
mailer.quit()
I always advise to run from doing MIME stuff when you just want to send emails. I feel like no one wants to deal with that. It feels like Java.
Try yagmail; my apologies, I'm the developer.
Its purpose is to make it super easy to send emails with HTML, inline images and attachments.
The code for what you want:
import os
import yagmail
def mailer(sender, to, path):
yag = yagmail.SMTP(sender, host="localhost", smtp_skip_login=True)
contents = ['Here are the reports you asked for.'] + os.listdir(path)
yag.send(to, 'UMR_EOD_RECONCILLATIONS', contents)
I'd suggest to read the README for more nice tricks in there :)
To get started, use pip install yagmail to install yagmail.