com_error when saving emails in windows outlook with python - python

I'm using python to save emails in a specified folder and complete the following:
check if the email is unread
save the email to target folder
mark the message as read
tell me how many messages were archived and the location
the code:
from win32com.client import Dispatch
import os
outlook = Dispatch('outlook.application').GetNamespace("MAPI")
root = outlook.Folders[0].Folders[27]
targetPath = os.path.expanduser(r'\\path\to\target\folder')
messages = root.Items
count = 0
for msg in messages:
if msg.UnRead:
msg.SaveAs(os.path.join(targetPath))
msg.UnRead = False
count +=1
print(str(count)+' emails archived to: '+targetPath)
I end up with this error i've never seen before, and I haven't had any luck with the google machine... so I come to stackoverflow and wake you from your slumber.
Traceback (most recent call last):
File "C:\Users\e582324\Documents\Python Scripts\untitled6.py", line 18, in <module>
msg.SaveAs(os.path.join(targetPath))
File "<COMObject <unknown>>", line 3, in SaveAs
com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'The operation failed.', None, 0, -2147024829), None)
Any idea whats causing this? I have a similar script that saves just attachments and it works fine. My target folder is on a network shared drive for both scripts and it hasn't caused an issue until now. Only real difference is the use of .SaveAs() instead of .SaveAsFile()

You need to specify the file name as well as its extension. passing the path is not enough sometimes, especially when you don't specify the format (see the second parameter). Note, an Outlook folder may contain different kind of items - mail items, appointments, documents, notes and etc. For example, here is a sample:
Item.SaveAs Environ("HOMEPATH") & "\My Documents\" & strname & ".txt", olTXT
Also I've noticed that you are iterating over all items in the folder:
for msg in messages:
if msg.UnRead:
Instead, you need to use the Find/FindNext or Restrict methods of the Items class. So, you get only items that correspond to your conditions and iterate only over 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

Related

Assistance debuging imaplib errors

Want to search folder "SPAM", for specific_user#any domain, and delete found mail.
Code below ...
import imaplib
box = imaplib.IMAP4_SSL('imap.mail.yahoo.com', 993)
box.login("xxxxxxxx#yahoo.com","xxxxxxxxxx")
box.select('SPAM')
typ, data = box.search(None, 'from','name#*.*')
for num in data[0].split():
box.store(num, '+FLAGS', '\\Deleted')
box.expunge()
box.close()
box.logout()
... is generating these errors below, please assist in debugging, thanks.
Traceback (most recent call last):
File "C:\Users\Desktop\Desktop\Python Spam Buster\test.py", line 6, in <module>
typ, data = box.search(None, 'from','name#*.*')
File "C:\Users\Desktop\AppData\Local\Programs\Python\Python310\lib\imaplib.py", line 734, in search
typ, dat = self._simple_command(name, *criteria)
File "C:\Users\Desktop\AppData\Local\Programs\Python\Python310\lib\imaplib.py", line 1230, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "C:\Users\Desktop\AppData\Local\Programs\Python\Python310\lib\imaplib.py", line 968, in _command
raise self.error("command %s illegal in state %s, "
imaplib.IMAP4.error: command SEARCH illegal in state AUTH, only allowed in states SELECTED
Issue is how to "search" folder using wildcard for domain.
Another issue is how to "select" any folder other then INBOX with yahoo mail!
For example, Gmail you would select SPAM folder as such '[Gmail]/Spam', but Yahoo mail is a mystery how you can access any folder other then INBOX using python imaplib.
SOLUTION:
Got off the phone with Yahoo Premium Support Engineer.
Yahoo mail has a unique way of generating the "Spam" folder filtering system, thus, folder scan would not display it!
Due to the above mentioned, 3rd party mailbox managers, can't access it by it's name, SO, an identical box called "Bulk" is generated, giving you access to all the contents of the "Spam" folder via "Bulk".
When I ran a scan for the folders/boxes, I didn't notice that I had an extra folder called "Bulk", that only appears via the scan, and can't be seen via the web browser.
I'm paraphrasing the above info from the engineer's explanation, hope it makes sense for anyone having the same issue.

Pywin32 update word document via scheduler

I have some simple code which opens a word document, updates the fields in it, then closes it. This code works correctly when I manually run it, however when I run it via the SQL Server Agent, I get an error. The user that SQL Server Agent runs with is the same user I am logged in with when running manually. I know the agent can 'see' the document because earlier code used in the task actually creates this document.
Code:
import win32com.client
word = win32com.client.DispatchEx("Word.Application")
filePath = "\\\\network\\data\\file.docx"
doc = word.Documents.Open(filePath)
doc.TablesOfContents(1).Update()
doc.Close(SaveChanges=True)
word.Quit()
Error:
Executed as user: DOMAIN\User. Traceback (most recent call last):
File "\\network\data\file.docx", line 8, in
doc.TablesOfContents(1).Update() AttributeError: 'NoneType' object
has no attribute 'TablesOfContents'
Why might this behavior happen?
For anyone in the future that might get this issue, I fixed it like this:
Open dcomcnfg Navigate to Component Services>Computers>My
Computer>DCOM Config>Microsoft Word 97-2003 Document
Right-click, click Properties
Select the Identity Tab
Select 'The Interactive User'

(Python3) How do you get the time stamp of a remote file in python (i.e. a web link)?

I have already seen the examples on here of using python's os library to get a local file's time stamp in python by passing it the local path (i.e. /var/www/html/etc.../filename.txt), but when I try to pass getmtime a link, it cannot process it.
Here is what the code looks like:
import os
print(os.path.getmtime('https://www.sec.gov/Archives/edgar/data/1474439/000169655519000022/xslF345X03/wf-form4_156772823294389.xml'))
Here is the error I get:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.7/genericpath.py", line 55, in getmtime
return os.stat(filename).st_mtime
FileNotFoundError: [Errno 2] No such file or directory: 'https://www.sec.gov/Archives/edgar/data/1474439/000169655519000022/xslF345X03/wf-form4_156772823294389.xml'
I know that this link exists.
So it obviously doesn't like me passing it a link. Is there another function that you use to pass links, to get the last modification time of a remote file?
An URL is not necessarily a file. You can ask the remote server to tell you about the link, and the remote server may provide a Last-Modified header, or may not, at the remote server's discretion. It could also lie, if so instructed. In order to do this, you would need to make a HTTP request; the easiest way to do it from Python is the nice requests library.
import requests
import dateutil.parser
response = requests.head(url)
last_modified = response.headers.get('Last-Modified')
if last_modified:
last_modified = dateutil.parser.parse(last_modified)

TypeError: '_Folders' object is not callable

I'm using win32.client and trying to manipulate email body text.
This was working today but I think when testing I might have broken Outlook! When I try to call an index of a _Folders object, I get a type error that it is uncallable.
I use indexes to get into my nested folders. This was working until tonight and I haven't changed any of the code.
import win32com.client
import urllib.parse
import webbrowser
from pyshorteners import Shortener
application = win32com.client.Dispatch('Outlook.Application')
namespace = application.GetNamespace('MAPI')
# 6 is the number for the main inbox
inbox_folder = namespace.GetDefaultFolder(6)
# had to create multiple objects of subfolders to get to specific directory
inbox = inbox_folder.Folders
mobile_folder = inbox(3)
mobile_folder_directory = mobile_folder.Folders
mobile_script_folder = mobile_folder_directory(2)
# using Items method to parse specific email files within the folder
messages = inbox_folder.Items
I get this error:
File "mail1.py", line 10, in mobile_folder = inbox_folders(3) TypeError: '_Folders' object is not callable
I was messing around with other code trying to monitor my inbox for new mail.
I ran some of this code in another file with some modifications to match my inboxes
import ctypes # for the VM_QUIT to stop PumpMessage()
import pythoncom
import win32com.client
import sys
# outlook config
SHARED_MAILBOX = "Your Mailbox Name"
# get the outlook instance and inbox folder
session = win32com.client.Dispatch("Outlook.Application").Session
user = session.CreateRecipient(SHARED_MAILBOX)
shared_inbox = session.GetSharedDefaultFolder(user, 6).Items # 6 is Inbox
class HandlerClass(object):
def OnItemAdd(self, item):
print("New item added in shared mailbox")
if item.Class == 43:
print("The item is an email!")
outlook = win32com.client.DispatchWithEvents(shared_inbox, HandlerClass)
def main():
print("Starting up Outlook watcher")
pythoncom.PumpMessages()
if __name__ == "__main__":
try:
status = main()
sys.exit(status)
except KeyboardInterrupt:
print("Terminating program..")
ctypes.windll.user32.PostQuitMessage(0)
sys.exit()
My suspicion is that it changed something with Outlook versions.
I also got something saying that a MAPIFolder object isn't callable. My research was showing this is an old, unsupported Outlook protocol.
Here's more data when I try to index my folders:
>>> inbox_folder
<win32com.gen_py.Microsoft Outlook 16.0 Object Library.MAPIFolder instance at 0x12191504>
>>> inbox = inbox_folder.Folders
>>> inbox
<win32com.gen_py.Microsoft Outlook 16.0 Object Library._Folders instance at 0x46668848>
>>> inbox(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '_Folders' object is not callable
I still don't know what broke it, but it turns out that searching folders by index wasn't working anymore.
The solution was now searching by folder name:
inbox_folder = namespace.GetDefaultFolder(6)
# had to create multiple objects of subfolders to get to specific directory
inbox = inbox_folder.Folders
mobile_folder = inbox["Mobile"]
mobile_script_folder = mobile_folder.Folders["Mobile_4_4_Alpha"]
not sure why it fixed it but it did. yay!
don't know why but delete this file work in my case.
C:\Users\[user name]\AppData\Local\Temp\gen_py\[python version]\00062FFF-0000-0000-C000-000000000046x0x9x6.py
credit: https://blog.csdn.net/ericatardicaca/article/details/90721909

Python suds error creating object

Trying to work with the echosign SOAP API.
The wsdl is here: https://secure.echosign.com/services/EchoSignDocumentService14?wsdl
When I try to create certain objects, it appears to not be able to find the type, even after listing it in print client
import suds
url = "https://secure.echosign.com/services/EchoSignDocumentService14?wsdl"
client = suds.client.Client(url)
print client
Service ( EchoSignDocumentService14 ) tns="http://api.echosign"
Prefixes (10)
ns0 = "http://api.echosign"
ns1 = "http://dto.api.echosign"
ns2 = "http://dto10.api.echosign"
ns3 = "http://dto11.api.echosign"
ns4 = "http://dto12.api.echosign"
ns5 = "http://dto13.api.echosign"
ns15 = "http://dto14.api.echosign"
ns16 = "http://dto7.api.echosign"
ns17 = "http://dto8.api.echosign"
ns18 = "http://dto9.api.echosign"
Ports (1):
(EchoSignDocumentService14HttpPort)
Methods (45):
...
Types (146):
ns1:CallbackInfo
ns17:WidgetCreationInfo
Trimmed for brevity, but showing the namespaces and the 2 types I'm concerned with right now.
Trying to run WCI = client.factory.create("ns17:WidgetCreationInfo") generates this error:
client.factory.create("ns17:WidgetCreationInfo")
Traceback (most recent call last):
File "", line 1, in
File "build/bdist.macosx-10.7-intel/egg/suds/client.py", line 244, in create
suds.BuildError:
An error occured while building a instance of (ns17:WidgetCreationInfo). As a result
the object you requested could not be constructed. It is recommended
that you construct the type manually using a Suds object.
Please open a ticket with a description of this error.
Reason: Type not found: '(CallbackInfo, http://dto.api.echosign, )'
So it doesn't appear to be able to find the CallbackInfo type. Maybe its because its missing the ns there?
Again, figured it out 15 min after posting here.
suds has an option to cross-pollinate all the namespaces so they all import each others schemas. autoblend can be set in the constructor or using the set_options method.
suds.client.Client(url, autoblend=True)
Take a look in the WSDL, it seems lots of definitions in http://*.api.echosign that suds cannot fetch.
Either update your /etc/hosts to make these not well-formed domains can be reached, or save the wsdl locally, modify it, then use Client('file://...', ...) to create your suds client.

Categories