I am new to writing Python code and am trying to run a test to determine if an email attachment (.xls file) is encrypted with a password. I am using win32com to retrieve from Outlook and then loop through emails and attachments.
I've reviewed Microsoft documentation, but couldn't find what I need.
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox=outlook.GetDefaultFolder(6)
email_count = inbox.Items.count
messages = inbox.Items
for message in messages:
emailSendDate = message.senton.date()
attachments = message.attachments
emailSubject = message.Subject
for attachment in attachments:
attachment_name = attachment.filename
#a way to test if email attachment is encrypted?
Outlook knows nothing about a particular attachment type - it does not know and does not care. You would need to use the Excel Object Model to try to figure that out after you save the attachment using Attachment.SaveAsFile. Start at https://learn.microsoft.com/en-us/office/vba/api/excel.workbook.passwordencryptionfileproperties
I went the route of saving the attachment, but it would be much better if I could retrieve the temporary file path of the attachment and not need to save it. I tried using the GetTemporaryFilePath() method, but the rules of the method made it not work for me. For now, I used xlrd to test if it can open the workbook.
attachment.SaveAsFile(os.path.join(testfilepath, attachment.filename))
try:
wb = xlrd.open_workbook(os.path.join(testfilepath, attachment.filename))
attachmentEncryption = 'N'
except:
attachmentEncryption = 'Y'
Related
I use the code below to extract the attachment from an email, but the problem is that I need to extract an attachment inside an email which is already an attachment of an email. It goes like this :
email -> email (as an attachment) -> attachment
Can someone help ? I have a shit ton of email attachment to extract...
The code I used:
from pathlib import Path #core python module
import win32com.client #pip install pywin32
# Create output folder
output_dir = Path.cwd() / "Output"
output_dir.mkdir(parents=True, exist_ok=True)
# Connect to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# Connect to folder
#inbox = outlook.Folders("youremail#provider.com").Folders("Inbox")
inbox = outlook.GetDefaultFolder(6)
# https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders
# DeletedItems=3, Outbox=4, SentMail=5, Inbox=6, Drafts=16, FolderJunk=23
# Get messages
messages = inbox.Items
for message in messages:
subject = message.Subject
body = message.body
attachments = message.Attachments
# Create separate folder for each message
target_folder = output_dir / str(subject)
target_folder.mkdir(parents=True, exist_ok=True)
# Write body to text file
Path(target_folder / "EMAIL_BODY.txt").write_text(str(body))
# Save attachments
for attachment in attachments:
attachment.SaveAsFile(target_folder / str(attachment))
I tried to add a loop, to get the item inside the item. It didn't work
The problematic lines of code are:
# Create separate folder for each message
target_folder = output_dir / str(subject)
target_folder.mkdir(parents=True, exist_ok=True)
Make sure that the Subject property value doesn't contain forbidden symbols. Windows (and linux) has a number of symbols forbidden to use in folder and file names. See What characters are forbidden in Windows and Linux directory names? for more information.
Second, you need to check the attachment type by checking the Attachment.Type property to make sure that you deal with a real file attached, not URL or linked attachments.
4096, 'Microsoft Outlook', "Cannot save the attachment. You don't have appropriate permission to perform this operation."
Make sure that you pass a valid file path to the SaveAsFile method. You must specify the full attachment file name including the name part. Most probably you are only specifying the directory name, but you need to concatenate the directory and file name (you may use the DisplayName property of the attachment object for the filename).
I have a .csv attachment that is emailed to me daily. I'd like to read in this email using python and perform some modifications on it. The emails are sent to my Outlook email account.
This is what I am doing:
import win32com.client
my_outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
folder = outlook.GetDefaultFolder(6) #index
for item in folder.Items
print(item.body)
However, this is for extracting data within the email, how would I read the actual attachment that is being sent? I am looking into extract-msg PyPi as well.
Any insight will be helpful.
To read the attachment, use the following..
import win32com.client
import datetime
import os
import email
outlook = win32com.client.Dispatch("outloook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) # change depending on folder you wish to see
message = inbox.items
for message in inbox.Items:
if message.Unread == True # finds unread mesages
for attachment in message.Attachments:
This will show you all unread email attachments, simply complete the code with the file address you wish to save the attachments..
I am currently trying to figure out how to parse all the msg files I have stored in a specific folder and then save the body text to a dataframe but when I'm trying to extract the body of the emaill it is also extracting the emails that are attached to it. I want to extract only the body of the first email that is present in the msg file.
#src-code:https://stackoverflow.com/questions/52608069/parsing-multiple-msg-files-and-storing-the-body-text-in-a-csv-file
#reading multiple .msg files using python
from pathlib import Path
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# Assuming \Documents\Email Reader is the directory containg files
for p in Path(r'C:\Users\XY\Documents\Email Reader').iterdir():
if p.is_file() and p.suffix == '.msg':
msg = outlook.OpenSharedItem(p)
print(msg.Body)
I had a similar requirement. Full code is here:
https://medium.com/#theamazingexposure/accessing-shared-mailbox-using-exchangelib-python-f020e71a96ab
For you purpose I think this snippet is going to work. It reads the first message with a specific subject line:
from exchangelib import Credentials, Account, FileAttachment
credentials = Credentials('First_Name.Last_Name#some_domain.com', 'Your_Password_Here')
account = Account('First_Name.Last_Name#some_domain.com', credentials=credentials, autodiscover=True)
filtered_items = account.inbox.filter(subject__contains='Your Search String Here')
print("Getting latest email from Given Search String...")
for item in account.inbox.filter(subject__contains='Your Search String Here').order_by('-datetime_received')[:1]:
print(item.subject, item.text_body.encode('UTF-8'), item.sender, item.datetime_received) #body of email is extracted using:: item.text_body.encode('UTF-8')
from exchangelib import Credentials, Account, FileAttachment
credentials = Credentials('First_Name.Last_Name#some_domain.com','Your_Password_Here')
account = Account('First_Name.Last_Name#some_domain.com', credentials=credentials, autodiscover=True)
unread_mails = account.inbox.filter(is_read=False)
# ur unread mail list
unread_mail_list = [mail for mail in unread_mails]
# get text body of the latest unread mail
mail_body = unread_mail_list[0].text_body
I am a bit new to coding and I am trying to understand how to get Python to save MS Outlook attachments from a specific sender. I currently receive the same email from the same person each day regarding data that I need to save to a specific folder. Below are the requirements I am trying to meet:
I want to open MS Outlook and search for specific sender
I want to make sure that the email that I am opening from the specific sender is the most current date
I want to save all attached files from this sender to a specific folder on my desktop
I have seen some posts on using win32com.client but have not had much luck getting it to work with MS Outlook. I will attach some code I have tried below. I appreciate any feedback!
import win32com.client
outlook=win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox=outlook.GetDefaultFolder(6)
messages=inbox.Items
for message in messages:
attachments = message.attachments
for attachment in attachments:
pass
You almost got it, add filter to the sender email address
import win32com.client
Outlook = win32com.client.Dispatch("Outlook.Application")
olNs = Outlook.GetNamespace("MAPI")
Inbox = olNs.GetDefaultFolder(6)
Filter = "[SenderEmailAddress] = '0m3r#email.com'"
Items = Inbox.Items.Restrict(Filter)
Item = Items.GetFirst()
for attachment in Item.Attachments:
print(attachment.FileName)
attachment.SaveAsFile(r"C:\path\to\my\folder\Attachment.xlsx")
Python 3.8 on windows
def saveAttachments(email:object):
for attachedFile in email.Attachments: #iterate over the attachments
try:
filename = attachedFile.FileName
attachedFile.SaveAsFile("C:\\EmailAttachmentDump\\"+filename) #Filepath must exist already
except Exception as e:
print(e)
for mailItem in inbox.Items:
#Here you just need to bould your own conditions
if mailItem.Sender == "x" or mailItem.SenderName == "y":
saveAttachments(mailItem)
The actual conditions you can change to your liking. I would recommend referring to the Object model for Outlook MailItem objects: https://learn.microsoft.com/en-gb/office/vba/api/outlook.mailitem
Specifically its Properties
Looking to create and send messages with multiple files attached. Per the online gmail api documentation, there is a function for building messages with an attachment but no documentation for howto use it to create a message with multiple attachments.
Can I use the gmail API to send messages with multiple attachments programmatically? How might one do this?
With this function, you can send to one or multiple recipient emails, and also you can attach zero, one or more files. Coding improvement recommendations are welcome, however the way it is now, it works.
Python v3.7
smtplib from https://github.com/python/cpython/blob/3.7/Lib/smtplib.py (download the code and create the smtplib.py on your project folder)
def send_email(se_from, se_pwd, se_to, se_subject, se_plain_text='', se_html_text='', se_attachments=[]):
""" Send an email with the specifications in parameters
The following youtube channel helped me a lot to build this function:
https://www.youtube.com/watch?v=JRCJ6RtE3xU
How to Send Emails Using Python - Plain Text, Adding Attachments, HTML Emails, and More
Corey Schafer youtube channel
Input:
se_from : email address that will send the email
se_pwd : password for authentication (uses SMTP.SSL for authentication)
se_to : destination email. For various emails, use ['email1#example.com', 'email2#example.com']
se_subject : email subject line
se_plain_text : body text in plain format, in case html is not supported
se_html_text : body text in html format
se_attachments : list of attachments. For various attachments, use ['path1\file1.ext1', 'path2\file2.ext2', 'path3\file3.ext3']. Follow your OS guidelines for directory paths. Empty list ([]) if no attachments
Returns
-------
se_error_code : returns True if email was successful (still need to incorporate exception handling routines)
"""
import smtplib
from email.message import EmailMessage
# Join email parts following smtp structure
msg = EmailMessage()
msg['From'] = se_from
msg['To'] = se_to
msg['Subject'] = se_subject
msg.set_content(se_plain_text)
# Adds the html text only if there is one
if se_html_text != '':
msg.add_alternative("""{}""".format(se_html_text), subtype='html')
# Checks if there are files to be sent in the email
if len(se_attachments) > 0:
# Goes through every file in files list
for file in se_attachments:
with open(file, 'rb') as f:
file_data = f.read()
file_name = f.name
# Attaches the file to the message. Leaves google to detect the application to open it
msg.add_attachment(file_data, maintype='application', subtype='octet-stream', filename=file_name)
# Sends the email that has been built
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
smtp.login(se_from, se_pwd)
smtp.send_message(msg)
return True
Don't forget to activate less secure apps on your google account (https://myaccount.google.com/lesssecureapps) for this code to work.
Hope this helps