1

I have mail messages which contain attachments.
I need to upload the attachments from mail to google drive.
For mail I'm using imaplib and for google drive I'm using pyDrive

I'm using the below code to get attachment:

if mail.get_content_maintype() == 'multipart':

        for part in mail.walk():
            if part.get_content_maintype() == 'multipart':
                continue

            if part.get('Content-Disposition') is None:

            attachment = part.get_payload(decode=True)

I have payload my attachment in mail. Now I can't understand how upload payload to google drive using pyDrive. I've tried this, but it did not work

attachment = part.get_payload(decode=True)
gd_file = self.gd_box.g_drive.CreateFile({'title': 'Hello.jpg',
                                                          "parents": [{"kind": "drive#fileLink", "id": folder['id']}]})
                gd_file.GetContentFile(attachment)
                gd_file.Upload()

UPD:

This code is work, but i think its bad solution(we save image localy, then upload this image in google drive)

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

                gd_file = self.gd_box.g_drive.CreateFile({'title': part.get_filename(),
                                                          "parents": [{"kind": "drive#fileLink", "id": folder['id']}]})
                gd_file.SetContentFile(part.get_filename())
                gd_file.Upload()
r1299597
  • 609
  • 3
  • 10
  • 20

1 Answers1

2

GetContentFile() is used to save a GoogleDriveFile to a local file. You want the opposite so try using SetContentString() instead, then call Upload():

gd_file.SetContentString(attachment)
gd_file.Upload()

Update

SetContentString() won't work if you are dealing with binary data, such as that contained in an image file. As a work-around you can write the data to a temporary file, upload to your drive, then delete the temporary file:

import os
from tempfile import NamedTemporaryFile

tmp_name = None
with NamedTemporaryFile(delete=False) as tf:
    tf.write(part.get_payload(decode=True))
    tmp_name = tf.name    # save the file name
if tmp_name is not None:
    gd_file.SetContentFile(tf_name)
    gd_file.Upload()
    os.remove(tmp_name)
mhawke
  • 84,695
  • 9
  • 117
  • 138
  • thnks for your answer, i try using `SetContentString` i have error `AttributeError: 'bytes' object has no attribute 'encode'` – r1299597 Jan 21 '18 at 11:10
  • 1
    OK, `SetContentString()` does not support bytes objects, i.e. binary strings. It expects a `str` object which is then encoded as UTF8. This will not work because you are dealing with binary data. You can save the attachment to a temporary file first, then use `SetContentFile()` instead. See updated answer. – mhawke Jan 21 '18 at 12:07
  • 1
    No worries. Just one more thing to mention if security is an issue. There is a possible race condition after the file has been written and closed where an attacker could replace the file content with other data. If that's a concern then you need to look at a more secure way to do it. – mhawke Jan 21 '18 at 12:26