I am trying to attach a PDF file to an e-mail message.
For one PDF (a Word document printed to PDF), it works (the recipient opens it in Outlook with no problem).
Yet for other PDFs (which seem the same except for being a few KBs larger), they get corrupted.
Here is a sample to use which fails (becomes corrupted).
import smtplib, os
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.utils import formatdate
from email import encoders
attachment_path=r'C:\Directory'+'\\'
login='login'
password='password'
part=MIMEBase('application',"octet-stream")
def message(attachment): #attachment is just the PDF file name
fromaddr = "example#example.com"
cc=fromaddr
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = "example#example.com"
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = "Subject"
body='''
<!DOCTYPE html>
<html>
<body>
<p><font face="Tahoma" size=2> I hope everything is going well.</p></font>
</body>
</html>
'''
msg.attach(MIMEText(body, 'html'))
part.set_payload(open(attachment_path+attachment,'rb').read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="{0}"'.format(os.path.basename(attachment_path+attachment)))
msg.attach(part)
mail=smtplib.SMTP('Server',587)
mail.ehlo()
mail.starttls()
mail.login(login,password)
mail.sendmail(fromaddr,[toaddr,cc],msg.as_string())
I have tried using the following instead of base 64 encoding, but to no avail:
encoders.encode_noop(part)
encoders.encode_7or8bit(part)
encoders.encode_quopri(part)
Thanks in advance!
All I had to do was move this:
part=MIMEBase('application',"octet-stream")
to just above:
part.set_payload(open(attachment_path+attachment,'rb').read())
I have used below line of code and it is working fine for me.
part=MIMEBase('application/pdf',"octet-stream")
Related
I currently have a script that manipulates a .csv file using pandas. I'm trying to send a MIMEMultipart email with the latest .csv version of the file that has been amended but for some reason, the email recipients keep receiving an older unaltered version of the .csv that I trying to send. I'm trying to make sense of it in my head because the old version of the .csv file is written over before it is sent but the original version of the .csv is sent to the recipients.
Maybe I need to specify a path for smtplib to get the file as opposed to just giving the name of the file. Is there a way to do that or is there another way around my problem? I've already tried to change the name to something else in order for smtplib to be able to differentiate between the old .csv and the new one.
This doesn't work though as the file is placed in the directory but my script says that the new file doesn't exist
This is my current code:
email_user = 'Bot#gmail.com'
email_password = 'Business101'
email_send = ('myemail#gmail.com', 'myfriendsemail#gmail.com')
subject = 'TOP 5 CONTRACTS'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = ",".join(email_send)
msg['Subject'] = subject
body = 'These are the latest contracts for this week!'
msg.attach(MIMEText(body,'plain'))
filename='CC.csv'
attachment =open(filename,'rb')
part = MIMEBase('application','octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',"attachment; filename= "+filename)
msg.attach(part)
text = msg.as_string()
server = smtplib.SMTP('smtp.gmail.com',587)
server.starttls()
server.login(email_user,email_password)
server.sendmail(email_user,email_send,text)
server.quit()
print("Emailed Recipients")
Might be worth mentioning that this process is an automated one so the script is being run from a Unix Executable file on my mac.
If you can assist, I'd really appreciate it!
This has been the best way to do it, thanks
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from smtplib import SMTP
import smtplib
import sys
import pandas as pd
df_test = pd.read_csv('/Users/emmanuelafoke/Documents/Selenium/CC.csv')
email_user = 'myemailaddress#gmail.com'
email_password = 'mypassword'
recipients = ['theiremailaddress#gmail.com']
emaillist = [elem.strip().split(',') for elem in recipients]
msg = MIMEMultipart()
msg['Subject'] = 'SUBJECT'
msg['From'] = 'myemailaddress#gmail.com'
html = """\
<html>
<head></head>
<body>
{0}
</body>
</html>
""".format(df_test.to_html())
part1 = MIMEText(html, 'html')
msg.attach(part1)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(email_user,email_password)
server.sendmail(msg['From'], emaillist , msg.as_string())
Thanks for all of your help!
You could actually do this by using the following libraries: email.mime.application, MIMEApplication, email.mime.multipart and email.mime.text. Now, I don't know which client you are using and you might have to do some adjustments to this.
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
SEND_FROM = 'myaddress#client.com' ## Your email address
TOSEND = {'dataframe.csv': export_csv, 'dataframe.xlsx': export_my_excel}
def send_dataframe(send_to, subject, body, df):
multipart = MIMEMultipart()
multipart['From'] = SEND_FROM
multipart['To'] = send_to
multipart['Subject'] = subject
for filename in EXPORTERS:
attachment = MIMEApplication(TOSEND[filename](df)) ### Here is where the df is attached
attachment['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
multipart.attach(attachment)
multipart.attach(MIMEText(body, 'html'))
s = smtplib.SMTP('localhost')
s.sendmail(SEND_FROM, send_to, multipart.as_string())
s.quit()
In send_dataframe() you'll have to put the df you want to attach. This is where TOSEND come in. As you see, there is a function called export_my_excel. You can create it as
import io
import pandas as pd
def export_my_excel(df):
with io.BytesIO() as buffer:
writer = pd.ExcelWriter(buffer)
df.to_excel(writer)
writer.save()
return buffer.getvalue()
Below is the code i'm using to send excel as a attachment to outlook email using python 2.7 version. If i command the attachment lines in the code, i could send the text email but not the attached email.Also i'm not receiving any error. Can somebody please help me identify the issue in the code.
import psycopg2
import pandas as pd
import numpy as np
import xlsxwriter
from datetime import date
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import smtplib
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
server = smtplib.SMTP(host='xxxxx.net', port=25)
fromaddr = "aaaaaaaaabb#outlook.com"
RECIPIENTS = "aaaaaaaaabb#outlook.com"
msg = MIMEMultipart()
body = """
Hi Team, <br>
<br>
Please find the attached data sync validation betweeen Reltio and BDS .<br>
<br>
Please reach out to Team for any questions.<br>
<br>
Regards,<br>
xxxx <br>
Support Team<br>"""
subject = 'Reltio and BDS Data Sync for EU Org'
msg = MIMEMultipart("alternative", None, [MIMEText(body, 'html','utf-8')])
msg['To'] = RECIPIENTS
msg['From'] = "axxxxxyyy#.net"
msg['Subject'] = subject
stg = MIMEBase('application', 'vnd.ms-excel')
stg.set_payload(open("EU_Consent.xlsx", "rb").read())
encoders.encode_base64(stg)
stg.add_header('Content-Disposition', 'attachment', filename="EU_Consent.xlsx")
msg.attach(stg)
server.ehlo()
server.starttls()
server.ehlo()
text = msg.as_string()
server.sendmail(fromaddr, RECIPIENTS, text)
server.quit()
path='/xxx/yyyy/zzz/file.xlsx'
fp=open(path, 'rb')
stg = MIMEBase('application','vnd.openxmlformatsofficedocument.spreadsheetml.sheet')
stg.set_payload(fp.read())
fp.close()
I have a html file whose contents I want to send in the email body using python. Below is the python script:
import smtplib,email,email.encoders,email.mime.text,email.mime.base
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
import codecs
msg = MIMEMultipart()
# me == my email address
# you == recipient's email address
me = "a#b.com"
you = "b#a.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('mixed')
msg['Subject'] = "Automation Testing"
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
f = codecs.open('/Users/test.htm')
html = f.read()
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(part2)
composed = msg.as_string()
fp = open('msgtest.txt', 'w')
fp.write(composed)
# Credentials (if needed)
# The actual mail send
server = smtplib.SMTP('smtp.a.com', 25)
server.starttls()
server.sendmail(me, you, composed)
server.quit()
fp.close()
But, it is sending only an empty email with no html content in the body. Please tell me how to fix this.
I'm using information found on this post Sending Email Using Python
So far the instructions were perfect. I have two additional things I'd like to do:
Call a variable inside the body
Add an attachment
The variable would be todays date. This is it:
today = datetime.datetime.today ()
tday = today.strftime ("%m-%d-%Y")
I know that with mailx, you can attach with the -a option.
To call the variables inside the html body ,just convert them to string to concatenate them in the body
from datetime import datetime
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
today = datetime.today ()
tday = today.strftime ("%m-%d-%Y")
# email subject, from , to will be defined here
msg = MIMEMultipart()
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
""" +str(today)+ """ and """ +str(tday)+ """
</p>
</body>
</html>
"""
msg.attach(MIMEText(html, 'html'))
For attachments please look at http://naelshiab.com/tutorial-send-email-python/
EDIT :
The link provided above seems not available, so the code snippet for sending attachments via email (specifically from gmail) is below
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
msg = MIMEMultipart()
msg['From'] = "from email address"
msg['To'] = "to email address"
msg['Subject'] = "Subject line"
body = """Body
content"""
msg.attach(MIMEText(body, 'plain'))
attachment = open("/path/to/file", "rb")
p = MIMEBase('application', 'octet-stream')
# To change the payload into encoded form
p.set_payload((attachment).read())
# encode into base64
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment; filename= %s" % filename)
# attach the instance 'p' to instance 'msg'
msg.attach(p)
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls() # for security
s.login("from email address", "your password")
text = msg.as_string()
# sending the mail
s.sendmail("from email address", "to email address" , text)
s.quit()
Note : Google will some times block logins from other application (less secure apps) so there is a need to allow this access in your Google account settings
https://myaccount.google.com/u/1/lesssecureapps?pli=1&pageId=none
For your first question: There are lots of ways to create strings that make use of variables.
Some ways are:
body = "blablabla " + tday + " bloo bloo bloo"
body = "Today's date is {}, in case you wondered".format(tday)
For your second question you'd have to tell us which library / module you're using, and then you could go to that module's documentation page and see if there's something for adding an attachment.
Thanks to everyone for posting tips.
For posterity, this is the working script.
The only remaining item is that I need to be able to send the same email to multiple people.
I've tried to add all of the email addresses to the variable with commas between, but they're not getting it. When I look at my email received, they appear to be in the To line. Is it possible that it's only sending to the first email address listed?
#!/usr/bin/python
import smtplib
import time
import datetime
from datetime import date
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email import encoders
fromaddr = "NOREPLY#test.com"
toaddr = ['me#test.com', 'thatguy#test.com']
# Date
today = datetime.datetime.today ()
tday = today.strftime ("%m-%d-%Y")
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = ", ".join(toaddr)
msg['Subject'] = "My Subject Goes Here"
body = """\
<html>
<head></head>
<body>
<p>DO NOT REPLY TO THIS EMAIL!!<br>
<br>
Script run for data as of """ + tday + """.<br>
<br>
See attachment for items to discuss<br>
<br>
The files have also been uploaded to SharePoint<br>
<br>
If you have any issues, email admin#test.com<br>
<br>
</p>
</body>
</html>
"""
msg.attach(MIMEText(body, 'html'))
filename = "discuss.csv"
attachment = open("discuss.csv", "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('localhost')
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
I saw there are a few somewhat similar questions on stack overflow already, but I couldn't find a solution to my specific problem in them.
I am trying to use Python to send an HTML email with a .pdf attachment. It seems to work fine when I check my email on gmail.com, but when I check the message through apple's Mail program, I do not see the attachment. Any idea what is causing this?
My code is below. A lot of it is copied from various places on stack overflow, so I do not completely understand what each part is doing, but it seems to (mostly) work:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from os.path import basename
import email
import email.mime.application
#plain text version
text = "This is the plain text version."
#html body
html = """<html><p>This is some HTML</p></html>"""
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Deliverability Report"
msg['From'] = "me#gmail.com"
msg['To'] = "you#gmail.com"
# Record the MIME types of both parts - text/plain and text/html
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# create PDF attachment
filename='graph.pdf'
fp=open(filename,'rb')
att = email.mime.application.MIMEApplication(fp.read(),_subtype="pdf")
fp.close()
att.add_header('Content-Disposition','attachment',filename=filename)
# Attach parts into message container.
msg.attach(att)
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
s = smtplib.SMTP()
s.connect('smtp.webfaction.com')
s.login('NAME','PASSWORD')
s.sendmail(msg['From'], msg['To'], msg.as_string())
s.quit()
I'm not sure if it is relevant, but I am running this code on a WebFaction server.
Thanks for the help!
To have text, html and attachments at the same time it is necessary to use both mixed and alternative parts.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
text = "This is the plain text version."
html = "<html><p>This is some HTML</p></html>"
text_part = MIMEText(text, 'plain')
html_part = MIMEText(html, 'html')
msg_alternative = MIMEMultipart('alternative')
msg_alternative.attach(text_part)
msg_alternative.attach(html_part)
filename='graph.pdf'
fp=open(filename,'rb')
attachment = email.mime.application.MIMEApplication(fp.read(),_subtype="pdf")
fp.close()
attachment.add_header('Content-Disposition', 'attachment', filename=filename)
msg_mixed = MIMEMultipart('mixed')
msg_mixed.attach(msg_alternative)
msg_mixed.attach(attachment)
msg_mixed['From'] = 'me#gmail.com'
msg_mixed['To'] = 'you#gmail.com'
msg_mixed['Subject'] = 'Deliverability Report'
smtp_obj = smtplib.SMTP('SERVER', port=25)
smtp_obj.ehlo()
smtp_obj.login('NAME', 'PASSWORD')
smtp_obj.sendmail(msg_mixed['From'], msg_mixed['To'], msg_mixed.as_string())
smtp_obj.quit()
Message structure should be like this:
Mixed:
Alternative:
Text
HTML
Attachment
Use
msg = MIMEMultipart('mixed')
instead of 'alternative'