James Cook
James Cook

Reputation: 344

Decoding zip file returned from MS Graph API as content Bytes

I have a connection to an organization's mailbox. Using the MS Graph API, the response from the API returns the given message's attachment as content bytes. The issue I'm having is that the attachment is within a .zip. There is only 1 file in the .zip which is of type .txt

So with just the .txt file as the attachment not in the .zip the content-bytes returned is

dGhpcyBpcyBzb21lIHRlc3QgdGV4dA==

Using something like:

def getAttachmentFromMailMessage(mailId, headers):
    url  = inboxFolderPricingFiles + '/' + mailId + '/' +'attachments'
    response = requests.request('GET', url, headers = headers)
    content = json.loads(response.text)['value'][0]['contentBytes']
    txtString = base64.b64decode(content).decode('utf-8')
    return txtString

Returns :

this is some test text

But when I get the content-bytes of the .zip file the API returns

UEsDBAoAAAAAAHZXRlMb8/ygFgAAABYAAAAIAAAAdGVzdC50eHR0aGlzIGlzIHNvbWUgdGVzdCB0ZXh0UEsBAj8ACgAAAAAAdldGUxvz/KAWAAAAFgAAAAgAJAAAAAAAAAAgAAAAAAAAAHRlc3QudHh0CgAgAAAAAAABABgAv57iEEW61wG/nuIQRbrXAcZ34hBFutcBUEsFBgAAAAABAAEAWgAAADwAAAAAAA==

Using the same code as above:

def getAttachmentFromMailMessage(mailId, headers):
    url  = inboxFolderPricingFiles + '/' + mailId + '/' +'attachments'
    response = requests.request('GET', url, headers = headers)
    content = json.loads(response.text)['value'][0]['contentBytes']
    txtString = base64.b64decode(content).decode('utf-8')
    return txtString

I get an error :

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf3 in position 15: invalid continuation byte

Given I don't have a "file-like" object to deal with and instead need to use the returned content-bytes from the API I'm unsure how to make this work...

Upvotes: 1

Views: 1064

Answers (1)

ogdenkev
ogdenkev

Reputation: 2374

When the attachment is a zip file, then the bytes you get will be the contents of the zip file. You can wrap those bytes with io.BytesIO to create a file-like object and then pass that file-like object to zipfile.ZipFile to properly read the contents of the zip file. Here is a modify version of your function that should work in this scenario.

import zipfile

def getAttachmentFromMailMessage(mailId, headers):
    url  = inboxFolderPricingFiles + '/' + mailId + '/' +'attachments'
    response = requests.request('GET', url, headers = headers)
    content = json.loads(response.text)['value'][0]['contentBytes']
    content_bytes = base64.b64decode(content)
    fd = io.BytesIO(content_bytes)
    with zipfile.ZipFile(fd) as myzip:
        first_file = myzip.infolist()[0]
        with myzip.open(first_file) as myfile:
            txtString = myfile.read().decode("utf-8")
    return txtString

Upvotes: 1

Related Questions