13

I need to download incoming attachment without past attachment from mail using Python Script.

For example:If anyone send mail at this time(now) then just download that attachment only into local drive not past attachments.

Please anyone help me to download attachment using python script or java.

noswear
  • 311
  • 1
  • 6
  • 27
Mister X
  • 3,406
  • 3
  • 31
  • 72

4 Answers4

17

The below code helps by downloading the attachments from outlook emails that are

  • 'Unread' (and changes the mail to Read.) or from 'Today's' date.
  • without altering the file name.

Just pass the 'Subject' argument.

import datetime
import os
import win32com.client


path = os.path.expanduser("~/Desktop/Attachments")
today = datetime.date.today()

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) 
messages = inbox.Items


def saveattachemnts(subject):
    for message in messages:
        if message.Subject == subject and message.Unread or message.Senton.date() == today:
            # body_content = message.body
            attachments = message.Attachments
            attachment = attachments.Item(1)
            for attachment in message.Attachments:
                attachment.SaveAsFile(os.path.join(path, str(attachment)))
                if message.Subject == subject and message.Unread:
                    message.Unread = False
                break
Ashwaq
  • 431
  • 7
  • 17
  • 1
    Running this code I get an 'Your Digital ID name cannot be found by the underlying security system.' error - which seems to be tied to encryption. Do you know if there's a way around this? Like only extracting attachments from unenrcptyed emails, or somehow adding your public key to win32? – Evan Mata Apr 22 '19 at 18:28
  • 1
    Using your code, gives me error `com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'Array index out of bounds.', None, 0, -2147352567), None)` – Andre_k Feb 04 '20 at 10:18
  • How do you make it download multiple attachments from one email? – Aps Aug 06 '21 at 13:48
  • To save multiple attachments remove the last break statement. Got an error on the Senton attribute for the message object. Seems like this one maybe has changed to SentOn: https://learn.microsoft.com/en-us/office/vba/api/outlook.mailitem.senton. Otherwise code works as a charm. – Torgrim Brochmann Oct 15 '21 at 10:34
  • Hi, this works for me but I want to know if I can set the mail address from where I want to download files. I have two corporative mails and I can download only from one with win32com library. Can I set the mail address to download files from anyone? – MARIO ANTONIO CASTILLO MACHUCA Apr 26 '22 at 14:05
6
import email
import imaplib
import os

class FetchEmail():

connection = None
error = None
mail_server="host_name"
username="outlook_username"
password="password"
self.save_attachment(self,msg,download_folder)
def __init__(self, mail_server, username, password):
    self.connection = imaplib.IMAP4_SSL(mail_server)
    self.connection.login(username, password)
    self.connection.select(readonly=False) # so we can mark mails as read

def close_connection(self):
    """
    Close the connection to the IMAP server
    """
    self.connection.close()

def save_attachment(self, msg, download_folder="/tmp"):
    """
    Given a message, save its attachments to the specified
    download folder (default is /tmp)

    return: file path to attachment
    """
    att_path = "No attachment found."
    for part in msg.walk():
        if part.get_content_maintype() == 'multipart':
            continue
        if part.get('Content-Disposition') is None:
            continue

        filename = part.get_filename()
        att_path = os.path.join(download_folder, filename)

        if not os.path.isfile(att_path):
            fp = open(att_path, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()
    return att_path

def fetch_unread_messages(self):
    """
    Retrieve unread messages
    """
    emails = []
    (result, messages) = self.connection.search(None, 'UnSeen')
    if result == "OK":
        for message in messages[0].split(' '):
            try: 
                ret, data = self.connection.fetch(message,'(RFC822)')
            except:
                print "No new emails to read."
                self.close_connection()
                exit()

            msg = email.message_from_string(data[0][1])
            if isinstance(msg, str) == False:
                emails.append(msg)
            response, data = self.connection.store(message, '+FLAGS','\\Seen')

        return emails

    self.error = "Failed to retrieve emails."
    return emails

Above code works for me to download attachment. Hope this really helpful for any one.

Andre Silva
  • 4,782
  • 9
  • 52
  • 65
Mister X
  • 3,406
  • 3
  • 31
  • 72
  • 1
    Do you know how to get this to work for company emails? Like yourname@company.com? This works perfectly fine for basic outlook or gmail accounts, but I can't figure out emails. – Evan Mata Apr 24 '19 at 14:33
  • 2
    Hope it get worked for company emails also. Just try with your company account and write to me if you face any issues. – Mister X Apr 25 '19 at 05:19
  • @MahendraPrabhu please help, I am getting same indentation error – Lynn Sep 27 '20 at 23:38
5
import win32com.client #pip install pypiwin32 to work with windows operating sysytm
import datetime
import os

# To get today's date in 'day-month-year' format(01-12-2017).
dateToday=datetime.datetime.today()
FormatedDate=('{:02d}'.format(dateToday.day)+'-'+'{:02d}'.format(dateToday.month)+'-'+'{:04d}'.format(dateToday.year))

# Creating an object for the outlook application.
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# Creating an object to access Inbox of the outlook.
inbox=outlook.GetDefaultFolder(6)
# Creating an object to access items inside the inbox of outlook.
messages=inbox.Items

def save_attachments(subject,which_item,file_name):
    # To iterate through inbox emails using inbox.Items object.
    for message in messages:
        if (message.Subject == subject):
            body_content = message.body
            # Creating an object for the message.Attachments.
            attachment = message.Attachments
            # To check which item is selected among the attacments.
            print (message.Attachments.Item(which_item))
            # To iterate through email items using message.Attachments object.
            for attachment in message.Attachments:
                # To save the perticular attachment at the desired location in your hard disk.
                attachment.SaveAsFile(os.path.join("D:\Script\Monitoring",file_name))
                break
Abhay Singh
  • 203
  • 1
  • 5
  • 11
  • Running this code I get an 'Your Digital ID name cannot be found by the underlying security system.' error - which seems to be tied to encryption. Do you know if there's a way around this? Like only extracting attachments from unencrypted emails, or somehow adding your public key to win32? (Source for understanding error: https://knowledge.digicert.com/solution/SO4972.html) – Evan Mata Apr 23 '19 at 13:50
2

If you want to download the attachment from the outlook application from a particular sender and with a specific subject. The below code may be helpful.

import win32com.client
import os
from datetime import datetime, timedelta
outlook = win32com.client.Dispatch('outlook.application')
mapi = outlook.GetNamespace("MAPI")
for account in mapi.Accounts:
    print(account.DeliveryStore.DisplayName) #outlook account
inbox = mapi.GetDefaultFolder(6) #Inbox folder
inbox = inbox.Folders["your folder"] #Folder inside Inbox Folder
messages = inbox.Items 
received_dt = datetime.now() - timedelta(days=1)
received_dt = received_dt.strftime('%m/%d/%Y %H:%M %p')
email_sender = 'sender@outlook.com'
email_subject = 'Subject of mail'
messages = messages.Restrict("[ReceivedTime] >= '"+received_dt+"'")
#save to current directory
outputDir = os.getcwd()
try:
    for message in list(messages):
        if email_subject == message.subject and message.SenderEmailAddress == email_sender and message.ReceivedTime.strftime('%Y-%m-%d') == _date:
            try:
                s = message.sender
                for attachment in message.Attachments:
                    attachment.SaveASFile(os.path.join(outputDir, attachment.FileName))
                    print(f"attachment {attachment.FileName} from {s} saved")
            except Exception as e:
                print("Error when saving the attachment:" + str(e))
except Exception as e:
    print("Error when processing emails messages:" + str(e))
RITA KUSHWAHA
  • 351
  • 3
  • 7
  • Hi, your code has come indentation problem and unrequired return statement , fix it so that other can use it., Do check for syntax error before posting it. – Abhishek Jul 17 '21 at 07:05
  • Hi @Abhishek, I have made the required changes. Thanks for letting me know. – RITA KUSHWAHA Jul 20 '21 at 14:10