Send files with Gmail using a python script

Photo by Stephen Phillips - Hostreviews.co.uk on Unsplash

Send files with Gmail using a python script

Theo van der Sluijs

Published on Jan 2, 2019

5 min read

Subscribe to my newsletter and never miss my upcoming articles

Sending an email with this Python 3 script is very easy, but you can also send attachments with Python and Gmail. Follow this guide and have it in minutes.

Now as I do not like doing stuff twice I wanted to have a script that would send files from a folder as separate emails.

And that is exactly what this python script does. It takes a folder and for every file a mail with that file is created and send to a email address.

So I have a subscription on this online Receipt scanner service where I can scan receipts with my mobile camera and it will get processed by this service.

Now as this service is very good I also receive a lot of invoices and receipts by mail or I have to download them manually. As the service has a send to email option, sending hundreds of invoices manually to this email address is not really an option for me…. it doing something very simple more then twice! And if I have to do it twice I AUOTMATE it!

Gmail app Password

Now if you are like me and want to use the Gmail service for this and you have 2-way authentication (which you REALLY shoud have!) you cannot simple start using Gmail to send these emails as Gmail wants to authenticate in a 2-way!

So when you have signed up for 2-Step Verification, Gmaikl normally sends you verification codes. However, these codes do not work with some apps and devices, like Outlook or my Python script. Instead, you’ll need to authorize the app or device the first time you use it to sign in to your Google Account by generating and entering an App password.

Creating a Google App Password is very easy.

  1. Go to your Google Account.
  2. On the left navigation panel, click Security.
  3. On the Signing in to Google panel, click App passwords. Note: If you can’t get to the page, 2-Step Verification is:

  4. Not set up for your account

  5. Set up for security keys only

  6. At the bottom, click Select app and choose the app you’re using.

  7. Click Select device and choose the device you’re using.
  8. Click Generate.
  9. Copy the the 16 character code in the yellow bar you will need it for this script.
  10. Click Done.

Once you are finished, you won’t see that App password code again. However, you will see a list of apps and devices you’ve created App passwords for.

Mail file folders

To use this script save it somewhere on your pc or Mac, name it “send_files_by_gmail.py” and create a folder named “mail_files” and within this folder, and within this new “mail_files” folder create a folder named “done” and “new”.

Your folder will look like this

  • send_files_by_gmail.py
  • mail_files
  • done
  • new

You can place all the attachments within the “new” folder.

When the script is ready all attachments send will be in the “done” folder.

If the script crashes, you can rerun the script as it will start where it stopped as it only puts files in the “done” folder when the mail is send out.

How the python script works

Well, very simple! You do not need to install anything. You have to use python 3 (it will not work with python 2)

You only have to fill in 3 items in the python script

your gmail email address your gmail app password and the email address your want to send it to!

if __name__ == '__main__':

    from_addr = "some@gmail.com"         # your gmail account email address
    pass_wd = "yourpasswors"              # your pwd (see discription above)
    to_addr = "to@emailaddress.com"     # where the attachment should go to

    m = MailFiles(from_addr, pass_wd, to_addr)

That’s it! Have Fun!

    """
    author: Theo van der Sluijs
    url: https://itheo.tech
    copyright: CC BY-NC 4.0
    creation date: 02-01-2019

    Small script to send mails with attachment from folder with Gmail

    Uses nothing but python 3 modules.

    Create a folder named mail_files and within this folder done and new.
    You can place all the attachments within the new folder.
    When the script is ready all attachments send will be in the Done folder.
    If the script crashes, you can rerun the script as it will start
    where it stopped.

    You need an gmail app password for this to work
    https://support.google.com/accounts/answer/185833?hl=en
    """
    import os
    import time
    import smtplib

    from email.mime.base import MIMEBase
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email import encoders


    class MailFiles:
        def __init__(self, from_addr=None, pass_wd=None, to_addr=None):
            """
            init function for this to work
            :param from_addr: your gmail account email address
            :param pass_wd: your gmail app pwd (see discription above)
            :param to_addr: here the attachment should go to
            """
            self.from_addr = from_addr
            self.pass_wd = pass_wd
            self.to_addr = to_addr

            dir_path = os.path.dirname(os.path.realpath(__file__))
            self.start_dir = os.path.join(dir_path, "mail_files/new")
            self.done_dir = os.path.join(dir_path, "mail_files/done")

            self.process_files()

        def process_files(self):
            """
            This will loop thru the files in the New folder and calls the
            mail_file function. It has a sleep function so Gmail will not
            be flooded.
            """
            i = 1
            for filename in os.listdir(self.start_dir):
                file = os.path.join(self.start_dir, filename)
                if self.mail_file(file, filename):  # Mailing retuns True or False
                    backup_file = os.path.join(self.done_dir, filename)
                    os.rename(file, backup_file)    # move done file to done folder
                print("Document {} send!".format(filename))
                i += 1
                time.sleep(5)   # Sleep for 5 seconds to not overrun Gmail

        def mail_file(self, file=None, filename=None):
            """
            This function will mail the file to the email address as an attachment
            :param file: path with filename
            :param filename: filename online
            :return: true or false
            """
            try:
                msg = MIMEMultipart()

                ['From'] = self.from_addr
                ['To'] = self.to_addr
                ['Subject'] = "Sending file {}".format(filename)

                body = "Sending File {} to you".format(filename)
                msg.attach(MIMEText(body, 'plain'))

                attachment = open(file, "rb")

                part = MIMEBase('application', 'octet-stream')
                part.set_payload(attachment.read())
                encoders.encode_base64(part)
                part.add_header('Content-Disposition', "attachment; filename= %s" % filename)

                msg.attach(part)

                server = smtplib.SMTP('smtp.gmail.com', 587)
                server.starttls()
                server.login(self.from_addr, self.pass_wd)
                text = msg.as_string()
                server.sendmail(self.from_addr, self.to_addr, text)
                server.quit()

                return True
            except smtplib.SMTPException as e:
                print(e)
                return False
            except:
                return False


    if __name__ == '__main__':

        from_addr = "some@gmail.com"         # your gmail account email address
        pass_wd = "yourpasswors"              # your pwd (see discription above)
        to_addr = "to@emailaddress.com"     # where the attachment should go to
        m = MailFiles(from_addr, pass_wd, to_addr)
 
Share this