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.
Related
I wrote a code that create a PDF, and I wanted to send it with another file (still a .pdf) with a python code based on SMTPLIB library.
You can see str(names[i]) value for the receiver email, since is taken from a table and also the sending-process is managed with a for cycle, were the name of the just-created pdf is depending on the str(names[i]) value.
I'm trying to manage the following code, considering a two factor authentication in order to send the automated email via python, from a gmail-based email:
sender_email = "sender#gmail.com"
receiver_email = str(names[i])
password = input("Authentication code: ")
subject = "Title"
body = """Hi,
This is the body of the email
"""
attachments = ['file1'+str(names[i])+'.pdf', 'file2.pdf'] # list of attachments
# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Bcc"] = receiver_email # For mass emails
# Add body to email
message.attach(MIMEText(body, "plain"))
if 'attachments' in globals() and len('attachments') > 0:
for filename in attachments:
f = filename
part = MIMEBase('application', "octet-stream")
part.set_payload( open(f,"rb").read() )
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
message.attach(part)
# Add header as key/value pair to attachment part
part.add_header("Content-Disposition",f"attachment; filename= {attachments}",)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
# Log in to server using secure context and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, text)
Everything works just fine: PDF is created, the mail is sent and received but.... the attachments are not ok in non-gmail emails.
What I find in the attachment list in a Outlook mail are files (with no extention) called ['file1'+str(names[i])+'.pdf', 'file2.pdf'], and trying with different receivers gives the same result.
It seems like non-gmail servers do not load files in the proper manner, while the gmail server recognizes the overall process
I thought about writing a "multiserver" object in the last with condition, but I don't know how to do it.
Thank you all!
In simplified code you do this:
# block#1 The following is simplified ---
for filename in attachments:
part = ... # construct part, include file content
part.add_header('Content-Disposition', ...)
message.attach(part)
# block#2: The following is original code ----
# Add header as key/value pair to attachment part
part.add_header("Content-Disposition",f"attachment; filename= {attachments}",)
# Add attachment to message and convert message to string
message.attach(part)
Thus, you
in block#1 you first create a part for each file
in block#2 you then take the last part from block#1 and add another content-disposition header, with including the name list as name
in block#2 you then attach this part again to this message
Obviously, block#1 is all you need and block#2 just messes up everything. Remove it.
I made a Python program that sends an attachment to a mailbox which is the main mailbox of my project. The mail is sent from the mailbox itself to the mailbox itself, so it is the same address for the receiver and for the sender. (see on pic)
here is my code which works from attachment that is not coming from the same mailbox. And I just can't get the attachment. Making another mail box is annoying.
import os
from imbox import Imbox
import traceback
host = "imap.gmail.com"
download_folder = "G:\DownloadFMail"
username = "example#gmail.com"
password = "123456"
mail = Imbox(host, username, password, ssl=True, ssl_context=None, starttls=False)
mailAttach = mail.messages(unread=True,sent_from = username)
for (uid, message) in mailAttach:
mail.mark_seen(uid) # optional, mark message as read
for idx, attachment in enumerate(message.attachments):
try:
att_fn = attachment.get('filename')
download_path = f"{download_folder}/{att_fn}"
print(download_path)
with open(download_path, "wb") as fp:
fp.write(attachment.get('content').read())
except:
print(traceback.print_exc())
mail.logout()
Fixed this issue but the cause was coming from the way I send the attachement. Here i was using stmplib to send it but there was not any header for the attachement resulting to this in mail detail :
That's why it was not detected as attachement by Imbox.
Now it look like this and it work perfectly :
and this is the code sample :
with open(zipfile, "rb") as attachment:
payload = MIMEBase('application', 'octate-stream')
payload.set_payload((attachment).read())
encoders.encode_base64(payload) #encode the attachment
payload.add_header('Content-Disposition','attachment',filename="image.zip")
message.attach(payload) here
If it's not clear enough or/and someone need futher explanation ask me.
i have an output.txt which i want to send its content as an email body.
1.i want to remove specific lines from the content ( not delete from the file itself)
2.i want to be able to convert it to html and to desing some of specific lines size and maybe even color.
i have a working script which sends the mail.
there are some problems:
im not able to remove specific line when using file.read().
when trying readlines() the type is list and the email body is getting messed up.(join doesnt work on list with bytes type)
import smtplib
import email.message
def send_email(subject, msg):
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
ID = 'XXXX'
PASSWORD = 'XXXXXXX'
email_reciever = 'XXXXXX'
server.login(ID, PASSWORD)
message = 'Subject:{} \n\n {}'.format(subject, msg)
server.sendmail(ID, email_reciever, message)
print('Succes')
except Exception as e:
# Print any error messages to stdout
print(e)
finally:
server.quit()
filename = r".\Reports\Report.txt"
with open(filename, "rb") as filename:
text = filename.read()
msg = email.message.Message()
msg.add_header('Content-Type', 'text/plain')
msg.set_payload(text)
subject = "Report"
send_email(subject, msg)
Looking for a way to send the contents of a HTML file that is generated once a day using this script below. Running into road blocks getting it to work. I can sent HTML and see it, just not sure how to print out the contents of the file and send it.
File Format is export_MM-DD-YY.html
Id rather have it display the contents of the HTML in the email not the HTML file.
#!/usr/bin/env python3
import smtplib
import config
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
filename = 'name_of_file'
# Read a file and encode it into base64 format
fo = open(filename, "rb")
filecontent = fo.read()
encodedcontent = base64.b64encode(filecontent) # base64
filename = os.path.basename(filename)
# me == my email address
# you == recipient's email address
me = "From#example.com"
you = "TO#example.com"
subject = 'Test Subject v5'
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
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:\nhttps://www.python.org"
html = """\
**INSERT HTML FILE CONTENTS HERE...**
"""
# 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.
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(config.EMAIL_ADDRESS, config.PASSWORD)
server.sendmail(me,you,msg.as_string())
server.quit()
So I think I got it working but im sure theres more code here than is needed (If anyone sees anything I can clean up?)
#!/usr/bin/env python3
import smtplib
import os
import config
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
raport_file = open('export.html','rb')
alert_msg = MIMEText(raport_file.read(),"html", "utf-8")
# me == my email address
# you == recipient's email address
me = "From#example.com"
you = "TO#example.com"
subject = 'Test Subject v5'
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
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:\nhttps://www.python.org"
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.
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(config.EMAIL_ADDRESS, config.PASSWORD)
server.sendmail(me,you,alert_msg.as_string())
server.quit()
You're really close. Three changes:
Don't open the html file in binary mode. Read the file directly into the html string
report_file = open('export.html')
html = report_file.read()
remove the subsequent assignment to html var
html = """\
"""
send the msg object as constructed
server.sendmail(me, you, msg.as_string())
That worked for me. Also keep in mind that by default gmail settings may not allow your script to send mail. If so you'll need to update your settings to allow "insecure" (meaning non-Google) apps to send mail.
While running the below piece of python script to send pdf attachment using SMTP, encountered SMTPDataError exception. I am able to send text or image files using the below code with the same sender and to the same recipient. The pdf file size is hardly 1 MB.
import smtplib
import email
import email.mime
import email.mime.application
from_email = "XXXX#gmail.com"
from_passwd = ""
to_email = "abc#gmail.com"
message = email.mime.Multipart.MIMEMultipart('mixed')
message['Subject'] = 'Test_run'
message['From'] = from_email
message['To'] = to_email
text_part = email.mime.Text.MIMEText("""This is an e-mail message to be sent in HTML format
<b>This is HTML message.</b>
<h1>This is headline.</h1>
""",'html')
message.attach(text_part)
filename1 = "some_doc.pdf"
fp = open(filename1 , 'rb')
attach_part = email.mime.application.MIMEApplication(fp.read(),"pdf")
fp.close()
attach_part.add_header('Content-Disposition','attachment',filename = "some_doc.pdf")
message.attach(attach_part)
server = smtplib.SMTP("smtp.gmail.com",587)
server.starttls()
server.login(from_email,from_passwd)
server.sendmail(from_email,to_email,message.as_string())
server.close()
The error message encountered
File "/usr/lib/python2.7/smtplib.py", line 746, in sendmail
raise SMTPDataError(code, resp)
smtplib.SMTPDataError: (550, '5.7.1 The user or domain that you are sending to (or from) has a policy that\n5.7.1 prohibited the mail that you sent. Please contact your domain\n5.7.1 administrator for further details. For more information, please visit\n5.7.1 https://support.google.com/a/answer/172179 66sm37804549pfx.29 - gsmtp')
Any help is much appreciated.
Have you tried sending a PDF to a different recipient in a different domain? Or sending a similarly-sized image to this same recipient?
Sounds like this domain might not allow pdf attachments, for whatever reason...