Python Forum
download base64 email attachment
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
download base64 email attachment
#1
Hey,

New to coding. New to python. I have been using home assistant to do some automation stuff at my place. But my lorex NVR is not natively supported. It does send a email notification on motion detection. I have been able to decode the email body with a python script ran inside the home assistant api (gmail is supported in home assistant.) But now i would like to download the attached email picture. I have been able to piece together a bit of code that can download attachments from non-base64 emails. But I haven't found anything that works for the encoded ones.

Here is what I have so far.

import imaplib
import email
import os

svdir = 'c:/save/temp'

mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)
mail.login("hidden","hidden")
mail.select("Inbox")

typ, data = mail.search(None, 'SEEN')
for num in data[0].split():
   mail.store(num, '+FLAGS', '\\deleted')

mail.expunge()

typ, msgs = mail.search(None, 'ALL')
msgs = msgs[0].split()

for emailid in msgs:
    resp, data = mail.fetch(emailid, "(RFC822)")
    email_body = data[0][1]
    m = email.message_from_bytes(email_body)

    if m.get_content_maintype() != 'multipart': continue

    for part in m.walk():
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Disposition') is None: continue

        filename = part.get_filename()
        if filename is not None:
            sv_path = os.path.join(svdir, filename)
            if not os.path.isfile(sv_path):
                print(sv_path)
                fp = open(sv_path, 'wb')
                fp.write(part.get_payload(decode=True))
                fp.close()

mail.close()
mail.logout()
It also only leaves one email in the account by design. Can anyone help me so I can get this to download any and all email attachments regardless of the encoding?

the svdir in the above code is what I am using in spyder for testing. But the version I run in home assistant works the same the correctly defined dir.

Thanks.

I have been able to run this code and identify the attachment.

import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)
mail.login("hidden","hidden")
mail.select('inbox')
result, data = mail.uid('search', None, 'ALL')
uids=data[0].split()
result, data = mail.uid('fetch', uids[-1], 'BODYSTRUCTURE')
print(data)
it returns
Output:
[b'1 (UID 5424 BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "utf-8") NIL NIL "BASE64" 128 3 NIL NIL NIL)("IMAGE" "JPG" ("NAME" "Motion_CAM01_20200223_094803.jpg") NIL NIL "BASE64" 198074 NIL NIL NIL) "MIXED" ("BOUNDARY" "====my_split_tag====") NIL NIL))']
Reply
#2
Woo I got a result! not I just gotta figure out how to decode it and turn it into a proper picture!

import imaplib
import email
import base64
import os

svdir = 'c:/save/temp'

mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)
mail.login("","")
mail.select("Inbox")

#typ, data = mail.search(None, 'SEEN')
#for num in data[0].split():
#   mail.store(num, '+FLAGS', '\\deleted')

#mail.expunge()

typ, msgs = mail.search(None, 'ALL')
msgs = msgs[0].split()

for emailid in msgs:
    resp, data = mail.fetch(emailid, "(RFC822)")
    email_body = data[0][1]
    m = email.message_from_bytes(email_body)
    print((data)[0][1]) #added this and the output was a raw base64 string I 
                        #was able to repair and decode on a website. Returned 
                        #the actual image! Now I just need to decode it and 
                        #save it as a file I guess.
    if m.get_content_maintype() != 'multipart': continue

    for part in m.walk():
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Disposition') is None: continue

        filename = part.get_filename()
        if filename is not None:
            sv_path = os.path.join(svdir, filename)
            if not os.path.isfile(sv_path):
                print(sv_path)
                fp = open(sv_path, 'wb')
                fp.write(part.get_payload(decode=True))
                fp.close()

mail.close()
mail.logout()
Reply
#3
still struggling with this.

    for part in m.walk():
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Transfer-Encoding') is None: continue

        filename = part.get_filename()
        filename = str(filename.strip('=?utf-8?b?)')
        filename = base64.b64decode(filename).decode('utf-8')
I tried this but I can't seem to figure out how to decode the output

(Feb-24-2020, 05:40 PM)cferguson Wrote: still struggling with this.

    for part in m.walk():
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Transfer-Encoding') is None: continue

        filename = part.get_filename()
        filename = str(filename.strip('=?utf-8?b?'))
        filename = base64.b64decode(filename).decode('utf-8')
I tried this but I can't seem to figure out how to decode the output

*correction
Reply
#4
I DID IT. WOO.

import imaplib
import email
import base64
import os

svdir = 'c:/save/temp'

def sender_decode(sender):
    parsed_string = sender.split("?")
    decoded = base64.b64decode(parsed_string[3]).decode(parsed_string[1], "ignore")
    return decoded

mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)
mail.login("HIDDEN","HIDDEN")
mail.select("Inbox")

typ, data = mail.search(None, 'SEEN')
for num in data[0].split():
   mail.store(num, '+FLAGS', '\\deleted')

mail.expunge()

typ, msgs = mail.search(None, 'UNSEEN')
msgs = msgs[0].split()

for emailid in msgs:
    resp, data = mail.fetch(emailid, "(RFC822)")
    email_body = data[0][1]
    m = email.message_from_bytes(email_body)
    if m.get_content_maintype() != 'multipart': continue

    for part in m.walk():
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Transfer-Encoding') is None: continue

        filename: str = part.get_filename()
        if filename is None: continue
        try:
            filename = sender_decode(filename)
        except IndexError:
            filename = part.get_filename()
        if filename is not None:
            sv_path = os.path.join(svdir, filename)
            if not os.path.isfile(sv_path):
                fp = open(sv_path, 'wb')
                fp.write(part.get_payload(decode=True))
                fp.close()

mail.close()
mail.logout()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Unable to download TLS Report attachment blason16 6 550 Feb-26-2024, 07:36 AM
Last Post: Pedroski55
  Extract PDF Attachment from Gmail jstaffon 0 584 Sep-10-2023, 01:55 PM
Last Post: jstaffon
  I get attachment paperclip on email without any attachments monika_v 5 1,985 Mar-19-2022, 10:20 PM
Last Post: cosmarchy
  Trying to determine attachment file type before saving off.. cubangt 1 2,160 Feb-23-2022, 07:45 PM
Last Post: cubangt
  Help Needed | Read Outlook email Recursively & download attachment Vinci141 1 4,088 Jan-07-2022, 07:38 PM
Last Post: cubangt
  download with internet download manager coral_raha 0 2,959 Jul-18-2021, 03:11 PM
Last Post: coral_raha
  Clicking Every Page and Attachment on Website shoulddt 1 1,743 Jul-09-2021, 01:08 PM
Last Post: snippsat
  ATT00001 instead of PDF attachment to an email dominiklucas 0 3,774 Jul-25-2020, 04:05 PM
Last Post: dominiklucas
  Sending an email with attachment without using SMTP? PythonNPC 5 3,207 May-05-2020, 07:58 AM
Last Post: PythonNPC
  Base64 to retrieve message JonasH 0 1,653 Jul-22-2019, 04:00 PM
Last Post: JonasH

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020