Skip to main content

A Pythonic interface to the Gmail API that actually works as of August 2021.

Project description

EZGmail

A Pythonic interface to the Gmail API that actually works as of August 2021.

The Gmail API quickstart doesn't actually seem to work on Python 3 without some adjustments, and the entire documentation is a bit much for someone who just wants to read and send emails from their Gmail account. EZGmail just works.

The Gmail API documentation by Google is available at https://developers.google.com/gmail/api/

Installation

To install with pip, run:

pip install ezgmail

You will need to download a credentials-gmail.json file by going to https://developers.google.com/gmail/api/quickstart/python and clicking the Enable the Gmail API button (after logging in to your Gmail account). You will need to rename the downloaded credentials-gmail.json file to credentials.json.

Once you have the credentials.json file, the first time you run import ezgmail it will bring up a window asking you to log in to your Gmail account and allow "Quickstart" to access it. A token.json file will be generated which your script can use to access your account.

Future calls to ezgmail.init() or any other ezgmail function won't require this token-generating step. The gmail.init() function is automatically called when any other ezgmail function is called.

Quickstart Guide

After you've downloaded a credentials-gmail.json and token-gmail.json file, you can import EZGmail with import ezgmail. To see what email address you are sending from, examine ezgmail.EMAIL_ADDRESS (this is configured by the token-gmail.json file you're using, and you must first call ezgmail.init() or some other ezgmail function first):

>>> import ezgmail
>>> ezgmail.EMAIL_ADDRESS
'example@gmail.com'

To send an email from your "example@gmail.com" account:

>>> import ezgmail
>>> ezgmail.send('recipient@example.com', 'Subject line', 'Body of the email', ['attachment1.jpg', 'attachment2.mp3'])

The attachments argument is optional, and if you only have one attachment you can just specify the filename string. Also note that Gmail will most likely filter any emails that contain .exe, .zip, or any other suspicious attachments.

The cc and bcc fields are also optional keyword arguments:

>>> import ezgmail
>>> ezgmail.send('recipient@example.com', 'Subject line', 'Body of the email', cc='friend@example.com', bcc='otherfriend@example.com,someoneelse@example.com')

The main classes in ezgmail are GmailThread and GmailMessage. A GmailThread is a chain of emails replying to one another, while a GmailMessage is an individual email in a thread.

To retrieve unread emails:

>>> import ezgmail
>>> unreadThreads = ezgmail.unread()  # Returns a list of GmailThread objects.

The summary() function is an easy way to print out info on a list of thread or message objects:

>>> ezgmail.summary(unreadThreads)
Jon, Al - Remember that old website Hamsterdance? LOL - Dec 09
Al - This is a test email about gerbils. - Dec 09

If you want this info as a data structure, pass printInfo=False to summary():

>>> ezgmail.summary(unreadThreads, printInfo=False)
[(['Jon Smith <example@gmail.com>', 'Al Sweigart <al@inventwithpython.com>'], 'Remember that old website Hamsterdance? LOL', datetime.datetime(2018, 12, 9, 13, 29, 17)), (['Al Sweigart <al@inventwithpython.com>'], 'This is a test email about gerbils.', datetime.datetime(2018, 12, 9, 13, 25, 58))]

The GmailMessage objects of a thread are in the messages list attribute:

>>> ezgmail.summary(unreadThreads[0].messages)
Jon - Remember that old website Hamsterdance? LOL - Dec 09
Al - Haha that&#39;s awesome! On Sun, Dec 9, 2018 at 1:28 PM Jon Smith &lt;example@gmail.com&gt; wrote: Remember that old website Hamsterdance? LOL - Dec 09

The GmailMessage objects have sender, recipient, subject, body, and timestamp attribues:

>>> msg = unreadThreads[0].messages[0]
>>> msg.sender
'Jon Smith <example@gmail.com>'
>>> msg.recipient
'Al Sweigart <al@inventwithpython.com>'
>>> msg.subject
'Hamsterdance'
>>> msg.body
'Remember that old website Hamsterdance? LOL\r\n'
>>> msg.timestamp
datetime.datetime(2018, 12, 9, 13, 28, 48)

You can also call the recent() function to get recent email threads:

>>> import ezgmail
>>> recentThreads = ezgmail.recent()
>>> len(recentThreads)
22

The recent() and unread() functions are just convenient wrappers around search(), which you can pass a query to (just like the query text field in the Gmail.com website):

>>> import ezgmail
>>> threads = ezgmail.search('mancala')
>>> len(threads)
1
>>> ezgmail.summary(threads[0])
Al, Jon - Zanzibar &gt; <b>Mancala</b> is one of the oldest known games to still be widely played today. &gt; <b>Mancala</b> is a generic name for a - Dec 08

The trash() method deletes the message or messages in a GmailMessage or GmailThread object:

>>> import ezgmail
>>> threads = ezgmail.search('mancala')
>>> threads[0].trash()  # Move the entire first thread to the Trash folder.

The search() function can accept search operators just like the query text field:

More are described at https://support.google.com/mail/answer/7190?hl=en

The search(), recent(), and unread() can also accept a maxResults keyword argument that is set to 25 by default. This sets an upper limit on how many threads/messages will be returned. API usage quotas are posted at https://developers.google.com/gmail/api/v1/reference/quota (roughly one million requests a day (and 25 per second) for the free tier).

By default, EZGmail sends messages as plaintext. You can send HTML emails by passing 'html' for the mimeSubtype parameter in send(). (By default, this parameter is set to 'plain'.) This email has "Hello" appear in bold and "body" appear italicized:

>>> ezgmail.send('recipient@example.com', 'Subject Line', '<strong>Hello</strong>, this is the <em>body</em> of the message.', mimeSubtype='html')

Accessing an email or thread doesn't mark it as unread automatically. You must do that yourself by calling the markAsRead() method of the GmailThread or GmailMessage object. (There is also a corresponding markAsUnread() function.) You can also call ezgmail.markAsRead() and pass it a list of GmailThread or GmailMessage objects.

>>> import ezgmail
>>> unreadThreads = ezgmail.unread()
>>> ezgmail.markAsRead(unreadThreads) # Marks all the GmailThread objects in the unreadThreads list as read.
>>> # Or you can do:
>>> for unreadThread in unreadThreads:
...     unreadThread.markAsRead() # Mark the individual GmailThread objects as read.

These two functions make add/remove the 'UNREAD' label using EZGmail's addLabel() and removeLabel() functions:

>>> import ezgmail
>>> unreadThreads = ezgmail.unread()
>>> ezgmail.removeLabel(unreadThreads, 'UNREAD') # Also marks threads as read.
>>> ezgmail.addLabel(unreadThreads, 'UNREAD') # Marks them as unread again.
>>> # Or you can do:
>>> for unreadThread in unreadThreads:
...     unreadThread.removeLabel(unreadThreads, 'UNREAD') # Mark the individual GmailThread objects as read.

(Currently EZGmail doesn't have functions for adding/deleting/managing custom labels.)

To view the attachments of an email, look at the GmailMessage object's attachments dictionary. The keys are the filenames of the attachments. You can either call the downloadAttachment() or downloadAllAttachments() methods:

>>> import ezgmail
>>> threads = ezgmail.search('See the attached files')
>>> threads[0].messages[0].attachments
>>> import pprint
>>> pprint.pprint(threads[0].messages[0].attachments)
{'a.png': {'id': 'ANGjdJ8eLDbjBpFTfvpuQ2HfR_iwp59XLUIl-IHW8eJcexMsxBYoPCZAXcX16rnqcbJZTknF5r3GmnM1W9n4vAE1oiVgUa4S4zBmNs7rd5PzFwLjO2vU3hp3_9SEZv-KBqVxi9nuNjarxhFqp3mxw6E5mqEYmFOYtT7Gx6CZbLaJuUox9GaWu-W9B4-XPDjwKkEfCdJ21FlOl-CsC6isZgD2Vh-ghh1haZN_2sifccznLv61ZW_KmqPKFcV1j7cXMQVqWU7bkgdH8do4Msc3QsG2ly_PNRid4-7gihsXaLI1ko_j3LSvsoLHFP3edhxh6YKQ2OdMhyZh5lqjmfT1TXgSo7hY16P_ScDO5MnWvmKscf_Hm5y5D4DHfwOq4--Otivoq2WVkVucVUJBkAoB',
           'size': 833609},
 'b.png': {'id': 'ANGjdJ_WYMmPmy2Dd2VBgvVoLAd1p3ARxGXKIzVfKqAiLhvKSBmEowYqFCdHbMJYlDZy4IWBGLg0eQCllMI0icqamM7vfMxBW2irJVogLM6SUT9cIcJFMSF7UhzU2I26bho086J7NjnX5u4kqYj_LHchowO56vTdKLRRsaJ2gfW0esz3cDFZzvthdR4wyBKEIeCJv7OJmFiaJIRf9f1KmFfKPLo9GZSyD2RMXdd6Qa2M3uN9pgT6sZ-OQx3e6aNDAKWh5GCeSiuIt_Z7GsDCdzVJjakMJx5FRFhp5zIck0p04AHnYhKfy1BipWmf7G-DAKzgJHAhFimBVUIBeFsHrqEGxDlevD7lK4ZBeb8cluSmYyEsRkSPSMYMlp-x1GVw25gqMnMVkGMKPfwj38iB',
	       'size': 335911}}
>>> threads[0].messages[0].downloadAttachment('a.png') # Download to current working directory.
>>> threads[0].messages[0].downloadAttachment('b.png', '/path/to/save/in')
>>> threads[0].messages[0].downloadAllAttachments() # Easier way to save all attachments.

Limitations

Currently, EZGmail cannot do the following:

  • Read or set labels. (Including marking emails as read.)
  • Sending emails with cc and bcc fields.
  • A lot of other basic features. This package is just a start!

Contribute

If you'd like to contribute to EZGmail, check out https://github.com/asweigart/ezgmail or email al@inventwithpython.com

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

EZGmail-2021.8.5.tar.gz (15.7 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page