How to fix OLE error while parsing emails - python

I am facing an OLE error while my outlook is being parsed through python using win32com module.
Traceback (most recent call last):
for i, message in enumerate(messages):
pywintypes.com_error: (-520879857, 'OLE error 0xe0f4010f', None, None)
I believe this is due to a network connection which might be restarting after a particular amount of time.
inbox= win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI").Folders["Inbox"]
messages = inbox.Items
for i, message in enumerate(messages):

Iterating through all items in the folder is not really a good idea:
for i, message in enumerate(messages):
Instead, I'd suggest getting a subset of items and process them in a batch. For example, you can use the Find/FindNext or Restrict methods to get a subset of items (according to your conditions) and process them. 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
Also, you may consider using the AdvancedSearch method of the Application class. The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.

Related

pywin32 - restrict, filtering by a list of potential senders

I need to iterate through every email within my project. I have more than 20000 mails. Therefore i read I need to use the restrict function. I found examples how to restrict to one specific domain
messages = messages.Restrict("#SQL=(urn:schemas:httpmail:SenderEmailAddress LIKE '%#domain.com')")
What do I need to use if have more than 100 domains or multiple (more than 100) Senders I want to use? Would it be a huge restrict function with logical OR connectors with all of the domains or can I input somehow a list into the restrict statement?
EDIT:
and i realized if i run a restrict function with this code, it just shows me with the len(messages) function that there are 0 emails while i can see a bunch of emails in outlook with used domain in the filter. what am i doing wrong?
Typically you would need to use the logical OR operator in the search string. Read more about that in the Filtering Items Using a String Comparison article. Also you may find the following articles helpful:
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
But I would recommend handling each domain separately, so you will get Outlook running without freezes and will be able to process items in a logical bunch, especially when you have a hundred of domain names to search for.
If you want to filter out internal senders and only process the senders outside your organization, check the SenderEmailType property - it will be "EX" for the internal senders (assuming you are using Exchange Server) and "SMTP" for the external senders.

Python Outlook how to handle recall email

My project works on emails in Inbox. When process get a "Recall" email it crashes. Recall email does not have subject attribute. I want to write some error handling. I cannot find method to move email to another folder or delete such email from Outlook.
Currently my Code skip such items using method GetPrevious() but the email is still in Inbox
Do you have any ideas how to make 'recall' email disappear from Inbox folder?
obj_emails = obj_inbox.Items
obj_email = obj_emails.GetLast()
if obj_email.MessageClass == 'IPM.Outlook.Recall':
obj_email = obj_emails.GetPrevious()
The Outlook object model doesn't provide anything for handling or generating recall items. You may consider using a low-level API on which Outlook is based on - Extended MAPI. Also you may consider using thied-party components, i.e. wrappers around the low-level API such as Redemption.
Try to play with MFCMAPI to make sure recall items can be easily handled (moved or removed).
Check the Class property - all OOM objects expose it. For the MailItem, it will be 43 (OlObjectClass.olMail). For ReportItem - 46 (OlObjectClass.olReport)
Thank you for your suggestion.
I do not want to complicate the code so I use MessageClass property to catch recall email. Next information will be sent to team to remove such email.
if obj_email.MessageClass == 'IPM.Outlook.Recall':
raise Exception(f"There is a recall email in mailbox. Please remove it from inbox.")

Prevent multiple service access same document in MongoDB till processing is done

I have multiple instances of a services. This service access a collection of unprocessed document. We are using MongoDB. The role of service is :
Fetch the first unprocessed document from collection A.
Make a Rest call using uuid.
Get the response and store the response in another collection B.
Multiple service may access the same document leading to duplicate. The steps which I can think to deal with this situation:
FindandModify() along with progress field. So we will call this function with query of progress field to be "0". We will update the value to 1 so other services can not access it. On getting the success from Rest call we can delete the record. On getting the failure we will again call the FindandModify() with update value to be "0" so other service can access at later time.
We we call Find() function which will give us one document. We get the "_id" of the document and store it into another collection. If another service also gets the same document and that document "_id" is already present. Then it will not be insert again and that service again call Find() function.
What would be the performance and bottleneck of these approaches. Also do we have any other better approach which will enhance the performance.
FindandModify() along with progress field. So we will call this function with query of progress field to be "0". We will update the value to 1 so other services can not access it. On getting the success from Rest call we can delete the record. On getting the failure we will again call the FindandModify() with update value to be "0" so other service can access at later time.
This solution is OK and is simpler and faster than the second.
We we call Find() function which will give us one document. We get the "_id" of the document and store it into another collection. If another service also gets the same document and that document "_id" is already present. Then it will not be insert again and that service again call Find() function.
This solution (as you presented) would not work unless the document is removed from the first collection after it is inserted in the second, otherwise the processes will be caught in an infinite loop. The drawback is that this solution implies two collections and the document moving process.
In any case, you must take into account the failure of the processes in any of the phases and you must be able to detect failure and recover from it.

Protocols list in Twisted app

I would like to know which is best way to manage the protocols active in Twisted or if there is no concrete way.
In my current app I created a dictionary where there are two fields. At one I put the remote user and the local user to another. Both fields are lists so I can add several items.
The method I'm using is the following. First I check by a try-except if the dictionary exists. If there is no dictionary, I create it.
try:
if self.factory.active_protocols:
log.msg('Active protocols dictionary already created')
except Exception as e:
log.err(e)
self.factory.active_protocols = {}
self.factory.active_protocols.setdefault('localUsr', [])
self.factory.active_protocols.setdefault('remoteUsr', [])
Then I check if the local user is in the local users list. If there is no user I adds it to the list of local users. If the list exists, it throws an error.
if sUsername in self.factory.active_protocols['localUsr']:
log.err('Client already logged in')
raise UnauthorizedLogin('Client already logged in')
else:
# Attach local user to active protocols list.
self.sUsername = sUsername
self.factory.active_protocols['localUsr'].append(self.sUsername)
If the conditions are right the remote user is also added to the list of remote users using the following code.
# If time is correct, attach remote user to active_protocols
self.factory.active_protocols['remoteUsr'].append(remoteUsr)
When I disconnect users, I delete the lists using the following code.
if self.sUsername in self.factory.active_protocols['localUsr']:
self.factory.active_protocols['localUsr'] = []
if self.remoteUsr in self.factory.active_protocols['remoteUsr']:
self.factory.active_protocols['remoteUsr'] = []
Is there a more correct way to do it? Should implement some special kind of dictionary? To Create a list? Does using a proprietary method of Twisted?
I have been looking for information about internet and I have not found anything conclusive about it.
Thank you!
No, there is no special type of list or dictionary in Twisted you can use for this.
Twisted's job is turning network events into method calls on your objects. Once you you are implementing those methods on those objects, as much as possible, you want to use regular Python data structures. There are certain things in Twisted, like Deferreds, which are data structures you can use to implement certain asynchronous data-flow patterns, but for something as simple as a basic observer pattern with multiple entities in a list, regular lists and dictionaries and such are just fine.

Use python to detect outlook auto-responder before sending message

I have found many resources on inspecting the headers in an email to detect whether or not the message was sent using an auto-responder. I'm looking to detect that an auto-responder is configured before any contact is made.
Why I think this is possible: In outlook, if you add a recipient from the address book it will show their auto-responder message above the "To:" line before even clicking send.
Goal: I would like to pass a list of employees to a function and return a binary list of whether or not they are in the office based on auto-responder on/off status.
Some bad psuedo-code (please excuse the mixing of classes and lists, it's just for a simple example).
list = ['Ted Jones', 'Michael Brickman', 'This name', 'That name']
for employee in list:
if employee.autoresponse != '':
employee.inoffice = 0
output = [0,1,1,1] #-- So, Ted Jones is out of the office
I'm certainly not stuck on this style of output, just trying to be specific. I need some sort of ordered list or something to tie Name -> In/Out of office
I would like to stay in Python if possible, but am interested to hear other solutions.
Is there anyway to do this? Maybe using win32com or pyad? If a resource for this information exists please let me know... I was unable to find it among the 'check the headers' muck.
You will have to either use Outlook's automation interface, or do the same thing Outlook does (presumably via MAPI or AD), or do the equivalent with some other API.
You can use win32com for the first of the three.
When you add a recipient to the To list in Outlook, it's getting a Recipient object, which has an AutoResponse property, which Outlook will show you.
The easiest (if maybe not the cleanest) way to get a Recipient object through the OOM is to do the exact same thing: create a dummy message, add a recipient, then look at its properties. Items have Recipients objects, which have an Add method that takes an identifier and returns a Recipient (and adds it to the item's recipients, of course).
So, the code should look something like this (untested because I don't have a Windows/Outlook box connected to Exchange here):
session = win32com.client.Dispatch("Mapi.Session")
session.Logon(MY_PROFILE)
outlook = win32com.client.Dispatch("Outlook.Application")
message = outlook.CreateItem(0) # olMailItem
autoresponses = {}
for name in names:
recipient = message.Recipients.Add(name)
autoresponses[name] = recipient.AutoResponse
You can of course combine that into a one-liner dict comprehension, but I thought this might be clearer. Also, you probably want to discard the message so Outlook doesn't end up sticking your leftover garbage in Drafts or something, and you probably want some error handling, and you may need to use a separate message for each recipient to make it easier to recover from errors and move on, and so on… But this, together with the MSDN and win32com docs, should be enough to get you going.
Of course this only works if name resolves to a server mailbox; if you give a local-only name or address, or external-only address, you'll just let a local address book entry or a bare email entry, neither of which have an AutoResponse. But that's exactly the same as in Outlook, so presumably it's expected.
Also note that the first time your script does anything that tries to access the Address Book, unless the user has deliberately turned off the default safety features, he will get a popup like "A program is trying to access e-mail addresses you have stored in Outlook. Do you want to allow this?"

Categories

Resources