Getting the name of a folder using Exchangelib - python

I have looked at:
How to get the parent folder name of Message with Exchangelib python
But have been unable to make this work using the following debugging code:
for item in docdead.all().order_by('-datetime_received')[:3000]: #look into the inbox the first 3K emails order desc by date received
if item.datetime_received < ews_bfr: #if the mail if older than the custom date in the EWS format then apply rule
print (item.subject)
print (item.datetime_received)
print (item.sender.email_address)
print (item.sender.name)
print (item.body)
print(SingleFolderQuerySet(
account=account,
folder=account.root
).get(id=item.parent_folder_id.id))
for attachment in item.attachments:
print (attachment.name)
I get:
ValueError: EWS does not support filtering on field 'id'
I am sure its a simple error, but I would appreciate any help.

If you're just querying one folder, then parent_folder_id will always point to that folder.
If you're querying multiple folders at a time, here's the general way to look up a folder name by ID:
from exchangelib.folders import FolderId, SingleFolderQuerySet
folder_name = SingleFolderQuerySet(
account=account,
folder=FolderId(id=item.parent_folder_id.id),
).resolve().name

Related

How do I access Online Archive mailbox using Python?

SOLVED ! :)
I used the following to move my mail from somewhere in my inbox into online archives with some important help mentioned below :
import win32com
import os
import sys
outlook = win32com.client.Dispatch('outlook.application')
mapi = outlook.GetNamespace("MAPI")
src = mapi.GetDefaultFolder(6).Folders["tobemoved"]
target = mapi.Folders["Online Archive - XXX"].Folders['Archive']
messages = src.Items
i = range(messages.count, 1, -1)
for x in i:
print(x)
messages(x).Move(target)
`
I have additional folder called
'Online-Archive-Same email address as "inbox" email '
that i currently can't locate it tried to use this link to figure out the enumeration of it . but no luck ..
as i must free up some disk space ill appreciate any help given.
P.S
tried the conventional way - with outlook struggling with connection issues and 22k email to be moved to be archived outlook just giving up on me :) feel free to advise anything that can resolve this issue.
You can access the Office 365 Online Archive folders like this:
Replace the example email with the exact email address you see in outlook.
import win32com.client
import win32com
app = win32com.client.gencache.EnsureDispatch("Outlook.Application")
outlook = app.GetNamespace("MAPI")
outlook_folder = outlook.Folders['Online Archive - Example#email.com'].Folders['Inbox']
item_count = outlook_folder.Items.Count
print(item_count)
180923
On the low (Extended MAPI) level (C++ or Delphi only), Online Archive is just another delegate Exchange mailbox. The only way to distinguish an archive mailbox from yet another delegate mailbox owned by some Exchange user is by reading PR_PROFILE_ALTERNATE_STORE_TYPE property in the archive store profile section - retrieve the store entry id (PR_ENTRYID), then find the matching row in the session stores table (IMAPISession::GetMsgStoresTable). For the matching row (use IMAPISession::CompareEntryIDs), retrieve PR_PROVIDER_UID property. Use its value to call IMAPISession.OpenProfileSection. Read PR_PROFILE_ALTERNATE_STORE_TYPE property from the IProfSect object and check if its value is "Archive" (unlike the store name, is not localized).
If Extended MAPI in C++ or Delphi is not an option, you can either
Try to find a matching store in the Namespace.Stores collection with the name starting with "Online Archive - " and the SMTP address of the user. Since that prefix is locale specific, that is not something I would use in production code.
Use Redemption (I am its author) - it exposes RDOExchangeMailboxStore.IsArchive property. If the archive store is not already opened in Outlook, you can also use RDOSession.GetArchiveMailbox. In VB script:
set rSession = CreateObject("Redemption.RDOSession")
rSession.MAPIOBJECT = Application.Session.MAPIOBJECT
userAddress = rSession.CurrentUser.SMTPAddress
set store = GetOpenArchiveMailboxForUser(userAddress)
if not store is Nothing Then
MsgBox "Found archive store for " & userAddress
Else
MsgBox "Could not find archive store for " & userAddress
End If
function GetOpenArchiveMailboxForUser(SmtpAddress)
set GetOpenArchiveMailboxForUser = Nothing
for each store in rSession.Stores
if TypeName(store) = "RDOExchangeMailboxStore" Then
Debug.Print store.Name & " - " & store.Owner.SMTPAddress & " - " & store.IsArchive
if store.IsArchive and LCase(store.Owner.SMTPAddress) = LCase(SmtpAddress) Then
set GetOpenArchiveMailboxForUser = store
exit for
End If
End If
next
end function

Python script to save email in a physical folder

I am a first time user of stack overflow. I am reaching out here because I have trouble saving outlook email (.MSG) using python. The idea is to archive email as it is in physical drive.
Everything works, except the save As command which throw a very generic error. It would be great help if anyone can help me please.
Here is the code I am I Using:
import win32com.client as win32
from win32com.client import Dispatch
import os
import re
os.chdir("C:\\Users\\username\\Downloads\\RPA")
outlook = win32.gencache.EnsureDispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
print(inbox)
messages = inbox.Items
for message in messages:
message = messages.GetNext()
name = str(message.Subject)
name = re.sub('[^A-Za-z0-9]+', '', name) + '.msg'
print(name)
# message.Display(True)
message.SaveAs(os.getcwd() + '//' + name)
The Error I get executing the code
return self._oleobj_.InvokeTypes(61521, LCID, 1, (24, 0), ((8, 1), (12, 17)),Path
pywintypes.com_error: (-2147467260, 'Operation aborted', None, None)
In the code you are iterating over all items in the Inbox folder:
for message in messages:
message = messages.GetNext()
name = str(message.Subject)
name = re.sub('[^A-Za-z0-9]+', '', name) + '.msg'
If the folder contains a lot of items the operation may take some time to complete. I'd suggest processing items in chunks, so you may keep Outlook under control and prevent freezing the UI (if any). The Find/FindNext or Restrict methods can help with that. 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
Another point is that a file name should be unique for all items in the folder. What is the actual string argument passed to the SaveAs method?
Also you need to make sure that no forbidden symbols are used in the filename.

Python Saving Attachments from Outlook

I am trying to automate some python code that will automatically save some attachments from certain emails with a specific title.
Below is what I currently have:
import win32com.client as client
outlook = client.Dispatch('Outlook.Application')
namespace = outlook.GetNameSpace('MAPI')
inbox = namespace.GetDefaultFolder(6)
target_subject = 'Testing attachment'
mail_items = [item for item in inbox.Items if item.Class == 43]
filtered = [item for item in mail_items if item.Subject == target_subject]
if len(filtered) != 0:
target_email = filtered[0]
if target_email.Attachments.Count > 0:
attachments = target_email.Attachments
save_path = 'C:'
for file in attachments:
file.SaveAsFile(save_path.format(file.FileName))
However I seem to be getting an error with permissions?
com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', "Cannot save the attachment. You don't have appropriate permission to perform this operation.", None, 0, -2147024891), None)
Not sure how to work around this, I am the Admin etc.
I am also wondering what would be the changes required to actually deploy this online and have it running, i.e. I am not passing any credentials as it's local, if operating stand alone I would like it to access my inbox every 7 days or so and download this specific attachments from this specific email.
Any help will be greatly appreciated.
Thanks!
Choose another drive or folder, for example, My Documents doesn't require admin privileges for writing. Otherwise, you will have to run Outlook with admin privileges if you want to write anything to the system drive (C:).
Also I've noticed the following lines of code:
mail_items = [item for item in inbox.Items if item.Class == 43]
filtered = [item for item in mail_items if item.Subject == target_subject]
Iterating over all items in the folder is not really a good idea, moreover, you are doing that twice!
I'd recommend using the Find/FindNextorRestrict` methods of the Items class that allow getting only items that correspond to the specified condition. 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
Users by default do not have write access to the root drive (C:).
Change it to something like 'c:\temp\'

How to get the name, surname and email from dropbox object in python?

i'm new in python and i try to get the name, surname and email from a dropbox object using the API v2 in python. I found this code but i get data that i don't need. How i can get only the datas previously named?
import dropbox
dbx = dropbox.Dropbox(<authentication-toke>)
print(dbx.users_get_current_account())
The users_get_current_account method returns a FullAccount object. You can get the desired pieces of account information from that object, like this:
import dropbox
dbx = dropbox.Dropbox(<authentication-toke)
account = dbx.users_get_current_account()
print(account.name.given_name)
print(account.name.surname)
print(account.email)

Using ExtractMsg in a loop?

I am trying to write a script that will extract details from Outlook .msg files and append then to a .csv file. ExtractMsg (https://github.com/mattgwwalker/msg-extractor) will process the messages one at a time, at the command line with 'python ExtractMsg.py message' but I can't work out how to use this to loop through all the messages in the directory.
I have tried:
import ExtractMsg
import glob
for message in glob.glob('*.msg'):
print 'Reading', message
ExtractMsg(message)
This gives "'module' object is not callable". I have tried to look at the ExtractMsg module but the structure of it is beyond me at the moment. How can I make the module callable?
ExtractMsg(message)
You are trying to call module object - exactly what error message us telling you.
Perhaps you need to use ExtractMsg.Message class instead
msg = ExtractMsg.Message(message)
In the next link on the very bottom you will find example of usage
https://github.com/mattgwwalker/msg-extractor/blob/master/ExtractMsg.py
Thanks all - the following sorted it:
import ExtractMsg
import glob
for message in glob.glob('*.msg'):
print 'Reading', message
msg = ExtractMsg.Message(message)
body = msg._getStringStream('__substg1.0_1000')
sender = msg._getStringStream('__substg1.0_0C1F')

Categories

Resources