Below is my code:
import win32com.client
import os
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) # "6" refers to the index of a folder - in this case the inbox. You can change that number to reference
messages = inbox.Items
message = messages.GetFirst()
subject = message.Subject
body = message.body
#
get_path = 'C:\\Users\\username\\Downloads'
for m in messages:
if m.Subject == "Dummy report":
attachments = message.Attachments
num_attach = len([x for x in attachments])
for x in range(1, num_attach):
attachment = attachments.Item(x)
attachment.SaveAsFile(os.path.join(get_path,attachment.FileName))
print (attachment.FileName)
break
else:
message = messages.GetNext()
Please let me know what is wrong with this code. I was able to find the specific mail but I was not able to download the attachment associated with that mail.
CodePudding user response:
First, the subject line may contain forbidden symbols for file names. Make sure the file name string is safe. The file will not be saved if the string contains any forbidden symbols.
Second, it makes sense to check the Attachment.Type property which returns an OlAttachmentType
constant indicating the type of the specified object. Make sure that you deal with real attached files by making sure the property is set to the olByValue
value.
Third, make sure the FileName
property is not empty. In some cases you may need to use the DisplayName
property value instead.
Fourth, direct comparison of the subject line is not the best way to find items with a specified subject line. It may be prepended with RE: or FW: prefixes.
for m in messages:
if m.Subject == "Dummy report":
Instead, you need to use the Find
/FindNext
or Restrict
methods of the Items
class. They allow getting items that correspond to your conditions without iterating over all items in the folder. Read more about these methods in the articles I wrote for the technical blog:
- 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
For example, you could use the following search criteria (VBA syntax):
criteria = "@SQL=" & Chr(34) _
& "urn:schemas:httpmail:subject" & Chr(34) _
& " ci_phrasematch 'question'"
This example shows Equivalence Matching, assuming that the folder you are searching contains items with the following subjects:
Question
Questionable
Unquestionable
RE: Question
The big question
If a store is indexed, searching with content indexer keywords is more efficient than with like. If your search scenarios include substring matching (which content indexer keywords don't support), use the like keyword in a DASL query.
Read more about that in the Filtering Items Using a String Comparison article.
CodePudding user response:
Taking on board some of @Eugene Astafiev's points, this code will iterate over the Inbox for a matching subject:
import win32com.client as wc
from os.path import join
ol = wc.gencache.EnsureDispatch('Outlook.Application')
ns = ol.GetNamespace('MAPI')
inbox = ns.GetDefaultFolder(wc.constants.olFolderInbox)
items = inbox.Items
pattern = 'Dummy report'
criteria = '@SQL="urn:schemas:httpmail:subject" like \'%' pattern '%\''
msg = items.Find(criteria)
while msg is not None:
for att in msg.Attachments:
if att.Type == wc.constants.olByValue:
att.SaveAsFile(join('c:\\temp',att.FileName))
print(att.FileName)
msg = items.FindNext()
I have to say that I did try to use ci_phrasematch
with Find, as suggested, but it would not work for me (even cutting & pasting the MS example into VBA). The keyword like
does seem to work though.
NB. By using EnsureDispatch
to create the Outlook object, you can access the Outlook enumerated constants from the documentation (such as olFolderInbox
and olByValue
) without resorting to magic numbers.