Python: Open Outlook Email (.msg) file in read write mode - python

I want to open Outlook email (msg) file in read and write mode to parse it and alter date values. To fetch (read mode) date from msg file and then replace (write mode) dummy date to msg file. I did following so far.
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = outlook.OpenSharedItem(r"C:\Users\abc.msg")
print msg.SentOn
I am able to get SendOn date. It means its by default in read mode. How to open it in to write mode and replace SendOn date with Dummy date. Or any other way to do so?

SentOn property is read-only in the Outlook Object Model. You'd need Extended MAPI for that (C++ or Delphi, use OpenIMsgOnIStg, set the PR_CLIENT_SUBMIT_TIME property) or Redemption (any language):
set Session = CreateObject("Redemption.RDOSession")
set Msg = Session.GetMessageFromMsgFile("C:\Users\abc.msg")
Msg.SentOn = #5/17/2016#
Msg.Save

Related

Edit read-only password protected excel with Python

I am trying to find a way to edit a password protected excel with Python. Password is not required to open the excel, it is only required if you want to edit it:
Is it possible to access this using password and edit it? Would be perfect if it would be possible to edit it using Openpyxl. I have already tried to use msoffcrypto:
decrypted = io.BytesIO()
with open("encrypted.xlsx", "rb") as f:
file = msoffcrypto.OfficeFile(f)
file.load_key(password="Passw0rd") # Use password
file.decrypt(decrypted)
df = pd.read_excel(decrypted)
But I think this works only when you can access the file only with password (the whole file is password encrypted, not the edit part.
If the Excel workbook has been saved with a "Password to modify" like in Office 2011 then you you usually need to perform following steps in Excel to save an unprotected version:
enter the password
open the workbook (still it is write-protected)
save as (unprotected)
In Python
You can decrypt it using a password and then pass the decrypted byte stream - as file-like object - to the opening function, be it pandas.read_excel() or openpyxl.load_workbook():
import io
import msoffcrypto
import openpyxl
decrypted_workbook = io.BytesIO()
with open('encrypted.xlsx', 'rb') as file:
office_file = msoffcrypto.OfficeFile(file)
office_file.load_key(password='passw0rd')
office_file.decrypt(decrypted_workbook)
# `filename` can also be a file-like object.
workbook = openpyxl.load_workbook(filename=decrypted_workbook)
See also:
Reading encrypted file with pandas
How to open a password protected excel file using python?
how to read password protected excel in python

Viewing content of outlook attachment in python

I'm trying to use python to get some data that is in an attachment on an outlook email and then use that data in python. I've managed to write the code that will get into the outlook inbox and folder I want and then get the attachments of a specific message, however I'm not sure how to view the content of that attachment. A lot of the other questions and tutorials I've found seem to be more related to saving the attachment in a folder location rather than viewing the attachment in python itself.
For context the data I'm trying to get to is an exported report from adobe analytics, this report is a csv file that is attached to an email as a zip file. The CSV file shows some data for a specific time period and I'm planning on scheduling this report to run weekly so what I want to do is get python to look through all the emails with this report on then stack all this data into one dataframe so that I have all the history plus the latest week's data in one place then export this file out.
Please find the code below that I've written so far. If you need more details or I haven't explained anything very well please let me know. I am fairly new to python especially the win32com library so there might be obvious stuff I'm missing.
#STEP 1---------------------------------------------
#import all methods needed
from pathlib import Path
import win32com.client
import requests
import time
import datetime
import os
import zipfile
from zipfile import ZipFile
import pandas as pd
#STEP 2 --------------------------------------------
#connect to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
#STEP 3 --------------------------------------------
#connect to inbox
inbox = outlook.GetDefaultFolder(6)
#STEP 4 --------------------------------------------
#connect to adobe data reports folder within inbox
adobe_data_reports_folder = inbox.Folders['Cust Insights'].Folders['Adobe data reports']
#STEP 5 --------------------------------------------
#get all messages from adobe reports folder
messages_from_adr_folder = adobe_data_reports_folder.Items
#STEP 6 ---------------------------------------------
#get attachement for a specific message (this is just for testing in real world I'll do this for all messages)
for message in messages_from_adr_folder:
if message.SentOn.strftime("%d-%m-%y") == '07-12-22':
attachment = message.Attachments
else:
pass
#STEP 7 ----------------------------------------------
#get the content of the attachment
##????????????????????????????
With the Outlook Object Model, the best you can do is save the attachment as a file (Attachment.SaveAsFile) - keep in mind that MailItem.Attachments property returns the Attachments collection, not a single Attachment object - loop through all attachments in the collection, figure out which one you want (if there is more than one), and save it as file.
To access file attachment data directly without saving as a file, you will need to use Extended MAPI (C++ or Delphi only) or Redemption (any language, I am its author).
Dmitry mentioned below that there isn't the option to view attachment content with an outlook object model.
So I've come up with a solution for this which basically involves using the save method to save the attachment into a folder location on the current working directory and then once that file is save just load that file back up into python as a dataframe. The only thing to note is that I've added an if statement that only saves files that are csvs, obviously this part can be removed if needed.
If you wanted to do this with multiple files and stack all of these into a single dataframe then I just created a blank dataframe at the start (with the correct column names of the file that will be loaded) and concatenated this blank dataframe with the "importeddata" then added this code into the "attachment" for loop so that each time it's appending the data that is saved and loaded from the attachment
#STEP 1---------------------------------------------
#import all methods needed
from pathlib import Path
import win32com.client
import requests
import time
import datetime
import os
import zipfile
from zipfile import ZipFile
import pandas as pd
#STEP 1b ---------------------------------------------
#create a directory where I can save the files
output_dir = Path.cwd() / "outlook_testing"
#STEP 2 --------------------------------------------
#connect to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
#STEP 3 --------------------------------------------
#connect to inbox
inbox = outlook.GetDefaultFolder(6)
#STEP 4 --------------------------------------------
#connect to adobe data reports folder within inbox
adobe_data_reports_folder = inbox.Folders['Cust Insights'].Folders['Adobe data
reports']
#STEP 5 --------------------------------------------
#get all messages from adobe reports folder
messages_from_adr_folder = adobe_data_reports_folder.Items
#STEP 6 ---------------------------------------------
#get attachement for a specific message (this is just for testing in real world
#I'll do this for all messages)
for message in messages_from_adr_folder:
body = message.Body
if message.SentOn.strftime("%d-%m-%y") == '07-12-22':
attachments = message.Attachments
for attachment in attachments:
stringofattachment = str(attachment)
#STEP 6b - if the attachment is a csv file then save the attachment to a folder
if stringofattachment.find('.csv') != - 1:
attachment.SaveAsFile(output_dir / str(attachment))
print(output_dir / str(attachment))
#STEP 6C - reload the saved file as a dataframe
importeddata = pd.read_csv(output_dir / str(attachment))
else:
print('NOT CSV')
pass
else:
pass

how to save an outlook mail (.msg) as .html or .pdf using python

I am trying to download an email from outlook sent-items. Currently I am able to save is '.msg' format. Is there anyway through which I can save the mail as '.html' or '.pdf' using python
from pathlib import Path
import win32com.client as win32
from datetime import date, timedelta
import os
import glob
# Create output folder
output_dir = Path.cwd()
output_dir.mkdir(parents=True, exist_ok=True)
# Connect to folder
outlook = win32.Dispatch('outlook.application').GetNamespace("MAPI")
# Connect to folder
sent_items = outlook.GetDefaultFolder(5)
# Get the required mail and store it locally
messages = sent_items.items
message = messages.GetLast()
name = str(message.subject)
message.saveas(os.getcwd()+'//'+name+".msg")
When I tried to replace .msg with .html or .pdf in the last line, then it is not working. The resultant file generated through html or pdf is displayed as special characters and not the actual .msg format
The Outlook object model doesn't provide any property or method for saving messages using the PDF file format. But you can use the OlSaveAsType enumeration for all available file formats. The HTML format (.html) is available. So, you just need to pass the olHTML value for the second parameter in addition to the file path:
message.saveas(os.getcwd()+'//'+name+".html", Outlook.OlSaveAsType.olHTML)
If you really need to save the message using the PDF file format you may consider using the Word object model for that. The Document.ExportAsFixedFormat2 method saves a document in PDF or XPS format. Use the GetInspector method to get the inspector where you may retrieve an instance of the Word Document object which represents the message body. The Inspector.WordEditor property returns the Microsoft Word Document Object Model of the message being displayed. The WordEditor property is only valid if the IsWordMail method returns true and the EditorType property is olEditorWord. The returned Word Document object provides access to most of the Word object model

How to read in Excel email attachments received in Outlook?

So I am trying to read in an Excel file from an attachment in Microsoft outlook. The code below works, but only while the email I am trying to read the attachment from is at the top of my inbox. How can I adjust my code so it looks at all emails in my inbox folder looking for the attachment or finding the emailed based on the subject provided. Also I would eventually like to have this work with a shared mailbox, but that is a secondary issue right now.
from win32com.client import Dispatch
import email
import datetime as date
import os
outlook = Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder("6")
all_inbox = inbox.Items
val_date = date.date.today()
sub_today = 'subject of email'
att_today = 'Filename'
for msg in all_inbox:
yourstring = msg.Subject.encode('ascii', 'ignore').decode('ascii')
if(yourstring.find('"Filename"') != -1):
break
for att in msg.Attachments:
if att.FileName == att_today:
attachments = msg.Attachments
break
attachment = attachments.Item(1)
fn = os.getcwd() + '\\' + att_today
attachment.SaveASFILE(fn)
df = pd.read_excel(fn)
First of all, to iterate over all items you need to skip items, not break the loop. Use the continue keyword instead of break in the loop.
The Outlook object model provides the Find/FindNext and Restrict methods for getting items that correspond to your conditions. The store provider does the job more efficient than just iterating over all items in the folder. Read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
You can use the following search criteria where the query performs a phrase match query for hello in the message subject (VBA syntax):
filter = "#SQL=" & Chr(34) & "https://schemas.microsoft.com/mapi/proptag/0x0037001E" _
& Chr(34) & " ci_phrasematch " & "'hello'"
To get a shared folder using the NameSpace.GetSharedDefaultFolder method which returns a Folder object that represents the specified default folder for the specified user. This method is used in a delegation scenario, where one user has delegated access to another user for one or more of their default folders (for example, their shared Calendar folder).

Importing mime .eml file to gmail API using the import function

I am a python developer and somewhat new to using Google's gMail API to import .eml files into a gMail account.
I've gotten all of the groundwork done getting my oAuth credentials working, etc.
However, I am stuck where I load in the data-file. I need help loading the message data in to place in a variable..
How do I create the message_data variable reference - in the appropriate format - from my sample email file (which is stored in rfc822 format) that is on disk?
Assuming I have a file on disk at /path/to/file/sample.eml ... how do I load that to message_data in the proper format for the gMail API import call?
...
# how do I properly load message_data from the rfc822 disk file?
media = MediaIoBaseUpload(message_data, mimetype='message/rfc822')
message_response = service.users().messages().import_(
userId='me',
fields='id',
neverMarkSpam=True,
processForCalendar=False,
internalDateSource='dateHeader',
media_body=media).execute(num_retries=2)
...
You want to import an eml file using Gmail API.
You have already been able to get and put values for Gmail API.
You want to achieve this using google-api-python-client.
service in your script can be used for uploading the eml file.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In this case, the method of "Users.messages: insert" is used.
Modified script:
Before you run the script, please set the filename with the path of the eml file.
eml_file = "###" # Please set the filename with the path of the eml file.
user_id = "me"
f = open(eml_file, "r", encoding="utf-8")
eml = f.read()
f.close()
message_data = io.BytesIO(eml.encode('utf-8'))
media = MediaIoBaseUpload(message_data, mimetype='message/rfc822', resumable=True)
metadata = {'labelIds': ['INBOX']}
res = service.users().messages().insert(userId=user_id, body=metadata, media_body=media).execute()
print(res)
In above script, the following modules are also required.
import io
from googleapiclient.http import MediaIoBaseUpload
Note:
In above modified script, {'labelIds': ['INBOX']} is used as the metadata. In this case, the imported eml file can be seen at INBOX of Gmail. If you want to change this, please modify this.
Reference:
Users.messages: insert
If I misunderstood your question and this was not the result you want, I apologize.

Categories