1

How do I save an email attachement as a tempfile? FYR I am trying to read data from a zipped xls attachment and I don't need both the xls and zip file in the end. Thank you.

My code fyr: (Right now I think I am just saving the attachment with a tempfile name as a normal file. You can see I even have to os.remove the saved attachment at the end)

import tempfile

import win32com.client

import zipfile

import os

#from openpyxl import Workbook, load_workbook


outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

inbox = outlook.Folders("John@gmail.com").Folders("Inbox")

msgs = inbox.Items

msgs.Sort('ReceivedTime',True)

tf=tempfile.TemporaryFile()

tfn=tempfile.TemporaryFile().name

td=tempfile.gettempdir()
 

for msg in msgs:

    atts=msg.Attachments

    if "ABCD" in str(msg.Subject):

        for att in atts:

            att.SaveAsFile (tfn)

        break

file=zipfile.ZipFile(tfn)

file.extractall(td)

file.close()

os.remove(tfn)

2 Answers2

0

The Attachment.SaveAsFile method saves the attachment to the specified path. The location at which to save the attachment (a file path string) should be passed as a parameter. Make sure the file path is valid:

tfn=tempfile.TemporaryFile().name

att.SaveAsFile (tfn)

There should be a file path, not just a file name.

Also I have noticed that your code iterates over all items in the folder:

for msg in msgs:

    atts=msg.Attachments

    if "ABCD" in str(msg.Subject):

        for att in atts:

Instead, you need to use the Find/FindNext or Restrict methods of the Items class that allow getting items corresponding to the search criteria. You can read more about these methods in the articles that I wrote for the technical blog:

For example, the following query performs a phrase match query for ABCD in the message subject:

filter = "@SQL=" & Chr(34) & "https://schemas.microsoft.com/mapi/proptag/0x0037001E" _
    & Chr(34) & " ci_phrasematch " & "ABCD"
Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
  • Thanks Eugene. The tfn=tempfile.TemporaryFile().name actually returns a full path (eg: C:\Users\John\AppData\Local\Temp\tmpu7g21d5k) on my computer. I should defnitely look into the Find/FindNext methods and example you provided. Thank you very much. – BluePowPowJones Mar 08 '23 at 14:26
  • You need to pass a *file path*, not just a `folder path`. – Eugene Astafiev Mar 08 '23 at 14:52
  • It actually passes a file path. The code works fine yet I am wondering if this is the right way of using tempfile module since the file saved won't delet itself like normal tempfile does. – BluePowPowJones Mar 09 '23 at 07:11
0

Since not getting an answer, I will share my current workaround code for ppl interested, which includes using TemporaryDirectory

import win32com.client
import tempfile
import zipfile
import os

outlook=win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox=outlook.Folders("John@mail.com").Folders("Inbox")
msgs=inbox.Items
msgs.Sort('ReceivedTime',True)
td=tempfile.TemporaryDirectory()
tdn=td.name
tfn=tempfile.TemporaryFile(dir=tdn).name

'''don't know why tfn can't be replaced by
tf=tempfile.TemporaryFile(dir=tdn)
tfn=tf.name
'''

for msg in msgs:
  atts=msg.Attachments
  if "ABC" in str(msg.Subject):
    for att in atts:
      att.SaveAsFile(tfn)
    break
file=zipfile.ZipFile(tfn)
file.extractall(tdn)
file.close()