Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - How to send an email with attachment without loading the whole file into memory at once?

I would like to send emails with attachments of 10MB or more in a VPS with low RAM; the usual way to send an email with attachments in Python 3 (that I have found) is this:

from email.message import EmailMessage
# import other needed stuff here omitted for simplicity
attachment = 'some_file.tar'
msg = EmailMessage()
# set from, to, subject here
# set maintype, subtype here
with open(attachment, 'rb') as fd:
    msg.add_attachment(fd.read(),  # this is the problem, the whole file is loaded
                       maintype=maintype,
                       subtype=subtype,
                       filename=attachment)
# smtp_serv is an instance of smtplib.SMTP
smtp_serv.send_message(msg)

With this approach the whole file is loaded into memory and then the EmailMessage object is sent with smtplib.SMTP.send_message, what I am expecting is a way to give to add_attachment a file descriptor(or an iterable), instead of the file content, that is read in a lazy approach(ex. line by line or by some fixed amount of bytes) while the attachment is sent to the server, something like:

with open('somefile') as fd:
    msg.add_attachment(fd, maintype=mt, subtype=st, filename=fn)
    smtp_serv.send_message(msg)

Is there a way to do this(sending an attachment without loading the whole file at once) with the standard library (email and smtplib)???? I can't find any clue in the python documentation.

Thanks in advance.

like image 884
Asiel Diaz Benitez Avatar asked Nov 16 '17 16:11

Asiel Diaz Benitez


People also ask

How do you send a simple email in Python?

Set up a secure connection using SMTP_SSL() and .starttls() Use Python's built-in smtplib library to send basic emails. Send emails with HTML content and attachments using the email package. Send multiple personalized emails using a CSV file with contact data.


1 Answers

My recommendation is to upload the attachments to an S3 bucket or Google Storage bucket, and then provide a URL in the email for the recipient to download it. Most mail servers will restrict the size of the attachments, so they are very unlikely to get through to most mail clients.

You don't have to use a public bucket, you can obfuscate the attachment names, and add a "presigned" url - that only works for a finite amount of time: https://docs.aws.amazon.com/code-samples/latest/catalog/python-s3-generate_presigned_url.py.html

like image 106
rotten Avatar answered Sep 29 '22 12:09

rotten